Skip to content

Commit aec981d

Browse files
committed
Rebvased and removed the getFieldType and getFieldDomain overrides for EsriImage that were recently added
1 parent 04cdcec commit aec981d

File tree

14 files changed

+92
-140
lines changed

14 files changed

+92
-140
lines changed

packages/geoview-core/src/api/config/reader/geopackage-reader.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,6 @@ export class GeoPackageReader {
576576
name: fieldEntryKey,
577577
alias: fieldEntryKey,
578578
type: fieldType as 'string' | 'number' | 'date',
579-
domain: null,
580579
};
581580

582581
outfields.push(newOutfield);

packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,11 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
356356
{
357357
uid: 'coordinate-info-feature',
358358
fieldInfo: {
359-
latitude: { value: lat.toFixed(6), fieldKey: 0, dataType: 'number', alias: 'Latitude', domain: null },
360-
longitude: { value: lng.toFixed(6), fieldKey: 1, dataType: 'number', alias: 'Longitude', domain: null },
361-
utmZone: { value: utmIdentifier, fieldKey: 2, dataType: 'string', alias: 'UTM Identifier', domain: null },
362-
easting: { value: easting?.toFixed(2), fieldKey: 3, dataType: 'number', alias: 'Easting', domain: null },
363-
northing: { value: northing?.toFixed(2), fieldKey: 4, dataType: 'number', alias: 'Northing', domain: null },
359+
latitude: { value: lat.toFixed(6), fieldKey: 0, dataType: 'number', alias: 'Latitude' },
360+
longitude: { value: lng.toFixed(6), fieldKey: 1, dataType: 'number', alias: 'Longitude' },
361+
utmZone: { value: utmIdentifier, fieldKey: 2, dataType: 'string', alias: 'UTM Identifier' },
362+
easting: { value: easting?.toFixed(2), fieldKey: 3, dataType: 'number', alias: 'Easting' },
363+
northing: { value: northing?.toFixed(2), fieldKey: 4, dataType: 'number', alias: 'Northing' },
364364
ntsMapsheet: {
365365
value: ntsData?.features
366366
.filter((f) => f.properties.name !== '')
@@ -373,14 +373,12 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor {
373373
fieldKey: 5,
374374
dataType: 'string',
375375
alias: 'NTS Mapsheets',
376-
domain: null,
377376
},
378377
elevation: {
379378
value: elevationData?.altitude ? `${elevationData.altitude} m` : undefined,
380379
fieldKey: 6,
381380
dataType: 'string',
382381
alias: 'Elevation',
383-
domain: null,
384382
},
385383
},
386384
extent: undefined,

packages/geoview-core/src/api/types/map-schema-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ export type TypeOutfields = {
581581
name: string;
582582
alias: string;
583583
type: TypeOutfieldsType;
584-
domain?: null | codedValueType | rangeDomainType;
584+
domain?: codedValueType | rangeDomainType;
585585
};
586586

587587
/** The types supported by the outfields object. */
@@ -610,7 +610,7 @@ export type TypeFieldEntry = {
610610
value: unknown;
611611
dataType: TypeOutfieldsType;
612612
alias: string;
613-
domain: null | codedValueType | rangeDomainType;
613+
domain?: codedValueType | rangeDomainType;
614614
};
615615

616616
// Definition of the alias lookup for matching field names to aliases

packages/geoview-core/src/core/components/details/feature-detail-modal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ export default function FeatureDetailModal(): JSX.Element {
5656
value: feature.fieldInfo[fieldName]!.value,
5757
dataType: feature.fieldInfo[fieldName]!.dataType,
5858
alias: feature.fieldInfo[fieldName]!.alias ? feature.fieldInfo[fieldName]!.alias : fieldName,
59-
domain: null,
6059
};
6160
});
6261

packages/geoview-core/src/core/components/details/feature-info.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ export function FeatureInfo({ feature, containerType }: FeatureInfoProps): JSX.E
217217
feature.geoviewLayerType !== 'ogcWms' && feature.geoviewLayerType !== 'ogcWfs'
218218
? field!.alias || fieldName
219219
: (field!.alias || fieldName).split('.').pop() || '',
220-
domain: null,
221220
}));
222221
}, [feature]);
223222

