From 2326499f630e5eaba1331954402b4623628d3e65 Mon Sep 17 00:00:00 2001 From: jakeross Date: Sat, 22 Aug 2026 08:19:52 -0700 Subject: [PATCH] feat(map-layers): register the six geothermal collections The catalog publishes geothermal_wells_bht, geothermal_wells_temperature_profile, bht_measurements, temp_depth_measurements, heat_flow, and dst, but no layer named any of them, so none reached the map or the collections page. The collections page even carried a Geothermal group described as reserved for these "when they are published" -- they are published. Registers all six in both registries, with the collection id as the first candidate and the display title as the fallback. Exact matching means the id is what binds; the titles carry em dashes, which normalize away, so either form resolves. The map's layer panel had no geothermal group -- getLayerGroupKey would have dropped all six into Reference. Adds the group between Climate and Geoscience, matched on 'geothermal', 'bht', 'temp-depth', 'heat-flow', and an exact 'ogc-dst'. The dst key is compared whole rather than by substring, since three letters collide too easily. The check runs first, before the groundwater branch, so a name like ogc-geothermal-wells-temperature-profile cannot be claimed by another group later. Popup labels are added for all six. No layer-specific popup rows yet -- the property shapes are unverified, so the generic renderer handles them until someone confirms what each collection carries. Layers are off by default, as every layer other than the summary is. Co-Authored-By: Claude Opus 5 --- src/components/MapPopupComponent.tsx | 6 ++ src/hooks/useThingLayers.tsx | 86 +++++++++++++++++++++++++ src/pages/ocotillo/collections/list.tsx | 41 +++++++++++- src/pages/ocotillo/map/list.tsx | 13 ++++ src/test/utils/ogcLayerUtils.test.ts | 23 +++++++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/src/components/MapPopupComponent.tsx b/src/components/MapPopupComponent.tsx index d5633785..f8a34b11 100644 --- a/src/components/MapPopupComponent.tsx +++ b/src/components/MapPopupComponent.tsx @@ -130,6 +130,12 @@ const getLayerLabel = (layerKey: string): string => { 'ogc-actively-monitored': 'Actively Monitored', 'ogc-springs': 'Springs', 'ogc-project-areas': 'AMP Project Areas', + 'ogc-geothermal-wells-bht': 'Geothermal Wells (BHT)', + 'ogc-geothermal-wells-temperature-profile': 'Geothermal Wells (Temp-Depth)', + 'ogc-bht-measurements': 'BHT Measurements', + 'ogc-temp-depth-measurements': 'Temperature-Depth Measurements', + 'ogc-heat-flow': 'Heat Flow', + 'ogc-dst': 'Drill Stem Tests', } return labelByLayer[layerKey] || titleCase(layerKey.replace(/^ogc-/, '')) diff --git a/src/hooks/useThingLayers.tsx b/src/hooks/useThingLayers.tsx index 64861906..7f73e8d6 100644 --- a/src/hooks/useThingLayers.tsx +++ b/src/hooks/useThingLayers.tsx @@ -150,6 +150,27 @@ export const useThingLayers = ( 'Soil Gas Sample Locations', 'soil_gas_sample_locations', ]) + const geothermalWellsBht = resolveCollection(collections, [ + 'geothermal_wells_bht', + 'Geothermal Wells — Bottom-Hole Temperature', + ]) + const geothermalWellsTemperatureProfile = resolveCollection(collections, [ + 'geothermal_wells_temperature_profile', + 'Geothermal Wells — Temperature-Depth Profile', + ]) + const bhtMeasurements = resolveCollection(collections, [ + 'bht_measurements', + 'BHT Measurements', + ]) + const tempDepthMeasurements = resolveCollection(collections, [ + 'temp_depth_measurements', + 'Temperature-Depth Measurements', + ]) + const heatFlow = resolveCollection(collections, ['heat_flow', 'Heat Flow']) + const drillStemTests = resolveCollection(collections, [ + 'dst', + 'Drill Stem Tests', + ]) const latestTdsLayer = useOGCLayer({ collection: latestTds.id, label: latestTds.label, @@ -649,6 +670,47 @@ export const useThingLayers = ( soilGasSampleLocations.exists && isLayerActive('ogc-soil-gas-sample-locations'), }) + const geothermalWellsBhtLayer = useOGCLayer({ + collection: geothermalWellsBht.id, + label: geothermalWellsBht.label, + color: '#b45309', + enabled: + geothermalWellsBht.exists && isLayerActive('ogc-geothermal-wells-bht'), + }) + const geothermalWellsTemperatureProfileLayer = useOGCLayer({ + collection: geothermalWellsTemperatureProfile.id, + label: geothermalWellsTemperatureProfile.label, + color: '#d97706', + enabled: + geothermalWellsTemperatureProfile.exists && + isLayerActive('ogc-geothermal-wells-temperature-profile'), + }) + const bhtMeasurementsLayer = useOGCLayer({ + collection: bhtMeasurements.id, + label: bhtMeasurements.label, + color: '#ea580c', + enabled: bhtMeasurements.exists && isLayerActive('ogc-bht-measurements'), + }) + const tempDepthMeasurementsLayer = useOGCLayer({ + collection: tempDepthMeasurements.id, + label: tempDepthMeasurements.label, + color: '#f59e0b', + enabled: + tempDepthMeasurements.exists && + isLayerActive('ogc-temp-depth-measurements'), + }) + const heatFlowLayer = useOGCLayer({ + collection: heatFlow.id, + label: heatFlow.label, + color: '#dc2626', + enabled: heatFlow.exists && isLayerActive('ogc-heat-flow'), + }) + const drillStemTestsLayer = useOGCLayer({ + collection: drillStemTests.id, + label: drillStemTests.label, + color: '#92400e', + enabled: drillStemTests.exists && isLayerActive('ogc-dst'), + }) return useMemo(() => { const result: Record = {} @@ -733,6 +795,24 @@ export const useThingLayers = ( soilGasSampleLocations, soilGasSampleLocationsLayer ) + addLayer( + 'ogc-geothermal-wells-bht', + geothermalWellsBht, + geothermalWellsBhtLayer + ) + addLayer( + 'ogc-geothermal-wells-temperature-profile', + geothermalWellsTemperatureProfile, + geothermalWellsTemperatureProfileLayer + ) + addLayer('ogc-bht-measurements', bhtMeasurements, bhtMeasurementsLayer) + addLayer( + 'ogc-temp-depth-measurements', + tempDepthMeasurements, + tempDepthMeasurementsLayer + ) + addLayer('ogc-heat-flow', heatFlow, heatFlowLayer) + addLayer('ogc-dst', drillStemTests, drillStemTestsLayer) return result }, [ @@ -756,5 +836,11 @@ export const useThingLayers = ( perennialStreamsLayer, rockSampleLocationsLayer, soilGasSampleLocationsLayer, + geothermalWellsBhtLayer, + geothermalWellsTemperatureProfileLayer, + bhtMeasurementsLayer, + tempDepthMeasurementsLayer, + heatFlowLayer, + drillStemTestsLayer, ]) } diff --git a/src/pages/ocotillo/collections/list.tsx b/src/pages/ocotillo/collections/list.tsx index 612ad570..5ed4a79c 100644 --- a/src/pages/ocotillo/collections/list.tsx +++ b/src/pages/ocotillo/collections/list.tsx @@ -228,6 +228,44 @@ const REGISTERED_MAP_COLLECTIONS: RegisteredMapCollection[] = [ groupKey: 'reference', candidates: ['Soil Gas Sample Locations', 'soil_gas_sample_locations'], }, + { + layerKey: 'ogc-geothermal-wells-bht', + groupKey: 'geothermal', + candidates: [ + 'geothermal_wells_bht', + 'Geothermal Wells — Bottom-Hole Temperature', + ], + displayLabel: 'Geothermal Wells (BHT)', + }, + { + layerKey: 'ogc-geothermal-wells-temperature-profile', + groupKey: 'geothermal', + candidates: [ + 'geothermal_wells_temperature_profile', + 'Geothermal Wells — Temperature-Depth Profile', + ], + displayLabel: 'Geothermal Wells (Temp-Depth)', + }, + { + layerKey: 'ogc-bht-measurements', + groupKey: 'geothermal', + candidates: ['bht_measurements', 'BHT Measurements'], + }, + { + layerKey: 'ogc-temp-depth-measurements', + groupKey: 'geothermal', + candidates: ['temp_depth_measurements', 'Temperature-Depth Measurements'], + }, + { + layerKey: 'ogc-heat-flow', + groupKey: 'geothermal', + candidates: ['heat_flow', 'Heat Flow'], + }, + { + layerKey: 'ogc-dst', + groupKey: 'geothermal', + candidates: ['dst', 'Drill Stem Tests'], + }, ] const trimTrailingSlash = (value: string) => value.replace(/\/+$/, '') @@ -314,7 +352,8 @@ const groupCollections = (collections: OgcCollectionRecord[]): CollectionGroup[] { key: 'geothermal', title: 'Geothermal', - description: 'Reserved for geothermal wells and supporting thermal, meteorological, and sample collections when they are published.', + description: + 'Geothermal wells with bottom-hole and temperature-depth data, plus the underlying measurements, heat flow, and drill stem tests.', collections: sortRegisteredCollections(grouped.geothermal), }, { diff --git a/src/pages/ocotillo/map/list.tsx b/src/pages/ocotillo/map/list.tsx index 38f68743..e9cd6729 100644 --- a/src/pages/ocotillo/map/list.tsx +++ b/src/pages/ocotillo/map/list.tsx @@ -109,6 +109,7 @@ const DEFAULT_EXPANDED_GROUPS = { groundwater: true, surfaceWater: true, climate: true, + geothermal: true, geoscience: true, reference: true, } @@ -116,6 +117,15 @@ const DEFAULT_EXPANDED_GROUPS = { const getLayerGroupKey = ( layerKey: string ): keyof typeof DEFAULT_EXPANDED_GROUPS => { + if ( + layerKey.includes('geothermal') || + layerKey.includes('bht') || + layerKey.includes('temp-depth') || + layerKey.includes('heat-flow') || + layerKey === 'ogc-dst' + ) { + return 'geothermal' + } if ( layerKey.includes('water-well') || layerKey.includes('actively-monitored') || @@ -156,6 +166,7 @@ const getExpandedGroupsForLayers = (layerKeys: string[]) => { groundwater: false, surfaceWater: false, climate: false, + geothermal: false, geoscience: false, reference: false, } @@ -694,6 +705,7 @@ export const MapView: React.FC = () => { groundwater: 'Groundwater', surfaceWater: 'Surface Water', climate: 'Climate', + geothermal: 'Geothermal', geoscience: 'Geoscience', reference: 'Reference', } @@ -710,6 +722,7 @@ export const MapView: React.FC = () => { groundwater: [] as Array<[string, any]>, surfaceWater: [] as Array<[string, any]>, climate: [] as Array<[string, any]>, + geothermal: [] as Array<[string, any]>, geoscience: [] as Array<[string, any]>, reference: [] as Array<[string, any]>, } diff --git a/src/test/utils/ogcLayerUtils.test.ts b/src/test/utils/ogcLayerUtils.test.ts index 6180725f..558ba505 100644 --- a/src/test/utils/ogcLayerUtils.test.ts +++ b/src/test/utils/ogcLayerUtils.test.ts @@ -65,6 +65,29 @@ describe('resolveCollection', () => { expect(resolved.id).toBe('springs') }) + it('matches a title containing an em dash', () => { + const resolved = resolveCollection( + [ + collection( + 'geothermal_wells_bht', + 'Geothermal Wells — Bottom-Hole Temperature' + ), + ], + ['Geothermal Wells — Bottom-Hole Temperature'] + ) + + expect(resolved.id).toBe('geothermal_wells_bht') + }) + + it('does not confuse dst with collections that contain it', () => { + const resolved = resolveCollection( + [collection('dst', 'Drill Stem Tests'), collection('dst_summary')], + ['dst'] + ) + + expect(resolved.id).toBe('dst') + }) + it('tries candidates in order', () => { const resolved = resolveCollection( [collection('project_area'), collection('project_areas')],