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

refactor(store): All state follow setterActions #2154

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/geoview-core/public/templates/sandbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ <h4 id="HLCONF1">Sanbox Map</h4>

// create map
// TODO: the delete has a timeout so we need to wait before trying to recreate the map...
// TD.CONT: this should be cleaner
// TO.DOCONT: this should be cleaner
setTimeout(() => {
cgpv.api.createMapFromConfig('sandboxMap', document.getElementById('configGeoview').value);
}, 1500);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { createGuideObject } from '@/core/utils/utilities';
import { MapViewer } from '@/geo/map/map-viewer';
import { MapEventProcessor } from './map-event-processor';

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

export class AppEventProcessor extends AbstractEventProcessor {
// Static functions for Typescript files to access store actions
// **********************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,7 @@ import { TypeLayerData } from '@/geo/layer/layer-sets/abstract-layer-set';
import { TypeAllFeatureInfoResultSet } from '@/geo/layer/layer-sets/all-feature-info-layer-set';
import { MapEventProcessor } from './map-event-processor';

// GV The paradigm when working with DataTableEventProcessor vs DataTableState goes like this:
// GV DataTableState provides: 'state values', 'actions' and 'setterActions'.
// GV Whereas Zustand would suggest having 'state values' and 'actions', in GeoView, we have a 'DataTableEventProcessor' in the middle.
// GV This is because we wanted to have centralized code between UI actions and backend actions via a DataTableEventProcessor.
// GV In summary:
// GV The UI components should use DataTableState's 'state values' to read and 'actions' to set states (which simply redirect to DataTableEventProcessor).
// GV The back-end code should use DataTableEventProcessor which uses 'state values' and 'setterActions'
// GV Essentially 3 main call-stacks:
// GV - DataTableEventProcessor ---calls---> DataTableState.setterActions
// GV - UI Component ---calls---> DataTableState.actions ---calls---> DataTableEventProcessor ---calls---> DataTableState.setterActions
// GV - DataTableEventProcessor ---triggers---> DataTableViewer events ---calls---> DataTableState.setterActions
// GV The reason for this pattern is so that UI components and processes performing back-end code
// GV both end up running code in DataTableEventProcessor (UI: via 'actions' and back-end code via 'DataTableEventProcessor')
// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

export class DataTableEventProcessor extends AbstractEventProcessor {
// **********************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { EventType, TypeLayerData } from '@/geo/layer/layer-sets/abstract-layer-
import { AbstractEventProcessor, BatchedPropagationLayerDataArrayByMap } from '@/api/event-processors/abstract-event-processor';
import { UIEventProcessor } from './ui-event-processor';

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

/**
* Event processor focusing on interacting with the feature info state in the store (currently called detailsState).
*/
Expand Down Expand Up @@ -77,7 +79,7 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
// Redirect to helper function
this.#deleteFromArray(featureInfoState.layerDataArray, layerPath, (layerArrayResult) => {
// Update the layer data array in the store
featureInfoState.actions.setLayerDataArray(layerArrayResult);
featureInfoState.setterActions.setLayerDataArray(layerArrayResult);

// Log
logger.logInfo('Removed Feature Info in stores for layer path:', layerPath);
Expand Down Expand Up @@ -135,7 +137,7 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
const atLeastOneFeature = layerDataArray.find((layerEntry) => !!layerEntry.features?.length) || false;

// Update the layer data array in the store, all the time, for all statuses
featureInfoState.actions.setLayerDataArray(layerDataArray);
featureInfoState.setterActions.setLayerDataArray(layerDataArray);

// If there was some features on this propagation
if (atLeastOneFeature) {
Expand Down Expand Up @@ -175,10 +177,10 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
layerDataArray,
this.#batchedPropagationLayerDataArray,
this.#timeDelayBetweenPropagationsForBatch,
featureInfoState.actions.setLayerDataArrayBatch,
featureInfoState.setterActions.setLayerDataArrayBatch,
'feature-info-processor',
featureInfoState.layerDataArrayBatchLayerPathBypass,
featureInfoState.actions.setLayerDataArrayBatchLayerPathBypass
featureInfoState.setterActions.setLayerDataArrayBatchLayerPathBypass
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { TypeLayerData } from '@/geo/layer/layer-sets/abstract-layer-set';

import { AbstractEventProcessor, BatchedPropagationLayerDataArrayByMap } from '@/api/event-processors/abstract-event-processor';

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

/**
* Event processor focusing on interacting with the geochart state in the store.
*/
Expand Down Expand Up @@ -102,7 +104,7 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
});

// set store charts config
this.getGeochartState(mapId)?.actions.setGeochartCharts(chartData);
this.getGeochartState(mapId)?.setterActions.setGeochartCharts(chartData);

// Log
logger.logInfo('Added GeoChart configs for layer paths:', layerPaths);
Expand All @@ -124,7 +126,7 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
toAdd[layerPath] = chartConfig;

// Update the layer data array in the store
this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...this.getGeochartState(mapId)?.geochartChartsConfig, ...toAdd });
this.getGeochartState(mapId)!.setterActions.setGeochartCharts({ ...this.getGeochartState(mapId)?.geochartChartsConfig, ...toAdd });