packages/geoview-core/src/geo/layer/geoview-layers/esri-layer-common.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
TypeMetadataEsriLayerSummary,
2727
TypeMetadataEsriImage,
2828
TypeMosaicRule,
29+
TypeLayerMetadataFields,
2930
} from '@/api/types/layer-schema-types';
3031
import { Fetch } from '@/core/utils/fetch-helper';
3132
import type { ConfigBaseClass } from '@/api/config/validation-classes/config-base-class';
@@ -377,7 +378,7 @@ export class EsriUtilities {
377378
throw new LayerServiceMetadataUnableToFetchError(layerConfig.getGeoviewLayerId(), layerConfig.getLayerName(), formatError(error));
378379
}
379380
} else {
380-
// The layer metadata was alredy queried (same as the service metadata), use that
381+
// In the case of an EsriImage, the layer metadata was already queried (same as the service metadata), use that
381382
layerMetadata = layerConfig.getServiceMetadata()!;
382383
}
383384

@@ -435,7 +436,8 @@ export class EsriUtilities {
435436

436437
// Read variables
437438
const queryable = layerMetadata.capabilities.includes('Query') || layerMetadata.capabilities.includes('Catalog');
438-
const hasFields = !!layerMetadata.fields?.length;
439+
const { fields } = layerMetadata;
440+
const hasFields = !!fields?.length;
439441
const isGroupLayer = layerMetadataEsriDynamicLayer.type === 'Group Layer';
440442
const isMetadataGroup = layerConfig.getIsMetadataLayerGroup();
441443

@@ -444,7 +446,7 @@ export class EsriUtilities {
444446

445447
// Initialize the outfields
446448
// dynamic group layer doesn't have fields definition
447-
if (layerMetadata.fields && !isGroupLayer) {
449+
if (hasFields && !isGroupLayer) {
448450
// Get the outfields
449451
let outfields = layerConfig.getOutfields();
450452

@@ -454,14 +456,15 @@ export class EsriUtilities {
454456
outfields = [];
455457

456458
// Loop
457-
layerMetadata.fields.forEach((fieldEntry) => {
459+
fields.forEach((fieldEntry) => {
458460
// If the field is the geometry field
459461
if (layerMetadataEsriDynamicLayer.geometryField && fieldEntry?.name === layerMetadataEsriDynamicLayer.geometryField?.name) {
460462
// Keep the geometry field for future use
461463
layerConfig.setGeometryField({
462464
name: fieldEntry.name,
463465
alias: fieldEntry.alias || fieldEntry.name,
464-
type: layerMetadataEsriDynamicLayer.geometryType as TypeOutfieldsType, // Force the typing, because the type doesn't include all geometry type values
466+
// TODO: CHECK - Mismatch of TypeOutfieldsType and geometryType as string. This seems wrong, should the TypeOutfieldsType be enhanced to include geometry types?
467+
type: layerMetadataEsriDynamicLayer.geometryType as TypeOutfieldsType,
465468
});
466469

467470
// Skip that geometry field
@@ -472,8 +475,8 @@ export class EsriUtilities {
472475
const newOutfield: TypeOutfields = {
473476
name: fieldEntry.name,
474477
alias: fieldEntry.alias || fieldEntry.name,
475-
type: this.esriGetFieldType(layerConfig, fieldEntry.name),
476-
domain: this.esriGetFieldDomain(layerConfig, fieldEntry.name),
478+
type: this.esriGetFieldType(layerConfig, fields, fieldEntry.name),
479+
domain: this.esriGetFieldDomain(fields, fieldEntry.name),
477480
};
478481

479482
outfields!.push(newOutfield);
@@ -782,18 +785,32 @@ export class EsriUtilities {
782785

783786
/**
784787
* Returns the type of the specified field.
785-
* @param {EsriDynamicLayerEntryConfig | EsriFeatureLayerEntryConfig | EsriImageLayerEntryConfig} layerConfig The ESRI layer config
786-
* @param {string} fieldName field name for which we want to get the type.
787-
* @returns {TypeOutfieldsType} The type of the field.
788-
* @static
788+
*
789+
* For ESRI Image layers, well-known pixel fields (`PixelValue`, `ProcessedValue`, `Name`)
790+
* are short-circuited to `'string'` because they have no metadata entry.
791+
*
792+
* @param layerConfig - The ESRI layer config, used to detect EsriImage-specific fields.
793+
* @param fields - The metadata field definitions to search.
794+
* @param fieldName - Field name for which we want to get the type.
795+
* @returns The mapped outfield type (`'date'`, `'oid'`, `'number'`, or `'string'`).
789796
*/
790797
static esriGetFieldType(
791798
layerConfig: EsriDynamicLayerEntryConfig | EsriFeatureLayerEntryConfig | EsriImageLayerEntryConfig,
799+
fields: TypeLayerMetadataFields[],
792800
fieldName: string
793801
): TypeOutfieldsType {
794-
const esriFieldDefinitions = layerConfig.getLayerMetadata()?.fields;
795-
const fieldDefinition = esriFieldDefinitions?.find((metadataEntry) => metadataEntry.name === fieldName);
802+
// For EsriImage layers, handle well-known pixel fields that have no metadata entry
803+
if (layerConfig instanceof EsriImageLayerEntryConfig) {
804+
const lowerFieldName = fieldName.toLowerCase();
805+
if (lowerFieldName === 'pixelvalue' || lowerFieldName === 'processedvalue' || lowerFieldName === 'name') {
806+
return 'string';
807+
}
808+
}
809+
810+
// Find the field definition in the provided fields array
811+
const fieldDefinition = fields?.find((metadataEntry) => metadataEntry.name === fieldName);
796812
if (!fieldDefinition) return 'string';
813+
797814
const esriFieldType = fieldDefinition.type;
798815
if (esriFieldType === 'esriFieldTypeDate') return 'date';
799816
if (esriFieldType === 'esriFieldTypeOID') return 'oid';
@@ -808,20 +825,16 @@ export class EsriUtilities {
808825

809826
/**
810827
* Returns the domain of the specified field.
811-
* @param {EsriDynamicLayerEntryConfig | EsriFeatureLayerEntryConfig | EsriImageLayerEntryConfig} layerConfig The ESRI layer config
812-
* @param {string} fieldName field name for which we want to get the domain.
813-
* @returns {codedValueType | rangeDomainType | null} The domain of the field.
814-
* @static
828+
*
829+
* @param fields - The metadata field definitions to search.
830+
* @param fieldName - Field name for which we want to get the domain.
831+
* @returns The domain of the field, or `null` if not found.
815832
*/
816833
// TODO: ESRI domains are translated to GeoView domains in the configuration. Any GeoView layer that support geoview domains can
817834
// TO.DOCONT: call a method getFieldDomain that use config.source.featureInfo.outfields to find a field domain.
818-
static esriGetFieldDomain(
819-
layerConfig: EsriDynamicLayerEntryConfig | EsriFeatureLayerEntryConfig | EsriImageLayerEntryConfig,
820-
fieldName: string
821-
): codedValueType | rangeDomainType | null {
822-
const esriFieldDefinitions = layerConfig.getLayerMetadata()?.fields;
823-
const fieldDefinition = esriFieldDefinitions?.find((metadataEntry) => metadataEntry.name === fieldName);
824-
return fieldDefinition ? fieldDefinition.domain : null;
835+
static esriGetFieldDomain(fields: TypeLayerMetadataFields[], fieldName: string): codedValueType | rangeDomainType | undefined {
836+
// Find the field definition in the provided fields array
837+
return fields?.find((metadataEntry) => metadataEntry.name === fieldName)?.domain;
825838
}
826839

827840
// #endregion PARSING METHODS

packages/geoview-core/src/geo/layer/geoview-layers/vector/abstract-geoview-vector.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Extent } from 'ol/extent';
66
import { getUid } from 'ol/util';
77
import type { ReadOptions } from 'ol/format/Feature';
88

9-
import type { TypeOutfields } from '@/api/types/map-schema-types';
9+
import type { TypeOutfields, TypeOutfieldsType } from '@/api/types/map-schema-types';
1010
import type { TypePostSettings } from '@/api/types/layer-schema-types';
1111
import type { VectorLayerEntryConfig } from '@/api/config/validation-classes/vector-layer-entry-config';
1212
import { AbstractGeoViewLayer } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
@@ -254,14 +254,13 @@ export abstract class AbstractGeoViewVector extends AbstractGeoViewLayer {
254254
return;
255255
}
256256

257-
let type = 'string';
257+
let type = 'string' as TypeOutfieldsType;
258258
if (firstRow[index] && firstRow[index] !== '' && Number(firstRow[index])) type = 'number';
259259

260260
const newOutfield: TypeOutfields = {
261261
name: header,
262262
alias: header,
263-
type: type as 'string' | 'number',
264-
domain: null,
263+
type: type,
265264
};
266265
outfields!.push(newOutfield);
267266
}

packages/geoview-core/src/geo/layer/geoview-layers/vector/ogc-feature.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Options as SourceOptions } from 'ol/source/Vector';
44
import type { Projection as OLProjection } from 'ol/proj';
55

66
import { AbstractGeoViewVector } from '@/geo/layer/geoview-layers/vector/abstract-geoview-vector';
7-
import type { DisplayDateMode, TypeOutfields } from '@/api/types/map-schema-types';
7+
import type { DisplayDateMode, TypeOutfields, TypeOutfieldsType } from '@/api/types/map-schema-types';
88
import type {
99
TypeGeoviewLayerConfig,
1010
TypeMetadataOGCFeature,
@@ -292,15 +292,14 @@ export class OgcFeature extends AbstractGeoViewVector {
292292
const fieldEntry = fields[fieldEntryKey];
293293
if (fieldEntry.type === 'Geometry') return;
294294

295-
let fieldType = 'string';
295+
let fieldType = 'string' as TypeOutfieldsType;
296296
if (fieldEntry.type === 'date') fieldType = 'date';
297297
else if (['bigint', 'number'].includes(typeof fieldEntry)) fieldType = 'number';
298298

299299
const newOutfield: TypeOutfields = {
300300
name: fieldEntryKey,
301301
alias: fieldEntryKey,
302-
type: fieldType as 'string' | 'number' | 'date',
303-
domain: null,
302+
type: fieldType,
304303
};
305304
outfields!.push(newOutfield);
306305
});

packages/geoview-core/src/geo/layer/geoview-layers/vector/wfs.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,6 @@ export class WFS extends AbstractGeoViewVector {
636636
name: fieldEntry.name,
637637
alias: fieldEntry.alias ?? fieldEntry.name,
638638
type: WFS.getFieldType(fieldEntry.name, layerConfig),
639-
domain: null,
640639
};
641640

642641
outfields!.push(newOutfield);

packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import type {
2929
TypeOutfields,
3030
TypeLayerStyleSettings,
3131
TypeFeatureInfoResult,
32+
codedValueType,
33+
rangeDomainType,
3234
} from '@/api/types/map-schema-types';
3335
import { type TypeLayerMetadataFields, type TypeGeoviewLayerType, type TypeMetadataEsriDynamicLayer } from '@/api/types/layer-schema-types';
3436
import type { GeoViewError } from '@/core/exceptions/geoview-exceptions';
@@ -1816,10 +1818,18 @@ export abstract class AbstractGVLayer extends AbstractBaseGVLayer {
18161818
// eslint-disable-next-line no-param-reassign
18171819
featureInfoEntry.fieldInfo[fieldEntry.name] = {
18181820
fieldKey: fieldKeyCounter++,
1819-
value: callbackGetFieldValue(feature, fieldEntry.name, fieldEntry.type, inputFormat, inputTimezone, inputTemporalMode),
1821+
value: callbackGetFieldValue(
1822+
feature,
1823+
fieldEntry.name,
1824+
fieldEntry.type,
1825+
fieldEntry.domain,
1826+
inputFormat,
1827+
inputTimezone,
1828+
inputTemporalMode
1829+
),
18201830
dataType: fieldEntry.type,
18211831
alias: fieldEntry.alias,
1822-
domain: fieldEntry.domain ?? null,
1832+
domain: fieldEntry.domain,
18231833
};
18241834
}
18251835
}
@@ -1830,22 +1840,29 @@ export abstract class AbstractGVLayer extends AbstractBaseGVLayer {
18301840

18311841
/**
18321842
* Retrieves and formats the value of a field from an OpenLayers feature.
1833-
* For fields of type `date`, the value is normalized and formatted using the
1834-
* date management utilities. Date values may be provided as epoch milliseconds
1835-
* or as date strings and are converted to a short ISO-like string.
1836-
* @param {Feature} feature - The OpenLayers feature containing the field values.
1837-
* @param {string} fieldName - The name of the field to retrieve.
1838-
* @param {TypeOutfieldsType} fieldType - The type of the field (e.g. `'string'`, `'number'`, `'date'`).
1839-
* @param {string | string[] | undefined} [inputFormat] - The format(s) to prioritize for string inputs. Defaults to an ISO-like format.
1840-
* @param {TimeIANA | undefined} [inputTimezone] - The IANA timezone to assume when interpreting input date values.
1841-
* @param {TemporalMode | undefined} [inputTemporalMode] - When `calendar`, treats the input as a calendar-date-only value (no timezones). When 'instant', treats the input as moment in time (timezones aware).
1842-
* @returns {unknown} The formatted field value. For date fields, this is a
1843-
* formatted date string; for other field types, the raw field value is returned.
1843+
* - For `date` fields, the raw value (epoch ms or date string) is normalized
1844+
* via the date management utilities.
1845+
* - For fields with a `codedValue` domain, the raw code is resolved to its
1846+
* human-readable name. If no matching code is found, the raw value is returned.
1847+
* - For all other fields, the raw value is returned as-is.
1848+
*
1849+
* @param feature - The OpenLayers feature containing the field values.
1850+
* @param fieldName - The name of the field to retrieve.
1851+
* @param fieldType - The data type of the field (e.g. `'string'`, `'number'`, `'date'`, `'oid'`).
1852+
* @param fieldDomain - Optional domain metadata. When present and of type `codedValue`,
1853+
* the raw field value is mapped to the corresponding coded-value name.
1854+
* @param inputFormat - Optional format(s) to prioritize when parsing date string inputs.
1855+
* @param inputTimezone - Optional IANA timezone to assume when interpreting date values.
1856+
* @param inputTemporalMode - Optional temporal mode. `'calendar'` treats dates as
1857+
* timezone-agnostic calendar dates; `'instant'` treats them as timezone-aware moments.
1858+
* @returns The processed field value: a formatted date for date fields, the decoded
1859+
* name for coded-value domains, or the raw value otherwise.
18441860
*/
18451861
static helperGetFieldValue(
18461862
feature: Feature,
18471863
fieldName: string,
18481864
fieldType: TypeOutfieldsType,
1865+
fieldDomain: codedValueType | rangeDomainType | undefined,
18491866
inputFormat: string | string[] | undefined,
18501867
inputTimezone: TimeIANA | undefined,
18511868
inputTemporalMode: TemporalMode | undefined
@@ -1855,6 +1872,16 @@ export abstract class AbstractGVLayer extends AbstractBaseGVLayer {
18551872
// Read the date
18561873
return DateMgt.createDate(fieldValue, inputFormat, inputTimezone, inputTemporalMode);
18571874
}
1875+
1876+
// If the field has a domain
1877+
if (fieldDomain && fieldDomain.type === 'codedValue') {
1878+
// Find the coded value corresponding to the value
1879+
const codedValue = fieldDomain.codedValues.find((cv) => cv.code === fieldValue);
1880+
1881+
// Read the value from the domain
1882+
return codedValue ? codedValue.name : fieldValue;
1883+
}
1884+
18581885
return fieldValue;
18591886
}
18601887

@@ -1867,6 +1894,7 @@ export type GetFieldValueDelegate = (
18671894
feature: Feature,
18681895
fieldName: string,
18691896
fieldType: TypeOutfieldsType,
1897+
fieldDomain: codedValueType | rangeDomainType | undefined,
18701898
inputFormat: string | string[] | undefined,
18711899
inputTimezone: TimeIANA | undefined,
18721900
inputTemporalMode: TemporalMode | undefined

0 commit comments

Comments
 (0)