Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(legend) Ordering issues with store #2726

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
1,827 changes: 911 additions & 916 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/geoview-core/public/templates/add-layers.html
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ <h4>Add Layer Examples</h4>
<div>GeoCore UUID Layer</div>
<div style="margin-top: 10px; margin-left: 20px">
<input id="selectGeoCore" list="geocoreids" style="width: 300px" />
<datalist id="geocoreids">
<datalist id="geocoreids" value="fd4369a4-21fe-4070-914a-067474da0fd6">
<option value="fd4369a4-21fe-4070-914a-067474da0fd6"></option>
<option value="9d96e8c9-22fe-4ad2-b5e8-94a6991b744b"></option>
<option value="21b821cf-0f1c-40ee-8925-eab12d357668"></option>
<option value="ccc75c12-5acc-4a6a-959f-ef6f621147b9"></option>
<option value="0fca08b5-e9d0-414b-a3c4-092ff9c5e326"></option>
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { MapViewer } from '@/geo/map/map-viewer';
import * as GeoUtilities from '@/geo/utils/utilities';

import { initMapDivFromFunctionCall } from '@/app';
import EventHelper, { EventDelegateBase } from './events/event-helper';
import EventHelper, { EventDelegateBase } from '@/api/events/event-helper';

/**
* Class used to handle api calls (events, functions etc...)
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 @@ -15,7 +15,7 @@ import { MapConfigError } from '@config/types/classes/config-exceptions';

import { generateId, isJsonString, removeCommentsFromJSON } from '@/core/utils/utilities';
import { logger } from '@/core//utils/logger';
import { createStyleUsingEsriRenderer, EsriBaseRenderer } from './esri-renderer-parser';
import { createStyleUsingEsriRenderer, EsriBaseRenderer } from '@/api/config/esri-renderer-parser';

/**
* The API class that create configuration object. It is used to validate and read the service and layer metadata.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MapEventProcessor } from './map-event-processor';
import { SnackbarType } from '@/core/utils/notifications';
import { logger } from '@/core/utils/logger';
import { api } from '@/app';
import i18n from '@/core/translation/i18n';

// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

Expand Down Expand Up @@ -116,14 +117,32 @@ export class AppEventProcessor extends AbstractEventProcessor {
this.getAppState(mapId).setterActions.setCrosshairActive(isActive);
}

static setDisplayLanguage(mapId: string, lang: TypeDisplayLanguage): Promise<[void, void]> {
this.getAppState(mapId).setterActions.setDisplayLanguage(lang);
// reload the basemap from new language
const promiseResetBasemap = MapEventProcessor.resetBasemap(mapId);
// load guide in new language
const promiseSetGuide = AppEventProcessor.setGuide(mapId);
// Return promise of both promises to resolve
return Promise.all([promiseResetBasemap, promiseSetGuide]);
static setDisplayLanguage(mapId: string, lang: TypeDisplayLanguage): Promise<void> {
// Return a new promise of void when all will be done instead of promise of array of voids
return new Promise((resolve, reject) => {
// Change language in i18n for the useTranslation used by the ui components
const promiseChangeLanguage = i18n.changeLanguage(lang);

this.getAppState(mapId).setterActions.setDisplayLanguage(lang);

// reload the basemap from new language
const promiseResetBasemap = MapEventProcessor.resetBasemap(mapId);

// load guide in new language
const promiseSetGuide = AppEventProcessor.setGuide(mapId);

// When all promises are done
Promise.all([promiseChangeLanguage, promiseResetBasemap, promiseSetGuide])
.then(() => {
// Now resolve
resolve();
})
.catch((error) => {
// Log and reject
logger.logPromiseFailed('inner promise in app-event-processor.setDisplayLanguage', error);
reject();
});
});
}

static setDisplayTheme(mapId: string, theme: TypeDisplayTheme): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
TypeAllFeatureInfoResultSetEntry,
} from '@/core/stores/store-interface-and-intial-values/data-table-state';
import { logger } from '@/core/utils/logger';
import { MapEventProcessor } from './map-event-processor';
import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor';
import { TypeResultSetEntry } from '@/geo/map/map-schema-types';

// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ export class LegendEventProcessor extends AbstractEventProcessor {
this.getLayerState(mapId).setterActions.setSelectedLayerPath(layerPath);
}

static reorderLegendLayers(mapId: string): void {
// Sort the layers
const sortedLayers = this.getLayerState(mapId).legendLayers.sort(
(a, b) =>
MapEventProcessor.getMapIndexFromOrderedLayerInfo(mapId, a.layerPath) -
MapEventProcessor.getMapIndexFromOrderedLayerInfo(mapId, b.layerPath)
);

// Save in store
this.getLayerState(mapId).setterActions.setLegendLayers(sortedLayers);
}

/**
* Gets a specific state.
* @param {string} mapId - The mapId
Expand Down Expand Up @@ -493,6 +505,8 @@ export class LegendEventProcessor extends AbstractEventProcessor {
static setItemVisibility(mapId: string, item: TypeLegendItem, visibility: boolean = true): void {
// Get current layer legends and set item visibility
const curLayers = this.getLayerState(mapId).legendLayers;

// TODO: Check - Is this line really at the right place in this function? It doesn't seem to be doing anything with regards to 'curLayers'!?
// eslint-disable-next-line no-param-reassign
item.isVisible = visibility;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ import { NORTH_POLE_POSITION, OL_ZOOM_DURATION, OL_ZOOM_MAXZOOM, OL_ZOOM_PADDING
import { logger } from '@/core/utils/logger';
import { whenThisThen } from '@/core/utils/utilities';

import { AppEventProcessor } from './app-event-processor';
import { AbstractEventProcessor } from '@/api/event-processors/abstract-event-processor';
import { DataTableEventProcessor } from './data-table-event-processor';
import { TimeSliderEventProcessor } from './time-slider-event-processor';
import { UIEventProcessor } from './ui-event-processor';
import { TypeMapFeaturesConfig } from '@/core/types/global-types';
import { TypeClickMarker } from '@/core/components';
import { TypeLegendLayer } from '@/core/components/layers/types';
import { AbstractEventProcessor } from '@/api/event-processors/abstract-event-processor';
import { AppEventProcessor } from '@/api/event-processors/event-processor-children/app-event-processor';
import { DataTableEventProcessor } from '@/api/event-processors/event-processor-children/data-table-event-processor';
import { TimeSliderEventProcessor } from '@/api/event-processors/event-processor-children/time-slider-event-processor';
import { UIEventProcessor } from '@/api/event-processors/event-processor-children/ui-event-processor';
import { LegendEventProcessor } from '@/api/event-processors/event-processor-children/legend-event-processor';
import { IMapState, TypeOrderedLayerInfo, TypeScaleInfo } from '@/core/stores/store-interface-and-intial-values/map-state';
import { getAppCrosshairsActive } from '@/core/stores/store-interface-and-intial-values/app-state';
import { TypeHoverFeatureInfo } from '@/core/stores/store-interface-and-intial-values/feature-info-state';
import { LegendEventProcessor } from './legend-event-processor';
import { TypeLegendLayer } from '@/core/components/layers/types';
import { ConfigBaseClass } from '@/core/utils/config/validation-classes/config-base-class';
import { VectorLayerEntryConfig } from '@/core/utils/config/validation-classes/vector-layer-entry-config';

Expand Down Expand Up @@ -556,8 +556,12 @@ export class MapEventProcessor extends AbstractEventProcessor {
* @param {string} layerPath - The path of the layer to get.
* @returns {TypeOrderedLayerInfo | undefined} The ordered layer info.
*/
static getMapOrderedLayerInfoForLayer(mapId: string, layerPath: string): TypeOrderedLayerInfo | undefined {
return this.getMapStateProtected(mapId).orderedLayerInfo.find((orderedLayerInfo) => orderedLayerInfo.layerPath === layerPath);
static findMapLayerFromOrderedInfo(
mapId: string,
layerPath: string,
orderedLayerInfo: TypeOrderedLayerInfo[] = this.getMapStateProtected(mapId).orderedLayerInfo
): TypeOrderedLayerInfo | undefined {
return orderedLayerInfo.find((layer) => layer.layerPath === layerPath);
}

/**
Expand All @@ -567,14 +571,12 @@ export class MapEventProcessor extends AbstractEventProcessor {
* @param {TypeOrderedLayerInfo[]} orderedLayerInfo - The array of ordered layer info to search, default is current ordered layer info.
* @returns {TypeOrderedLayerInfo[] | undefined} The ordered layer info of the layer and its children.
*/
static getMapLayerAndChildrenOrderedInfo(
static findMapLayerAndChildrenFromOrderedInfo(
mapId: string,
layerPath: string,
orderedLayerInfo: TypeOrderedLayerInfo[] = this.getMapStateProtected(mapId).orderedLayerInfo
): TypeOrderedLayerInfo[] {
return orderedLayerInfo.filter(
(info: TypeOrderedLayerInfo) => info.layerPath.startsWith(`${layerPath}/`) || info.layerPath === layerPath
);
return orderedLayerInfo.filter((layer) => layer.layerPath.startsWith(`${layerPath}/`) || layer.layerPath === layerPath);
}

static getMapIndexFromOrderedLayerInfo(mapId: string, layerPath: string): number {
Expand Down Expand Up @@ -743,7 +745,7 @@ export class MapEventProcessor extends AbstractEventProcessor {

static setOrderedLayerInfoWithNoOrderChangeState(mapId: string, curOrderedLayerInfo: TypeOrderedLayerInfo[]): void {
// Redirect
this.getMapStateProtected(mapId).setterActions.setOrderedLayerInfo([...curOrderedLayerInfo]);
this.getMapStateProtected(mapId).setterActions.setOrderedLayerInfo(curOrderedLayerInfo);
}

static reorderLayer(mapId: string, layerPath: string, move: number): void {
Expand All @@ -770,7 +772,7 @@ export class MapEventProcessor extends AbstractEventProcessor {
: (geoviewLayerConfig as TypeLayerEntryConfig).layerPath;
const pathToSearch = layerPathToReplace || layerPath;
const index = this.getMapIndexFromOrderedLayerInfo(mapId, pathToSearch);
const replacedLayers = this.getMapLayerAndChildrenOrderedInfo(mapId, pathToSearch);
const replacedLayers = this.findMapLayerAndChildrenFromOrderedInfo(mapId, pathToSearch);
const newOrderedLayerInfo = LayerApi.generateArrayOfLayerOrderInfo(geoviewLayerConfig);
orderedLayerInfo.splice(index, replacedLayers.length, ...newOrderedLayerInfo);

Expand Down Expand Up @@ -1138,7 +1140,7 @@ export class MapEventProcessor extends AbstractEventProcessor {
): TypeLayerEntryConfig {
// Get needed info
const layerEntryConfig = MapEventProcessor.getMapViewerLayerAPI(mapId).getLayerEntryConfig(layerPath);
const orderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfoForLayer(mapId, layerPath);
const orderedLayerInfo = MapEventProcessor.findMapLayerFromOrderedInfo(mapId, layerPath);
const legendLayerInfo = LegendEventProcessor.getLegendLayerInfo(mapId, layerPath);

// Get original layerEntryConfig from map config
Expand Down Expand Up @@ -1221,7 +1223,7 @@ export class MapEventProcessor extends AbstractEventProcessor {
const layerEntryConfig = MapEventProcessor.getMapViewerLayerAPI(mapId).getLayerEntryConfig(layerPath)!;

const { geoviewLayerConfig } = layerEntryConfig;
const orderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfoForLayer(mapId, layerPath);
const orderedLayerInfo = MapEventProcessor.findMapLayerFromOrderedInfo(mapId, layerPath);
const legendLayerInfo = LegendEventProcessor.getLegendLayerInfo(mapId, layerPath);

// Check if the layer is a geocore layers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
} from '@/core/stores/store-interface-and-intial-values/time-slider-state';
import { WMS } from '@/geo/layer/geoview-layers/raster/wms';
import { TypeFeatureInfoLayerConfig, TypeLayerEntryConfig, layerEntryIsGroupLayer } from '@/geo/map/map-schema-types';
import { MapEventProcessor } from './map-event-processor';
import { UIEventProcessor } from './ui-event-processor';
import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor';
import { UIEventProcessor } from '@/api/event-processors/event-processor-children/ui-event-processor';
import { GVWMS } from '@/geo/layer/gv-layers/raster/gv-wms';
import { GVEsriImage } from '@/geo/layer/gv-layers/raster/gv-esri-image';
import { AbstractGVLayer } from '@/geo/layer/gv-layers/abstract-gv-layer';
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/api/event-processors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MapEventProcessor } from '@/api/event-processors/event-processor-childr
import { TimeSliderEventProcessor } from '@/api/event-processors/event-processor-children/time-slider-event-processor';
import { GeochartEventProcessor } from '@/api/event-processors/event-processor-children/geochart-event-processor';
import { DataTableEventProcessor } from '@/api/event-processors/event-processor-children/data-table-event-processor';
import { SwiperEventProcessor } from './event-processor-children/swiper-event-processor';
import { SwiperEventProcessor } from '@/api/event-processors/event-processor-children/swiper-event-processor';

// core
const appEventProcessor = new AppEventProcessor();
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/src/api/plugin/plugin-types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AnySchemaObject } from 'ajv';
import React from 'react';
import { TypeJsonObject, TypeJsonValue } from '@/core/types/global-types';
import { API } from '../api';
import { API } from '@/api';

/** ******************************************************************************************************************************
* interface used when creating the actual plugin.
Expand Down
4 changes: 4 additions & 0 deletions packages/geoview-core/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { TypeCGPV, TypeMapFeaturesConfig } from '@/core/types/global-types';
import { Config } from '@/core/utils/config/config';
import { useWhatChanged } from '@/core/utils/useWhatChanged';
import { addGeoViewStore } from '@/core/stores/stores-managers';
import i18n from '@/core/translation/i18n';
import { logger } from '@/core/utils/logger';
import { removeCommentsFromJSON } from '@/core/utils/utilities';

Expand Down Expand Up @@ -151,6 +152,9 @@ async function renderMap(mapElement: Element): Promise<void> {
const configObj = config.initializeMapConfig(configuration.mapId, configuration!.map!.listOfGeoviewLayerConfig!);
configuration.map.listOfGeoviewLayerConfig = configObj!;

// Set the i18n language to the language specified in the config
await i18n.changeLanguage(lang);

// if valid config was provided - mapId is now part of config
if (configuration) {
const { mapId } = configuration;
Expand Down
18 changes: 5 additions & 13 deletions packages/geoview-core/src/core/app-start.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { createContext, StrictMode, Suspense, useMemo } from 'react';

import './translation/i18n';
import i18n from 'i18next';
import { I18nextProvider } from 'react-i18next';

import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
Expand All @@ -11,9 +8,10 @@ import { Shell } from '@/core/containers/shell';
import { getTheme, cgpvTheme } from '@/ui/style/theme';
import { MapViewer } from '@/geo/map/map-viewer';
import { TypeMapFeaturesConfig } from '@/core/types/global-types';
import { logger } from '@/core/utils/logger';
import i18n from '@/core/translation/i18n';
import { api } from '@/app';
import { logger } from './utils/logger';
import { useAppDisplayLanguageById, useAppDisplayThemeById } from './stores/store-interface-and-intial-values/app-state';
import { useAppDisplayThemeById } from '@/core/stores/store-interface-and-intial-values/app-state';

// create a state that will hold map config information
// TODO: use store, only keep map id on context for store manager to gather right store on hooks
Expand Down Expand Up @@ -57,28 +55,22 @@ function AppStart(props: AppStartProps): JSX.Element {

// GV get store values by id because context is not set.... it is the only 2 atomic selector by id
// once context is define, map id is available
const language = useAppDisplayLanguageById(mapId);
const theme = useAppDisplayThemeById(mapId);

/**
* Create maps from inline configs with class name geoview-map
* returns {JSX.Element}
*/
function getInlineMaps(): JSX.Element {
const i18nInstance = i18n.cloneInstance({
lng: language,
fallbackLng: language,
});

// create a new map viewer instance and add it to the api
// TODO: use store, remove the use of feature by viewer class and use state to gather values
if (!(mapId in api.maps)) {
const mapViewer = new MapViewer(mapFeaturesConfig, i18nInstance);
const mapViewer = new MapViewer(mapFeaturesConfig, i18n);
api.setMapViewer(mapId, mapViewer, onMapViewerInit);
}

return (
<I18nextProvider i18n={i18nInstance}>
<I18nextProvider i18n={i18n}>
<MapContext.Provider value={mapContextValue}>
<ThemeProvider theme={getTheme(theme)}>
<StrictMode>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const Attribution = memo(function Attribution(): JSX.Element {
};

// Memoize values
const attributionContent = useMemo(
const memoAttributionContent = useMemo(
() => mapAttribution.map((attribution) => <Typography key={attribution}>{attribution}</Typography>),
[mapAttribution]
);
Expand Down Expand Up @@ -96,7 +96,7 @@ export const Attribution = memo(function Attribution(): JSX.Element {
}}
onClose={handleClosePopover}
>
<Box sx={BOX_STYLES}>{attributionContent}</Box>
<Box sx={BOX_STYLES}>{memoAttributionContent}</Box>
</Popover>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { LayerListEntry } from '.';
export interface TypeIconStackProps {
layerPath: string;
onIconClick?: () => void;
onStackIconClick?: (e: React.KeyboardEvent<HTMLElement>) => void;
onStackIconClick?: (event: React.KeyboardEvent<HTMLElement>) => void;
}

interface LayerIconProps {
Expand Down
10 changes: 7 additions & 3 deletions packages/geoview-core/src/core/components/common/layer-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Box, List, ListItem, ListItemButton, Paper, Tooltip, Typography } from
import { TypeFeatureInfoEntry, TypeQueryStatus, TypeLayerStatus } from '@/geo/map/map-schema-types';
import { getSxClasses } from './layer-list-style';
import { LayerIcon } from './layer-icon';
import { logger } from '@/core/utils/logger';

export interface LayerListEntry {
content?: string | ReactNode;
Expand Down Expand Up @@ -82,12 +83,15 @@ export const LayerListItem = memo(function LayerListItem({ id, isSelected, layer
* Handle layer click when mouse enter is pressed.
*/
const handleLayerKeyDown = useCallback(
(e: React.KeyboardEvent, selectedLayer: LayerListEntry): void => {
if (e.key === 'Enter' && !isDisabled) {
(event: React.KeyboardEvent, selectedLayer: LayerListEntry): void => {
// Log
logger.logTraceUseCallback('LAYER-LIST - handleLayerKeyDown');

if (event.key === 'Enter' && !isDisabled) {
onListItemClick(selectedLayer);
// NOTE: did this, bcz when enter is clicked, tab component `handleClick` function is fired,
// to avoid this we have do prevent default so that it doesn't probagate to the parent elements.
e.preventDefault();
event.preventDefault();
}
},
[isDisabled, onListItemClick]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { CrosshairIcon } from './crosshair-icon';
import { useAppCrosshairsActive } from '@/core/stores/store-interface-and-intial-values/app-state';
import { getMapPointerPosition, useMapStoreActions } from '@/core/stores/store-interface-and-intial-values/map-state';
import { logger } from '@/core/utils/logger';
import { useEventListener } from '../common/hooks/use-event-listener';
import { useEventListener } from '@/core/components/common/hooks/use-event-listener';
import { useGeoViewMapId } from '@/app';

type CrosshairProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function DataTable({ data, layerPath }: DataTableProps): JSX.Element {
setDensity(updaterOrValue);
};

const handleToggleColumnFilters = () => {
const handleToggleColumnFilters = (): void => {
setShowColumnFilters((prev) => !prev);
setColumnsFiltersVisibility(false, layerPath);
};
Expand Down
Loading
Loading