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 29, 2025
1 parent 1c0488c commit 8acfb0f
Show file tree
Hide file tree
Showing 16 changed files with 1,008 additions and 909 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 Expand Up @@ -383,7 +383,6 @@ <h4 id="HMap1">OSDP Integration</h4>
IAAC: 'f4c51eaa-a6ca-48b9-a1fc-b0651da20509',
IAACConfig: [
{
layerId: '0',
entryType: 'group',
layerName: 'IAAC Projects',
listOfLayerEntryConfig: [
Expand Down
8 changes: 8 additions & 0 deletions packages/geoview-core/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,10 @@
""
],
"description": "Footer tab to be selected at map load"
},
"selectedLayersLayerPath": {
"type": "string",
"description": "Layerpath of layer to be selected at map load"
}
},
"required": [
Expand Down Expand Up @@ -1967,6 +1971,10 @@
"guide"
],
"description": "App bar tab to be selected at map load"
},
"selectedLayersLayerPath": {
"type": "string",
"description": "Layerpath of layer to be selected at map load"
}
},
"required": [
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 @@ -210,6 +210,10 @@
"geochart"
],
"description": "Footer tab to be selected at map load"
},
"selectedLayersLayerPath": {
"type": "string",
"description": "Layerpath of layer to be selected in the layers tab at map load"
}
},
"required": [
Expand Down Expand Up @@ -275,6 +279,10 @@
""
],
"description": "App bar tab to be selected at map load"
},
"selectedLayersLayerPath": {
"type": "string",
"description": "Layerpath of layer to be selected at map load"
}
},
"required": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type TypeFooterBarProps = {
};
collapsed: boolean;
selectedTab: TypeValidFooterBarTabsCoreProps;
selectedLayersLayerPath: string;
};

/** Supported app bar values. */
Expand All @@ -69,6 +70,7 @@ export type TypeAppBarProps = {
};
collapsed: boolean;
selectedTab: TypeValidAppBarCoreProps;
selectedLayersLayerPath: string;
};

/** Overview map options. Default none. */
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,33 @@ 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 || (isGeocore && maintainGeocoreLayerNames)) ? 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,51 +1159,71 @@ 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]);

const layerEntryLayerPaths = geoviewLayerConfig.listOfLayerEntryConfig.map(
(geoviewLayerEntryConfig) => geoviewLayerEntryConfig.layerPath
);

// Check for sublayers
const sublayerPaths = MapEventProcessor.getMapLayerOrder(mapId).filter(
// We only want the immediate child layers, group sublayers will handle their own sublayers
(entryLayerPath) => entryLayerPath.startsWith(`${layerPath}/`) && entryLayerPath.split('/').length === layerPath.split('/').length + 1
(entryLayerPath) => layerEntryLayerPaths.includes(entryLayerPath)
);

// 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,
initialSettings,
isTimeAware: geoviewLayerConfig.isTimeAware,
listOfLayerEntryConfig,
metadataAccessPath: geoviewLayerConfig.metadataAccessPath,
serviceDateFormat: geoviewLayerConfig.serviceDateFormat,
};
const newGeoviewLayerConfig: MapConfigLayerEntry = isGeocore
? {
geoviewLayerId: geoviewLayerConfig.geoviewLayerId,
geoviewLayerName: !maintainGeocoreLayerNames ? undefined : geoviewLayerConfig.geoviewLayerName,
geoviewLayerType: 'geoCore',
initialSettings,
listOfLayerEntryConfig,
}
: {
externalDateFormat: geoviewLayerConfig.externalDateFormat,
geoviewLayerId: geoviewLayerConfig.geoviewLayerId,
geoviewLayerName: geoviewLayerConfig.geoviewLayerName,
geoviewLayerType: geoviewLayerConfig.geoviewLayerType,
initialSettings,
isTimeAware: geoviewLayerConfig.isTimeAware,
listOfLayerEntryConfig,
metadataAccessPath: geoviewLayerConfig.metadataAccessPath,
serviceDateFormat: geoviewLayerConfig.serviceDateFormat,
};

return newGeoviewLayerConfig;
}

/**
* 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 +1233,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 Expand Up @@ -1249,12 +1287,16 @@ export class MapEventProcessor extends AbstractEventProcessor {
if (newMapConfig.appBar) {
newMapConfig.appBar.selectedTab = UIEventProcessor.getActiveAppBarTab(mapId).tabGroup as TypeValidAppBarCoreProps;
newMapConfig.appBar.collapsed = !UIEventProcessor.getActiveAppBarTab(mapId).isOpen;
const selectedLayerPath = LegendEventProcessor.getLayerPanelState(mapId, 'selectedLayerPath');
if (selectedLayerPath) newMapConfig.appBar.selectedLayersLayerPath = selectedLayerPath as string;
}

// Set open footer bar tab
if (newMapConfig.footerBar) {
newMapConfig.footerBar.selectedTab = UIEventProcessor.getActiveFooterBarTab(mapId) as TypeValidFooterBarTabsCoreProps;
newMapConfig.footerBar.collapsed = UIEventProcessor.getFooterBarIsCollapsed(mapId);
const selectedLayerPath = LegendEventProcessor.getLayerPanelState(mapId, 'selectedLayerPath');
if (selectedLayerPath) newMapConfig.footerBar.selectedLayersLayerPath = selectedLayerPath as string;
}

return newMapConfig;
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
Loading

0 comments on commit 8acfb0f

Please sign in to comment.