Skip to content

Commit

Permalink
feat(geocore): better language switching for geocore
Browse files Browse the repository at this point in the history
Closes #2711
  • Loading branch information
DamonU2 committed Jan 28, 2025
1 parent 1c0488c commit 9820dd3
Show file tree
Hide file tree
Showing 14 changed files with 957 additions and 899 deletions.
1,721 changes: 864 additions & 857 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/geoview-core/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"errorServer": "source is not valid",
"errorNotLoaded": "An error occured when loading the layer",
"errorProj": "does not support current map projection",
"errorImageLoad": "Error loading source image for layer: __param__ at zoom level __param__",
"only": "only",
"opacity": "Opacity",
"opacityMax": "Maximum from parent",
Expand Down Expand Up @@ -226,4 +227,4 @@
"resizeTooltip": "Resize",
"noTab": "No tab"
}
}
}
3 changes: 2 additions & 1 deletion packages/geoview-core/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"errorServer": "source n'est pas valide",
"errorNotLoaded": "Une erreur s'est produite lors du chargement de la couche",
"errorProj": "ne prend pas en charge la projection cartographique actuelle",
"errorImageLoad": "Erreur de chargement de l'image source pour le couche: __param__ au niveau de zoom __param__",
"only": "seulement",
"opacity": "Opacité",
"opacityMax": "Maximum du parent",
Expand Down Expand Up @@ -225,4 +226,4 @@
"resizeTooltip": "Redimensionner",
"noTab": "Pas d'onglet"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,16 @@ <h4 id="HMap1">OSDP Integration</h4>
</li>
<li>
<button id="changeLanguage" style="margin: 10px">Change Language</button>
Changes the language from french to english or english to french and reloads the map if it exists. Note: this will not change the
language of the layers, as they are loaded in the current state.
Changes the language from french to english or english to french and reloads the map if it exists. Note: this will change the
language of the layers, as maintainGeocoreLayerNames is set to false.
<details>
<summary>Code</summary>
<pre>
lang = lang === 'fr' ? 'en' : 'fr';
const mapDiv = document.getElementById('Map1');
if (mapDiv) {
mapDiv.setAttribute('data-lang', lang);
cgpv.api.maps.Map1.reloadWithCurrentState();
cgpv.api.maps.Map1.reloadWithCurrentState(false);
}
</pre>
</details>
Expand Down Expand Up @@ -330,7 +330,7 @@ <h4 id="HMap1">OSDP Integration</h4>
const mapDiv = document.getElementById('Map1');
if (mapDiv) {
mapDiv.setAttribute('data-lang', lang);
cgpv.api.maps.Map1.reloadWithCurrentState();
cgpv.api.maps.Map1.reloadWithCurrentState(false);
}
});

Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/api/config/config-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ export class ConfigApi {
// doesn't accept string config. Note that convertStringToJson returns undefined if the string config cannot
// be translated to a json object.
const providedMapFeatureConfig: TypeJsonObject | undefined =
// We clone to prevent modifications from leaking back to the user object.
// We clone to prevent modifications from leaking back to the user object.
typeof mapConfig === 'string' ? ConfigApi.#convertStringToJson(mapConfig as string) : (cloneDeep(mapConfig) as TypeJsonObject);

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ export abstract class AbstractGeoviewLayerConfig {
// GV: GeoCore layers are processed by the configApi. GeoView layer instances do not recognize them as a valid geoView layer Type.
// GV: However, whe have the isGeocore flag to keep track of geocore layers that were converted to geoview layers.
this.isGeocore = (userGeoviewLayerConfig.isGeocore as boolean) || false;
if (this.isGeocore) this.geoviewLayerName = userGeoviewLayerConfig.geoviewLayerName as string;
if (this.isGeocore)
this.geoviewLayerName = userGeoviewLayerConfig.geoviewLayerName ? (userGeoviewLayerConfig.geoviewLayerName as string) : '';
this.geoviewLayerId = (userGeoviewLayerConfig.geoviewLayerId || generateId()) as string;
this.metadataAccessPath = userGeoviewLayerConfig.metadataAccessPath as string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ export class MapEventProcessor extends AbstractEventProcessor {
* @param {TypeLegendLayer} legendLayerInfo - Legend layer info for the layer.
* @returns {TypeLayerInitialSettings} Initial settings object.
*/
static getInitialSettings(
static #getInitialSettings(
layerEntryConfig: ConfigBaseClass,
orderedLayerInfo: TypeOrderedLayerInfo,
legendLayerInfo: TypeLegendLayer
Expand All @@ -1074,9 +1074,16 @@ export class MapEventProcessor extends AbstractEventProcessor {
* Creates a layer entry config based on current layer state.
* @param {string} mapId - Id of map.
* @param {string} layerPath - Path of the layer to create config for.
* @param {boolean} isGeocore - Indicates if it is a geocore layer.
* @param {boolean} maintainGeocoreLayerNames - Indicates if geocore layer names should be kept as is or returned to defaults.
* @returns {TypeLayerEntryConfig} Entry config object.
*/
static createLayerEntryConfig(mapId: string, layerPath: string): TypeLayerEntryConfig {
static #createLayerEntryConfig(
mapId: string,
layerPath: string,
isGeocore: boolean,
maintainGeocoreLayerNames: boolean
): TypeLayerEntryConfig {
// Get needed info
const layerEntryConfig = MapEventProcessor.getMapViewerLayerAPI(mapId).getLayerEntryConfig(layerPath);
const orderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfoForLayer(mapId, layerPath);
Expand Down Expand Up @@ -1110,24 +1117,32 @@ export class MapEventProcessor extends AbstractEventProcessor {
(entryLayerPath) =>
entryLayerPath.startsWith(`${layerPath}/`) && entryLayerPath.split('/').length === layerPath.split('/').length + 1
);
sublayerPaths.forEach((sublayerPath) => listOfLayerEntryConfig.push(MapEventProcessor.createLayerEntryConfig(mapId, sublayerPath)));
sublayerPaths.forEach((sublayerPath) =>
listOfLayerEntryConfig.push(MapEventProcessor.#createLayerEntryConfig(mapId, sublayerPath, isGeocore, maintainGeocoreLayerNames))
);
}

// Get initial settings
const initialSettings = this.getInitialSettings(layerEntryConfig!, orderedLayerInfo!, legendLayerInfo!);
const initialSettings = this.#getInitialSettings(layerEntryConfig!, orderedLayerInfo!, legendLayerInfo!);

const source = (layerEntryConfig! as VectorLayerEntryConfig).source
? cloneDeep((layerEntryConfig! as VectorLayerEntryConfig).source)
: undefined;

if (source?.dataAccessPath && isGeocore) source.dataAccessPath = '';

const layerStyle = legendLayerInfo!.styleConfig && !isGeocore ? legendLayerInfo!.styleConfig : undefined;

// Construct layer entry config
const newLayerEntryConfig = {
layerId: layerEntryConfig!.layerId,
layerName: layerEntryConfig!.layerName,
layerName: isGeocore && !maintainGeocoreLayerNames ? undefined : layerEntryConfig!.layerName,
layerFilter: (configLayerEntryConfig as VectorLayerEntryConfig)?.layerFilter
? (configLayerEntryConfig as VectorLayerEntryConfig).layerFilter
: undefined,
initialSettings,
layerStyle: legendLayerInfo!.styleConfig ? legendLayerInfo!.styleConfig : undefined,
source: (layerEntryConfig! as VectorLayerEntryConfig).source
? cloneDeep((layerEntryConfig! as VectorLayerEntryConfig).source)
: undefined,
layerStyle,
source,
entryType: listOfLayerEntryConfig.length ? 'group' : undefined,
listOfLayerEntryConfig: listOfLayerEntryConfig.length ? listOfLayerEntryConfig : [],
};
Expand All @@ -1143,15 +1158,19 @@ export class MapEventProcessor extends AbstractEventProcessor {
* Creates a geoview layer config based on current layer state.
* @param {string} mapId - Id of map.
* @param {string} layerPath - Path of the layer to create config for.
* @param {boolean} maintainGeocoreLayerNames - Indicates if geocore layer names should be kept as is or returned to defaults.
* @returns {MapConfigLayerEntry} Geoview layer config object.
*/
static createGeoviewLayerConfig(mapId: string, layerPath: string): MapConfigLayerEntry {
static #createGeoviewLayerConfig(mapId: string, layerPath: string, maintainGeocoreLayerNames: boolean): MapConfigLayerEntry {
// Get needed info
const layerEntryConfig = MapEventProcessor.getMapViewerLayerAPI(mapId).getLayerEntryConfig(layerPath)!;
const { geoviewLayerConfig } = layerEntryConfig;
const orderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfoForLayer(mapId, layerPath);
const legendLayerInfo = LegendEventProcessor.getLegendLayerInfo(mapId, layerPath);

// Check if the layer is a geocore layers
const isGeocore = api.config.isValidUUID(layerPath.split('/')[0]);

// Check for sublayers
const sublayerPaths = MapEventProcessor.getMapLayerOrder(mapId).filter(
// We only want the immediate child layers, group sublayers will handle their own sublayers
Expand All @@ -1161,22 +1180,24 @@ export class MapEventProcessor extends AbstractEventProcessor {
// Build list of sublayer entry configs
const listOfLayerEntryConfig: TypeLayerEntryConfig[] = [];
if (sublayerPaths.length)
sublayerPaths.forEach((sublayerPath) => listOfLayerEntryConfig.push(MapEventProcessor.createLayerEntryConfig(mapId, sublayerPath)));
else listOfLayerEntryConfig.push(this.createLayerEntryConfig(mapId, layerPath));
sublayerPaths.forEach((sublayerPath) =>
listOfLayerEntryConfig.push(MapEventProcessor.#createLayerEntryConfig(mapId, sublayerPath, isGeocore, maintainGeocoreLayerNames))
);
else listOfLayerEntryConfig.push(this.#createLayerEntryConfig(mapId, layerPath, isGeocore, maintainGeocoreLayerNames));

// Get initial settings
const initialSettings = this.getInitialSettings(layerEntryConfig!, orderedLayerInfo!, legendLayerInfo!);
const initialSettings = this.#getInitialSettings(layerEntryConfig!, orderedLayerInfo!, legendLayerInfo!);

// Construct geoview layer config
const newGeoviewLayerConfig: MapConfigLayerEntry = {
externalDateFormat: geoviewLayerConfig.externalDateFormat,
geoviewLayerId: geoviewLayerConfig.geoviewLayerId,
geoviewLayerName: geoviewLayerConfig.geoviewLayerName,
geoviewLayerType: geoviewLayerConfig.geoviewLayerType,
geoviewLayerId: isGeocore ? layerPath.split('/')[0] : geoviewLayerConfig.geoviewLayerId,
geoviewLayerName: isGeocore && !maintainGeocoreLayerNames ? undefined : geoviewLayerConfig.geoviewLayerName,
geoviewLayerType: isGeocore ? 'geoCore' : geoviewLayerConfig.geoviewLayerType,
initialSettings,
isTimeAware: geoviewLayerConfig.isTimeAware,
listOfLayerEntryConfig,
metadataAccessPath: geoviewLayerConfig.metadataAccessPath,
metadataAccessPath: isGeocore ? '' : geoviewLayerConfig.metadataAccessPath,
serviceDateFormat: geoviewLayerConfig.serviceDateFormat,
};

Expand All @@ -1186,8 +1207,9 @@ export class MapEventProcessor extends AbstractEventProcessor {
/**
* Creates a map config based on current map state.
* @param {string} mapId - Id of map.
* @param {boolean} maintainGeocoreLayerNames - Indicates if geocore layer names should be kept as is or returned to defaults.
*/
static createMapConfigFromMapState(mapId: string): TypeMapFeaturesInstance | undefined {
static createMapConfigFromMapState(mapId: string, maintainGeocoreLayerNames: boolean = true): TypeMapFeaturesInstance | undefined {
const config = MapEventProcessor.getGeoViewMapConfig(mapId);

if (config) {
Expand All @@ -1197,7 +1219,9 @@ export class MapEventProcessor extends AbstractEventProcessor {
);

// Build list of geoview layer configs
const listOfGeoviewLayerConfig = layerOrder.map((layerPath) => this.createGeoviewLayerConfig(mapId, layerPath));
const listOfGeoviewLayerConfig = layerOrder.map((layerPath) =>
this.#createGeoviewLayerConfig(mapId, layerPath, maintainGeocoreLayerNames)
);

// Get info for view
const projection = this.getMapState(mapId).currentProjection as TypeValidMapProjectionCodes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class ConfigValidation {
if (!mapConfigLayerEntryIsGeoCore(listOfGeoviewLayerConfig[i])) {
const gvLayerConfigCasted = listOfGeoviewLayerConfig[i] as TypeGeoviewLayerConfig;
isValid = this.#isValidTypeListOfLayerEntryConfig(
gvLayerConfigCasted.geoviewLayerType,
gvLayerConfigCasted.geoviewLayerType as TypeGeoviewLayerType,
gvLayerConfigCasted.listOfLayerEntryConfig,
validator
);
Expand Down
9 changes: 7 additions & 2 deletions packages/geoview-core/src/core/utils/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ export class Config {
if (mapConfigLayerEntryIsGeoCore(geoviewLayerEntry)) {
// Skip it, because we don't validate the GeoCore configuration anymore. Not the same way as typical GeoView Layer Types at least.
// TODO Why not do GeoCore request here? Then could easily replace listOfLayerEntries and validate / process along with other layers
} else if (Object.values(CONST_LAYER_TYPES).includes((geoviewLayerEntry as TypeGeoviewLayerConfig).geoviewLayerType)) {
} else if (
Object.values(CONST_LAYER_TYPES).includes((geoviewLayerEntry as TypeGeoviewLayerConfig).geoviewLayerType as TypeGeoviewLayerType)
) {
const geoViewLayerEntryCasted = geoviewLayerEntry as TypeGeoviewLayerConfig;
this.#setLayerEntryType(geoViewLayerEntryCasted.listOfLayerEntryConfig!, geoViewLayerEntryCasted.geoviewLayerType);
this.#setLayerEntryType(
geoViewLayerEntryCasted.listOfLayerEntryConfig!,
geoViewLayerEntryCasted.geoviewLayerType as TypeGeoviewLayerType
);
} else throw new Error(`Invalid GeoView Layer Type ${geoviewLayerEntry.geoviewLayerType}`);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,22 @@ export function commonValidateListOfLayerEntryConfig(
const { layerPath } = layerConfig;

if (layerEntryIsGroupLayer(layerConfig)) {
// Use the layer name from the metadata if it exists and there is no existing name.
if (!layerConfig.layerName)
layerConfig.layerName = layer.metadata!.layers[layerConfig.layerId].name
? (layer.metadata!.layers[layerConfig.layerId].name as string)
: '';

layer.validateListOfLayerEntryConfig(layerConfig.listOfLayerEntryConfig!);

if (!(layerConfig as GroupLayerEntryConfig).listOfLayerEntryConfig.length) {
layer.layerLoadError.push({
layer: layerPath,
loggerMessage: `Empty layer group (mapId: ${layer.mapId}, layerPath: ${layerPath})`,
});
layerConfig.layerStatus = 'error';
}

return;
}

Expand Down
15 changes: 11 additions & 4 deletions packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import { TypeLegend } from '@/core/stores/store-interface-and-intial-values/laye
import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor';
import { MapViewer } from '@/geo/map/map-viewer';
import { AbstractBaseLayer } from './abstract-base-layer';
import { TypeOutfieldsType } from '@/api/config/types/map-schema-types';
import { TypeGeoviewLayerType, TypeOutfieldsType } from '@/api/config/types/map-schema-types';
import { getLocalizedMessage } from '@/core/utils/utilities';

/**
* Abstract Geoview Layer managing an OpenLayer layer.
Expand Down Expand Up @@ -242,9 +243,15 @@ export abstract class AbstractGVLayer extends AbstractBaseLayer {
* We do not put the layer status as error, as this could be specific to a zoom level and the layer is otherwise fine.
*/
protected onImageLoadError(): void {
logger.logError(
`Error loading source image for layer path: ${this.getLayerPath()} at zoom level: ${this.getMapViewer().getView().getZoom()}`
);
const lang = document.getElementById(this.getMapId())!.getAttribute('data-lang') as 'en' | 'fr';
// Add notification with the current zoom level
this.getMapViewer().notifications.showError(
`Error loading source image for layer ${this.getLayerPath()} at zoom level: ${this.getMapViewer().getView().getZoom()}`
getLocalizedMessage('layers.errorImageLoad', lang),
[this.getLayerName()!, this.getMapViewer().getView().getZoom()!],
true
);
}

Expand Down Expand Up @@ -477,7 +484,7 @@ export abstract class AbstractGVLayer extends AbstractBaseLayer {
async onFetchLegend(): Promise<TypeLegend | null> {
try {
const legend: TypeLegend = {
type: this.getLayerConfig().geoviewLayerConfig.geoviewLayerType,
type: this.getLayerConfig().geoviewLayerConfig.geoviewLayerType as TypeGeoviewLayerType,
styleConfig: this.getStyle(),
legend: await getLegendStyles(this.getStyle()),
};
Expand Down Expand Up @@ -574,7 +581,7 @@ export abstract class AbstractGVLayer extends AbstractBaseLayer {
const featureInfoEntry: TypeFeatureInfoEntry = {
// feature key for building the data-grid
featureKey: featureKeyCounter++,
geoviewLayerType: this.getLayerConfig().geoviewLayerConfig.geoviewLayerType,
geoviewLayerType: this.getLayerConfig().geoviewLayerConfig.geoviewLayerType as TypeGeoviewLayerType,
extent,
geometry: feature,
featureIcon: canvas,
Expand Down
8 changes: 5 additions & 3 deletions packages/geoview-core/src/geo/layer/other/geocore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,22 @@ export class GeoCore {
// Get the GV config from UUID and await
const response = await UUIDmapConfigReader.getGVConfigFromUUIDs(url, this.#displayLanguage, [uuid]);

// Validate the generated Geoview Layer Config
ConfigValidation.validateListOfGeoviewLayerConfig(this.#displayLanguage, response.layers);

// Use user supplied listOfLayerEntryConfig if provided
if (layerConfig?.listOfLayerEntryConfig || layerConfig?.initialSettings) {
const tempLayerConfig = { ...layerConfig } as unknown as TypeGeoviewLayerConfig;
tempLayerConfig.metadataAccessPath = response.layers[0].metadataAccessPath;
tempLayerConfig.geoviewLayerType = response.layers[0].geoviewLayerType;
// Use the name from the first layer if none is provided in the config
if (!tempLayerConfig.geoviewLayerName) tempLayerConfig.geoviewLayerName = response.layers[0].geoviewLayerName;

const config = new Config(this.#displayLanguage);
const newLayerConfig = config.getValidMapConfig([tempLayerConfig]);
return newLayerConfig as TypeGeoviewLayerConfig[];
}

// Validate the generated Geoview Layer Config
ConfigValidation.validateListOfGeoviewLayerConfig(this.#displayLanguage, response.layers);

// For each found geochart associated with the Geocore UUIDs
response.geocharts?.forEach((geochartConfig) => {
// Add a GeoChart
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/geo/map/map-schema-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export type TypeGeoviewLayerConfig = {
/** The GeoView layer access path (English/French). */
metadataAccessPath?: string;
/** Type of GeoView layer. */
geoviewLayerType: TypeGeoviewLayerType;
geoviewLayerType: 'geoCore' | TypeGeoviewLayerType;
/** Date format used by the service endpoint. */
serviceDateFormat?: string;
/** Date format used by the getFeatureInfo to output date variable. */
Expand Down
Loading

0 comments on commit 9820dd3

Please sign in to comment.