// Log
logger.logInfo('Added GeoChart configs for layer path:', layerPath);
Expand All @@ -150,7 +152,7 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
delete chartConfigs[layerPath];

// Update the layer data array in the store
this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...chartConfigs });
this.getGeochartState(mapId)!.setterActions.setGeochartCharts({ ...chartConfigs });

// Log
logger.logInfo('Removed GeoChart configs for layer path:', layerPath);
Expand All @@ -170,7 +172,7 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
if (!this.getGeochartState(mapId)) return;

// Update the layer data array in the store
this.getGeochartState(mapId)!.actions.setLayerDataArray(layerDataArray);
this.getGeochartState(mapId)!.setterActions.setLayerDataArray(layerDataArray);
}

/**
Expand Down Expand Up @@ -198,10 +200,10 @@ export class GeochartEventProcessor extends AbstractEventProcessor {
layerDataArray,
this.batchedPropagationLayerDataArray,
this.timeDelayBetweenPropagationsForBatch,
geochartState.actions.setLayerDataArrayBatch,
geochartState.setterActions.setLayerDataArrayBatch,
'geochart-processor',
geochartState.layerDataArrayBatchLayerPathBypass,
geochartState.actions.setLayerDataArrayBatchLayerPathBypass
geochartState.setterActions.setLayerDataArrayBatchLayerPathBypass
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
import { AppEventProcessor } from './app-event-processor';
import { MapEventProcessor } from './map-event-processor';

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

export class LegendEventProcessor extends AbstractEventProcessor {
// **********************************************************
// Static functions for Typescript files to access store actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export class MapEventProcessor extends AbstractEventProcessor {
try {
// Check if the plugins exist
// TODO: if you run the code fast enough (only happened to me in the TimeSliderEventProcessor),
// TD.CONT: the getMapViewer should be async, because it can be unset as well ( so not just getMapViewerPlugins() ).
// TO.DOCONT: the getMapViewer should be async, because it can be unset as well ( so not just getMapViewerPlugins() ).
await whenThisThen(() => api && api.maps && api.maps[mapId] && api.maps[mapId].plugins);
} catch (error) {
// Log
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { logger } from '@/core/utils/logger';

import { AbstractEventProcessor } from '@/api/event-processors/abstract-event-processor';

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

/**
* Event processor focusing on interacting with the swiper state in the store.
*/
Expand Down Expand Up @@ -34,7 +36,7 @@ export class SwiperEventProcessor extends AbstractEventProcessor {
*/
static setLayerPaths(mapId: string, layerPaths: string[]): void {
// set store layer paths
this.getSwiperState(mapId)?.actions.setLayerPaths(layerPaths);
this.getSwiperState(mapId)?.setterActions.setLayerPaths(layerPaths);

// Log
logger.logInfo('Added Swiper functionality for layer paths:', layerPaths);
Expand All @@ -60,7 +62,7 @@ export class SwiperEventProcessor extends AbstractEventProcessor {
updatedArray.push(layerPath);

// Update the layer data array in the store
this.getSwiperState(mapId)!.actions.setLayerPaths(updatedArray);
this.getSwiperState(mapId)!.setterActions.setLayerPaths(updatedArray);

// Log
logger.logInfo('Added Swiper functionality for layer path:', layerPath);
Expand Down Expand Up @@ -93,7 +95,7 @@ export class SwiperEventProcessor extends AbstractEventProcessor {
updatedArray.splice(layerIndex, 1);

// Update the layer data array in the store
this.getSwiperState(mapId)!.actions.setLayerPaths(updatedArray);
this.getSwiperState(mapId)!.setterActions.setLayerPaths(updatedArray);

// Log
logger.logInfo('Removed Swiper functionality for layer path:', layerPath);
Expand All @@ -119,7 +121,7 @@ export class SwiperEventProcessor extends AbstractEventProcessor {
const { layerPaths } = this.getSwiperState(mapId)!;

// Update the layer data array in the store
this.getSwiperState(mapId)!.actions.setLayerPaths([]);
this.getSwiperState(mapId)!.setterActions.setLayerPaths([]);

// Log
logger.logInfo('Removed Swiper functionality for all layer paths', layerPaths);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import { AbstractEventProcessor } from '@/api/event-processors/abstract-event-pr
import { AbstractGeoViewVector } from '@/geo/layer/geoview-layers/vector/abstract-geoview-vector';
import { ITimeSliderState, TypeTimeSliderValues } from '@/core/stores/store-interface-and-intial-values/time-slider-state';
import { getLocalizedValue } from '@/core/utils/utilities';
import { AbstractGeoViewLayer, CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { EsriDynamic } from '@/geo/layer/geoview-layers/raster/esri-dynamic';
import { WMS } from '@/geo/layer/geoview-layers/raster/wms';
import { TypeFeatureInfoLayerConfig, TypeLayerEntryConfig } from '@/geo/map/map-schema-types';
import { EsriImage } from '@/geo/layer/geoview-layers/raster/esri-image';
import { AppEventProcessor } from './app-event-processor';
import { MapEventProcessor } from './map-event-processor';

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

export class TimeSliderEventProcessor extends AbstractEventProcessor {
// **********************************************************
Expand All @@ -33,51 +36,40 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
/**
* Checks if the layer has time slider values. If there are, adds the time slider layer and applies filters.
* @param {string} mapId - The map id of the state to act on
* @param {AbstractGeoViewLayer} geoviewLayer - The GeoView layer to act on
* @param {TypeLayerEntryConfig} layerConfig - The layer path of the layer to add to the state
*/
static checkInitTimeSliderLayerAndApplyFilters(
mapId: string,
geoviewLayer: AbstractGeoViewLayer,
layerConfig: TypeLayerEntryConfig
): void {
static checkInitTimeSliderLayerAndApplyFilters(mapId: string, layerConfig: TypeLayerEntryConfig): void {
// If there is no TimeSlider
if (!this.getTimesliderState(mapId)) return;

// Get the time slider values
const timeSliderValues = this.getInitialTimeSliderValues(mapId, geoviewLayer, layerConfig);
const timeSliderValues = this.getInitialTimeSliderValues(mapId, layerConfig);

// If any
if (timeSliderValues) {
// Add the time slider in store
this.addTimeSliderLayerAndApplyFilters(mapId, geoviewLayer, layerConfig.layerPath, timeSliderValues);
this.addTimeSliderLayerAndApplyFilters(mapId, layerConfig.layerPath, timeSliderValues);
}
}

/**
* Adds a time slider layer to the state
* @param {string} mapId - The map id of the state to act on
* @param {AbstractGeoViewLayer} geoviewLayer - The GeoView layer to act on
* @param {string} layerPath - The layer path of the layer to add to the state
* @param {TypeTimeSliderValues} timeSliderValues - The time slider values to add and apply filters
*/
static addTimeSliderLayerAndApplyFilters(
mapId: string,
geoviewLayer: AbstractGeoViewLayer,
layerPath: string,
timeSliderValues: TypeTimeSliderValues
): void {
static addTimeSliderLayerAndApplyFilters(mapId: string, layerPath: string, timeSliderValues: TypeTimeSliderValues): void {
// If there is no TimeSlider
if (!this.getTimesliderState(mapId)) return;

// Create set part (because that's how it works for now)
const timeSliderLayer = { [layerPath]: timeSliderValues };

// Add it
this.getTimesliderState(mapId)?.actions.addTimeSliderLayer(timeSliderLayer);
this.getTimesliderState(mapId)?.setterActions.addTimeSliderLayer(timeSliderLayer);

const { defaultValue, field, filtering, minAndMax, values } = timeSliderLayer[layerPath];
this.applyFilters(geoviewLayer, layerPath, defaultValue, field, filtering, minAndMax, values);
this.applyFilters(mapId, layerPath, defaultValue, field, filtering, minAndMax, values);
}

/**
Expand All @@ -87,25 +79,27 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
*/
static removeTimeSliderLayer(mapId: string, layerPath: string): void {
// Redirect
this.getTimesliderState(mapId)?.actions.removeTimeSliderLayer(layerPath);
this.getTimesliderState(mapId)?.setterActions.removeTimeSliderLayer(layerPath);
}

/**
* Get initial values for a layer's time slider states
*
* @param {string} mapId - The id of the map
* @param {AbstractGeoViewLayer} geoviewLayer - The GeoView layer to act on
* @param {TypeLayerEntryConfig} layerConfig - The layer path of the layer to add to the state
* @returns {TimeSliderLayer | undefined}
*/
static getInitialTimeSliderValues(
mapId: string,
geoviewLayer: AbstractGeoViewLayer,
layerConfig: TypeLayerEntryConfig
): TypeTimeSliderValues | undefined {
const name = getLocalizedValue(layerConfig.layerName, AppEventProcessor.getDisplayLanguage(mapId)) || layerConfig.layerId;
static getInitialTimeSliderValues(mapId: string, layerConfig: TypeLayerEntryConfig): TypeTimeSliderValues | undefined {
// Get the layer using the map event processor, If no temporal dimension OR layerPath, return undefined
if (!layerConfig.layerPath) return undefined;
const geoviewLayer = MapEventProcessor.getMapViewerLayerAPI(mapId).getGeoviewLayer(layerConfig.layerPath)!;
const temporalDimensionInfo = geoviewLayer.getTemporalDimension(layerConfig.layerPath);
if (!temporalDimensionInfo || !temporalDimensionInfo.range) return undefined;

// Get layer name and temporal dimension
const name = getLocalizedValue(layerConfig.layerName, AppEventProcessor.getDisplayLanguage(mapId)) || layerConfig.layerId;

// Set defaults values from temporal dimension
const { range } = temporalDimensionInfo.range;
const defaultValueIsArray = Array.isArray(temporalDimensionInfo.default);
const defaultValue = defaultValueIsArray ? temporalDimensionInfo.default[0] : temporalDimensionInfo.default;
Expand Down Expand Up @@ -161,7 +155,7 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
/**
* Filter the layer provided in the layerPath variable according to current states (filtering and values)
*
* @param {AbstractGeoViewLayer} geoviewLayer - The GeoView layer to act on
* @param {string} mapId - The id of the map
* @param {string} layerPath - The path of the layer to filter
* @param {string} defaultValue - The default value to use if filters are off
* @param {string} field - The field to filter the layer by
Expand All @@ -171,14 +165,17 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
* @returns {void}
*/
static applyFilters(
geoviewLayer: AbstractGeoViewLayer,
mapId: string,
layerPath: string,
defaultValue: string,
field: string,
filtering: boolean,
minAndMax: number[],
values: number[]
): void {
// Get the layer using the map event processor
const geoviewLayer = MapEventProcessor.getMapViewerLayerAPI(mapId).getGeoviewLayer(layerPath)!;

const layerType = geoviewLayer.type;
if (layerType === CONST_LAYER_TYPES.WMS) {
if (filtering) {
Expand Down Expand Up @@ -210,6 +207,9 @@ export class TimeSliderEventProcessor extends AbstractEventProcessor {
}
(geoviewLayer as AbstractGeoViewVector | EsriDynamic).applyViewFilter(layerPath, filter);
}

this.getTimesliderState(mapId)?.setterActions.setFiltering(layerPath, filtering);
this.getTimesliderState(mapId)?.setterActions.setValues(layerPath, values);
}
// #endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,7 @@ import { TypeMapCorePackages, TypeValidAppBarCoreProps } from '@config/types/map
import { AbstractEventProcessor } from '@/api/event-processors/abstract-event-processor';
import { IUIState } from '@/core/stores/store-interface-and-intial-values/ui-state';

// GV The paradigm when working with UIEventProcessor vs UIState goes like this:
// GV UIState provides: 'state values', 'actions' and 'setterActions'.
// GV Whereas Zustand would suggest having 'state values' and 'actions', in GeoView, we have a 'UIEventProcessor' in the middle.
// GV This is because we wanted to have centralized code between UI actions and backend actions via a UIEventProcessor.
// GV In summary:
// GV The UI components should use UIState's 'state values' to read and 'actions' to set states (which simply redirect to UIEventProcessor).
// GV The back-end code should use UIEventProcessor which uses 'state values' and 'setterActions'
// GV Essentially 3 main call-stacks:
// GV - UIEventProcessor ---calls---> UIState.setterActions
// GV - UI Component ---calls---> UIState.actions ---calls---> UIEventProcessor ---calls---> UIState.setterActions
// GV - UIEventProcessor ---triggers---> UIViewer events ---calls---> UIState.setterActions
// GV The reason for this pattern is so that UI components and processes performing back-end code
// GV both end up running code in UIEventProcessor (UI: via 'actions' and back-end code via 'UIEventProcessor')
// GV Important: See notes in header of MapEventProcessor file for information on the paradigm to apply when working with UIEventProcessor vs UIState

export class UIEventProcessor extends AbstractEventProcessor {
// **********************************************************
Expand Down
Loading
Loading