From a0cbcdf105737cabca959f6692627670e98dfbd2 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 11 Nov 2025 20:40:04 -0600 Subject: [PATCH 01/15] [interfaces/ocotillo] Update types & display panel to reflect those changes --- src/components/card/CoreWellInfo.tsx | 108 +++++++++--------- .../card/InteractiveSatelliteMap.tsx | 43 +++---- src/interfaces/ocotillo/ILocation.ts | 34 +++--- src/interfaces/ocotillo/IThing.ts | 36 ++++-- src/pages/ocotillo/thing/well-show.tsx | 2 +- 5 files changed, 120 insertions(+), 103 deletions(-) diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index a680b8e1..557e9fb9 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -1,4 +1,4 @@ -import { IGroup, IWell } from '@/interfaces/ocotillo/IThing' +import { IWell } from '@/interfaces/ocotillo/IThing' import { Card, CardContent, @@ -10,36 +10,20 @@ import { Typography, } from '@mui/material' import Grid from '@mui/material/Grid2' -import { convertLonLatToUTM, parseWktPoint } from '@/utils' -import { useQuery } from '@tanstack/react-query' -import { apiFetch } from '@/utils' - -export const CoreWellInfoCard = ({well, usgs_id, osepod_id}: { well: IWell, usgs_id: string, osepod_id: string }) => { - - // ({ well }: { well: IWell }) => { - const coords = parseWktPoint(well?.current_location?.point) - const [easting, northing] = coords - ? convertLonLatToUTM(coords.lon, coords.lat) - : [undefined, undefined] +export const CoreWellInfoCard = ({ + well, + usgs_id, + osepod_id, +}: { + well: IWell + usgs_id: string + osepod_id: string +}) => { if (!well) { return } - const groupId = well?.group_id - const groupQuery = useQuery({ - queryKey: ['group', groupId], - queryFn: async () => { - if (!groupId) return null - - return apiFetch({ - endpoint: `/group/${groupId}`, - failureMessage: 'Failed to fetch group', - }) - }, - enabled: Boolean(groupId), - }) - return ( {well?.name}} /> @@ -53,15 +37,17 @@ export const CoreWellInfoCard = ({well, usgs_id, osepod_id}: { well: IWell, usgs alignItems="center" justifyContent="space-around" > - + {(well?.well_purposes && well.well_purposes.length > 0 + ? well.well_purposes + : [well?.thing_type || 'UNKNOWN TYPE'] + ).map((p) => ( + + ))} - {groupQuery.isLoading ? ( - - ) : ( + {well?.groups?.map((g) => ( - )} + ))} @@ -106,24 +82,48 @@ export const CoreWellInfoCard = ({well, usgs_id, osepod_id}: { well: IWell, usgs + Measuring Point Height: + + {well?.measuring_point_height || 'N/A'}{' '} + {well?.measuring_point_height + ? well?.measuring_point_height_unit + : null} + + + Northing/Easting: - {`${northing?.toFixed(0) || 'N/A'}, ${easting?.toFixed(0) || 'N/A'}`} + {`${well?.current_location?.properties?.utm_coordinates?.easting?.toFixed(0) || 'N/A'}, ${well?.current_location?.properties?.utm_coordinates?.northing?.toFixed(0) || 'N/A'}`} + + + + Vertical Datum: + + {well?.current_location?.properties?.vertical_datum || 'N/A'}{' '} Latitude/Longitude: - {coords - ? `${coords.lat?.toFixed(6)}, ${coords.lon?.toFixed(6)}` + {well?.current_location?.geometry?.coordinates + ? `${well?.current_location?.geometry?.coordinates?.[0]?.toFixed(6)}, ${well?.current_location?.geometry?.coordinates?.[1]?.toFixed(6)}` : 'N/A'} - + Elevation: - {well?.current_location?.elevation?.toFixed(0) || 'N/A'} - {well?.current_location?.elevation ? ' ft' : null} + {well?.current_location?.properties?.elevation?.toFixed(0) || + 'N/A'} + {well?.current_location?.properties?.elevation_unit + ? ` ${well?.current_location?.properties?.elevation_unit}` + : null} + + + + Elevation Method: + + {well?.current_location?.properties?.elevation_method || 'N/A'} diff --git a/src/components/card/InteractiveSatelliteMap.tsx b/src/components/card/InteractiveSatelliteMap.tsx index 72c62929..cbb8a9fb 100644 --- a/src/components/card/InteractiveSatelliteMap.tsx +++ b/src/components/card/InteractiveSatelliteMap.tsx @@ -1,3 +1,4 @@ +import { useEffect, useRef, useState } from 'react' import { IWell } from '@/interfaces/ocotillo/IThing' import { Box, @@ -12,8 +13,6 @@ import { Map } from '@mui/icons-material' import { Layer, MapRef, Source } from 'react-map-gl' import { MapComponent, MapPopup } from '@/components' import { useThingLayers } from '@/hooks' -import { parseWktPoint } from '@/utils' -import { useEffect, useRef, useState } from 'react' import { useGo } from '@refinedev/core' export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { @@ -26,15 +25,16 @@ export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { const waterWellsLayer = THING_LAYERS['water-wells'] const { sourceProps, layerProps } = waterWellsLayer - const coords = well ? parseWktPoint(well?.current_location?.point) : null + const coordinates = well?.current_location?.geometry?.coordinates ?? [] + const [lon, lat] = coordinates // Automatically zoom to well coordinates when map loads or well changes useEffect(() => { - if (!coords || !mapRef.current) return + if (!lon || !lat || !mapRef.current) return const map = mapRef.current.getMap() map.flyTo({ - center: [coords.lon, coords.lat], + center: [lon, lat], zoom: 14, essential: true, // for accessibility }) @@ -44,21 +44,22 @@ export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { return } - const highlightFeature = coords - ? { - type: 'FeatureCollection', - features: [ - { - type: 'Feature', - geometry: { - type: 'Point', - coordinates: [coords.lon, coords.lat], + const highlightFeature = + lon && lat + ? { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [lon, lat], + }, + properties: { name: well.name }, }, - properties: { name: well.name }, - }, - ], - } - : null + ], + } + : null const onMapPointClick = (_: any, points: any[]) => { const selectedPoint = points[0] @@ -116,8 +117,8 @@ export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { Date: Tue, 11 Nov 2025 21:25:18 -0600 Subject: [PATCH 02/15] [interfaces/FieldConfigs] Fix broken types --- src/components/DynamicShowDisplay.tsx | 29 +++++++++---------- src/components/SpatialSearchComponent.tsx | 2 +- .../form/thing/SelectThingComponent.tsx | 22 ++------------ src/components/pdf/well.tsx | 25 ++++++++-------- src/interfaces/FieldConfigs.ts | 7 +++++ src/interfaces/index.ts | 1 + src/interfaces/ocotillo/ILocation.ts | 1 + src/pages/ocotillo/location/show.tsx | 3 +- 8 files changed, 41 insertions(+), 49 deletions(-) create mode 100644 src/interfaces/FieldConfigs.ts diff --git a/src/components/DynamicShowDisplay.tsx b/src/components/DynamicShowDisplay.tsx index a1251271..cd35014b 100644 --- a/src/components/DynamicShowDisplay.tsx +++ b/src/components/DynamicShowDisplay.tsx @@ -1,33 +1,27 @@ import { Stack, Typography, Box } from '@mui/material' import { TextFieldComponent as TextField } from '@refinedev/mui' +import { FieldConfigs } from '@/interfaces' /** * DynamicShowDisplay Component * A component to use on the show.tsx pages to dynamically display the fields of a record. * This component is to be used as a default on show.tsx pages. It processes the json response from the api and displays the fields * in a basic way. More avanced shows should be created on a per entity basis. - * + * * @param record - The record to display * @param fieldConfigs - The field configurations for custom field display, field config interface: * label: the label to display for the field * formatter: a function to format the value of the field (optional) * hidden: whether to hide the field (boolean) (optional) - * + * * @param excludeFields - The fields to exclude * @param autoFormatLabels - Whether to automatically format the labels */ -//field config interface -interface FieldConfig { - label: string - formatter?: (value: any) => string | React.ReactNode - hidden?: boolean -} - //component props interface DynamicShowDisplayProps { record: T - fieldConfigs?: Partial> + fieldConfigs?: FieldConfigs excludeFields?: Array autoFormatLabels?: boolean } @@ -36,26 +30,29 @@ export const DynamicShowDisplay = >({ record, fieldConfigs = {}, excludeFields = [], - autoFormatLabels = true + autoFormatLabels = true, }: DynamicShowDisplayProps) => { - const formatLabel = (key: string): string => { if (!autoFormatLabels) return key return key .replace(/([A-Z])/g, ' $1') - .replace(/^./, str => str.toUpperCase()) + .replace(/^./, (str) => str.toUpperCase()) .replace(/_/g, ' ') } //handle value for rendering arrays nad objects from json response const renderValue = (value: any): React.ReactNode => { if (value === null || value === undefined) { - return - + return ( + + - + + ) } //handle arrays and objects!! if (Array.isArray(value) || typeof value === 'object') { return ( - + {JSON.stringify(value, null, 2)} ) @@ -92,4 +89,4 @@ export const DynamicShowDisplay = >({ {record && Object.keys(record).map((key) => renderField(key))} ) -} \ No newline at end of file +} diff --git a/src/components/SpatialSearchComponent.tsx b/src/components/SpatialSearchComponent.tsx index 47dca8d5..46eeffaa 100644 --- a/src/components/SpatialSearchComponent.tsx +++ b/src/components/SpatialSearchComponent.tsx @@ -1,5 +1,5 @@ import React, { useRef, useState } from 'react' -import { Button, Modal, useTheme } from '@mui/material' +import { Button, Modal } from '@mui/material' import wellknown from 'wellknown' import { Place } from '@mui/icons-material' import { Box } from '@mui/system' diff --git a/src/components/form/thing/SelectThingComponent.tsx b/src/components/form/thing/SelectThingComponent.tsx index 41c741c3..3c9e7332 100644 --- a/src/components/form/thing/SelectThingComponent.tsx +++ b/src/components/form/thing/SelectThingComponent.tsx @@ -1,6 +1,6 @@ import { Box } from '@mui/system' import { useAutocomplete } from '@refinedev/mui' -import { IWell, IThing } from '@/interfaces/ocotillo/IThing' +import { IThing } from '@/interfaces/ocotillo/IThing' import { Controller } from 'react-hook-form' import Autocomplete from '@mui/material/Autocomplete' import TextField from '@mui/material/TextField' @@ -173,7 +173,7 @@ export const SelectThingComponent: React.FC = ({ type: 'FeatureCollection', features: [], }) - } else if (newValue[0]?.active_location === null) { + } else if (newValue[0]?.current_location === null) { setSelectedThingFeatureCollection({ type: 'FeatureCollection', features: [], @@ -184,7 +184,7 @@ export const SelectThingComponent: React.FC = ({ features: newValue.map((item) => ({ type: 'Feature', id: item.id, - geometry: wellknown.parse(item.active_location.point), + geometry: item.current_location.geometry, properties: { name: item.name, id: item.id, @@ -292,7 +292,6 @@ export const SelectThingComponent: React.FC = ({ Well Details - @@ -307,22 +306,7 @@ export const SelectThingComponent: React.FC = ({
- {/*{selectedThing && */} - {/* */} - {/* */} - {/* */} - {/*}*/}
- {/**/} - {/* Well Details*/} - {/**/}
diff --git a/src/components/pdf/well.tsx b/src/components/pdf/well.tsx index 3f9e3818..318988d3 100644 --- a/src/components/pdf/well.tsx +++ b/src/components/pdf/well.tsx @@ -1,6 +1,6 @@ import { IAddress, IContact, IWell } from '@/interfaces/ocotillo/IThing' import { BaseRecord } from '@refinedev/core' -import { buildPdfFilename, convertLonLatToUTM, parseWktPoint } from '@/utils' +import { buildPdfFilename } from '@/utils' import { Document, Page, @@ -93,11 +93,6 @@ export const WellPDF = ({ assets: BaseRecord[] contacts: IContact[] }) => { - const coords = parseWktPoint(well?.current_location?.point) - const [easting, northing] = coords - ? convertLonLatToUTM(coords.lon, coords.lat) - : [undefined, undefined] - const filename = useMemo(() => buildPdfFilename(well), [well?.id]) const { primaryContact, secondaryContact } = useMemo(() => { @@ -151,10 +146,20 @@ export const WellPDF = ({ Date: - + - + @@ -218,10 +223,6 @@ export const WellPDF = ({ - string | React.ReactNode + hidden?: boolean +} + +export type FieldConfigs = Partial> diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 7a8e45f8..631664f4 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -5,4 +5,5 @@ export * from './IStatus' export * from './Nullable' export * from './Page' export * from './pydantic' +export * from './FieldConfigs' export * from './STATE_ABBREVIATIONS' diff --git a/src/interfaces/ocotillo/ILocation.ts b/src/interfaces/ocotillo/ILocation.ts index 49dcdb61..fa76c6c9 100644 --- a/src/interfaces/ocotillo/ILocation.ts +++ b/src/interfaces/ocotillo/ILocation.ts @@ -14,6 +14,7 @@ export interface ILocation { horizontal_datum?: string | null } } + created_at?: string } export interface GeoPoint3D extends GeoJSON.Point { diff --git a/src/pages/ocotillo/location/show.tsx b/src/pages/ocotillo/location/show.tsx index df01fa30..ea5ef316 100644 --- a/src/pages/ocotillo/location/show.tsx +++ b/src/pages/ocotillo/location/show.tsx @@ -2,6 +2,7 @@ import { useShow } from '@refinedev/core' import { Show } from '@refinedev/mui' import { ILocation } from '@/interfaces/ocotillo/ILocation' import { DynamicShowDisplay } from '@/components/DynamicShowDisplay' +import { FieldConfigs } from '@/interfaces' export const LocationShow = () => { const { queryResult } = useShow({}) @@ -9,7 +10,7 @@ export const LocationShow = () => { const record = data?.data as ILocation //custom configs for location - const fieldConfigs = { + const fieldConfigs: FieldConfigs = { created_at: { label: 'Created At', formatter: (value: string) => From d8ca45f0f145e23e938d94eda01c662e27e352fd Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Wed, 12 Nov 2025 09:20:03 -0600 Subject: [PATCH 03/15] [pdf/well] Add new fields to pdf --- src/components/Button/WellPDFDownload.tsx | 30 +++- src/components/card/CoreWellInfo.tsx | 6 + .../card/RecentWaterLevelObservations.tsx | 2 +- src/components/pdf/well.tsx | 137 ++++++++++++++---- .../ocotillo/thing/well-show-pdf-preview.tsx | 28 +++- src/pages/ocotillo/thing/well-show.tsx | 9 +- 6 files changed, 171 insertions(+), 41 deletions(-) diff --git a/src/components/Button/WellPDFDownload.tsx b/src/components/Button/WellPDFDownload.tsx index 6b5ef7fd..3427cbf2 100644 --- a/src/components/Button/WellPDFDownload.tsx +++ b/src/components/Button/WellPDFDownload.tsx @@ -20,6 +20,7 @@ import { WellPDF } from '@/components' import { ArrowDropDown, Download, Visibility } from '@mui/icons-material' import { buildPdfFilename } from '@/utils' import { pdf } from '@react-pdf/renderer' +import { useDataGrid } from '@refinedev/mui' export const WellPDFDownloadButton = ({ well, @@ -32,6 +33,22 @@ export const WellPDFDownloadButton = ({ const { data: permissions, isLoading: isPermissionsLoading } = usePermissions() + const { + dataGridProps: { rows: observations, loading: isObservationsloading }, + } = useDataGrid({ + resource: 'observation/groundwater-level', + dataProviderName: 'ocotillo', + meta: { + params: { + thing_id: well?.id, + }, + }, + queryOptions: { + cacheTime: 10 * 60 * 1000, // cached data for 10 minutes + staleTime: 5 * 60 * 1000, // get data fresh for 5 minutes, + }, + }) + const { data: assetData } = useList({ resource: 'asset', dataProviderName: 'ocotillo', @@ -70,7 +87,11 @@ export const WellPDFDownloadButton = ({ const isViewer = permissions?.includes('AMPViewer') ?? false const disabled = - isLoading || isPermissionsLoading || !isViewer || isGenerating + isLoading || + isPermissionsLoading || + !isViewer || + isGenerating || + isObservationsloading const handleDownload = async () => { try { @@ -79,7 +100,12 @@ export const WellPDFDownloadButton = ({ // Generate a PDF blob from the React PDF component const blob = await pdf( - + ).toBlob() // Create a temporary download link diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index 557e9fb9..a1b4d1fc 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -36,6 +36,12 @@ export const CoreWellInfoCard = ({ flexWrap="wrap" alignItems="center" justifyContent="space-around" + sx={{ + gap: 2, + rowGap: 2, + columnGap: 2, + mt: 1, + }} > {(well?.well_purposes && well.well_purposes.length > 0 ? well.well_purposes diff --git a/src/components/card/RecentWaterLevelObservations.tsx b/src/components/card/RecentWaterLevelObservations.tsx index c533093e..14f58b04 100644 --- a/src/components/card/RecentWaterLevelObservations.tsx +++ b/src/components/card/RecentWaterLevelObservations.tsx @@ -20,7 +20,7 @@ export const RecentWaterLevelObservationsCard = ({ isLoading = false, }: { well: IWell - rows: readonly any[] + rows: readonly IObservation[] isLoading: boolean }) => { if (!well || isLoading) { diff --git a/src/components/pdf/well.tsx b/src/components/pdf/well.tsx index 318988d3..6bb922de 100644 --- a/src/components/pdf/well.tsx +++ b/src/components/pdf/well.tsx @@ -10,6 +10,7 @@ import { Image, } from '@react-pdf/renderer' import { useMemo } from 'react' +import { IObservation } from '@/interfaces/ocotillo/IObservation' const styles = StyleSheet.create({ page: { @@ -38,11 +39,11 @@ const styles = StyleSheet.create({ }, cell3: { width: '32%', // slightly less than 1/3 for spacing - marginBottom: 1, + marginBottom: 1.5, }, cell2: { width: '48%', // slightly less than 1/2 for spacing - marginBottom: 1, + marginBottom: 1.5, }, label: { fontSize: 12, @@ -88,13 +89,28 @@ export const WellPDF = ({ well, assets, contacts, + observations, }: { well: IWell assets: BaseRecord[] contacts: IContact[] + observations: readonly Partial[] }) => { const filename = useMemo(() => buildPdfFilename(well), [well?.id]) + const { mostRecentObservation } = useMemo(() => { + if (!observations?.length) return { mostRecentObservation: undefined } + + // Sort descending by observation_datetime (most recent first) + const sorted = [...observations].sort((a, b) => { + const aTime = new Date(a.observation_datetime ?? 0).getTime() + const bTime = new Date(b.observation_datetime ?? 0).getTime() + return bTime - aTime + }) + + return { mostRecentObservation: sorted[0] } + }, [observations]) + const { primaryContact, secondaryContact } = useMemo(() => { if (!contacts?.length) return { primaryContact: undefined, secondaryContact: undefined } @@ -136,32 +152,52 @@ export const WellPDF = ({ + + + Date: + - Date: + + + + + - @@ -227,22 +263,63 @@ export const WellPDF = ({ title="Measurement Notes" value={(well as unknown as any)?.measurement_notes} /> - - - + + + + + + + + + + + + + + + + + + + + {assets.length === 0 && ( diff --git a/src/pages/ocotillo/thing/well-show-pdf-preview.tsx b/src/pages/ocotillo/thing/well-show-pdf-preview.tsx index fd6c0fac..8f796cf8 100644 --- a/src/pages/ocotillo/thing/well-show-pdf-preview.tsx +++ b/src/pages/ocotillo/thing/well-show-pdf-preview.tsx @@ -8,7 +8,7 @@ import { Typography, } from '@mui/material' import { HttpError, useList, useNavigation, useShow } from '@refinedev/core' -import { ListButton, Show, ShowButton } from '@refinedev/mui' +import { ListButton, Show, ShowButton, useDataGrid } from '@refinedev/mui' import { useParams } from 'react-router-dom' import { ArrowBack } from '@mui/icons-material' import { PDFViewer } from '@react-pdf/renderer' @@ -29,6 +29,22 @@ export const WellShowPdfPreview = () => { id, }) + const { + dataGridProps: { rows: observations, loading: isObservationsloading }, + } = useDataGrid({ + resource: 'observation/groundwater-level', + dataProviderName: 'ocotillo', + meta: { + params: { + thing_id: id, + }, + }, + queryOptions: { + cacheTime: 10 * 60 * 1000, // cached data for 10 minutes + staleTime: 5 * 60 * 1000, // get data fresh for 5 minutes, + }, + }) + const { data: assetData, isLoading: isAssetLoading } = useList({ resource: 'asset', dataProviderName: 'ocotillo', @@ -45,7 +61,8 @@ export const WellShowPdfPreview = () => { const assets = assetData?.data ?? [] const contacts = contactData?.data ?? [] - const isLoading = isWellLoading || isAssetLoading || isContactLoading + const isLoading = + isWellLoading || isAssetLoading || isContactLoading || isObservationsloading useEffect(() => { if (!isLoading) { @@ -93,7 +110,12 @@ export const WellShowPdfPreview = () => { }} > - + )} diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 7b24fa44..e0769541 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -1,6 +1,6 @@ import { HttpError, useResourceParams, useShow } from '@refinedev/core' import { Breadcrumb, Show, useDataGrid } from '@refinedev/mui' -import { IGroup, IWell } from '@/interfaces/ocotillo/IThing' +import { IWell } from '@/interfaces/ocotillo/IThing' import { Box, Stack, Typography } from '@mui/material' import { useEffect, useState } from 'react' import { IHydrographDatasource } from '@/interfaces/st2/IHydrographDatasource' @@ -32,7 +32,9 @@ export const WellShow = () => { >([]) const { id } = useResourceParams() - const { dataGridProps: observationDataGridProps } = useDataGrid({ + const { + dataGridProps: { rows: observations, loading: observationsIsloading }, + } = useDataGrid({ resource: 'observation/groundwater-level', dataProviderName: 'ocotillo', meta: { @@ -55,9 +57,6 @@ export const WellShow = () => { }, }) - const { rows: observations, loading: observationsIsloading } = - observationDataGridProps - const { rows: idLinks, loading: idLinksIsloading } = idLinkDataGridProps const usgs_id = idLinks?.find((link: any) => link.alternate_organization === 'USGS') From bd0ac2196797a73152b66b9b9de0d161c501fba9 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Wed, 12 Nov 2025 11:49:07 -0600 Subject: [PATCH 04/15] [CoreWellInfo] Patch Loading Skeletons --- src/components/card/CoreWellInfo.tsx | 34 +++++++++++++++++----------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index a1b4d1fc..8d6e9777 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -178,28 +178,36 @@ const LoadingCard = () => (
- - + + - - + + + + + + - - + + - + - + - - - + + + + + + + Alternate IDs @@ -207,11 +215,11 @@ const LoadingCard = () => ( - + - + From e5c311ee5761a69106b2fdb8f9ae285c76717f6d Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Thu, 13 Nov 2025 09:23:09 -0600 Subject: [PATCH 05/15] [CoreWellInfo] Update elevation to be fixed to 2 decimal points --- src/components/card/CoreWellInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index 8d6e9777..6863daff 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -119,7 +119,7 @@ export const CoreWellInfoCard = ({ Elevation: - {well?.current_location?.properties?.elevation?.toFixed(0) || + {well?.current_location?.properties?.elevation?.toFixed(2) || 'N/A'} {well?.current_location?.properties?.elevation_unit ? ` ${well?.current_location?.properties?.elevation_unit}` From 26a6f0e8e7c659e7daa0324c758b087517977400 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Thu, 13 Nov 2025 13:08:24 -0600 Subject: [PATCH 06/15] [pdf/well] Add roles to pdf --- src/components/pdf/well.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/pdf/well.tsx b/src/components/pdf/well.tsx index 6bb922de..c6b00157 100644 --- a/src/components/pdf/well.tsx +++ b/src/components/pdf/well.tsx @@ -211,7 +211,12 @@ export const WellPDF = ({ value={secondaryContact?.name} /> - + + + + + + Date: Thu, 13 Nov 2025 15:23:20 -0600 Subject: [PATCH 07/15] [src/generated] Updated types --- src/generated/types.gen.ts | 4 ---- src/generated/zod.gen.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/generated/types.gen.ts b/src/generated/types.gen.ts index 10bba985..3aa2c7d0 100644 --- a/src/generated/types.gen.ts +++ b/src/generated/types.gen.ts @@ -5071,10 +5071,6 @@ export type GetTransducerGroundwaterLevelObservationsObservationTransducerGround * Thing Id */ thing_id?: number | null; - /** - * Parameter Id - */ - parameter_id?: number | null; /** * Start Time */ diff --git a/src/generated/zod.gen.ts b/src/generated/zod.gen.ts index bf20bdc6..63fcc391 100644 --- a/src/generated/zod.gen.ts +++ b/src/generated/zod.gen.ts @@ -3334,10 +3334,6 @@ export const zGetTransducerGroundwaterLevelObservationsObservationTransducerGrou z.int(), z.null() ])), - parameter_id: z.optional(z.union([ - z.int(), - z.null() - ])), start_time: z.optional(z.union([ z.iso.datetime({ offset: true From 289b391a54341fcabb1a793b9cdb042f38496b2c Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 14 Nov 2025 09:10:30 -0600 Subject: [PATCH 08/15] [CI_cypress] Update workflow to use the auth docs --- .github/workflows/CI_cypress.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index f775b596..24328162 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -45,7 +45,7 @@ jobs: docker compose build --build-arg INSTALL_DEV=$INSTALL_DEV app docker compose up -d echo "Waiting for FastAPI to be ready..." - timeout 180 bash -c 'until curl -f http://localhost:8000/docs; do sleep 3; done' + timeout 180 bash -c 'until curl -f http://localhost:8000/docs-auth; do sleep 3; done' echo "FastAPI is up and healthy" - name: Seed database From 15c42d968609346e18a357414bcb322c937a5604 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 14 Nov 2025 09:21:23 -0600 Subject: [PATCH 09/15] [CI_cypress] Add startup and API logs to backend --- .github/workflows/CI_cypress.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index 24328162..12a2d63d 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -44,10 +44,23 @@ jobs: run: | docker compose build --build-arg INSTALL_DEV=$INSTALL_DEV app docker compose up -d + + - name: Show early API logs (startup) + working-directory: ./api-repo + run: docker compose logs --tail=200 app || true + + - name: Wait for FastAPI to be ready + working-directory: ./api-repo + run: | echo "Waiting for FastAPI to be ready..." timeout 180 bash -c 'until curl -f http://localhost:8000/docs-auth; do sleep 3; done' echo "FastAPI is up and healthy" + - name: Show API logs after readiness probe + if: always() + working-directory: ./api-repo + run: docker compose logs --tail=200 app || true + - name: Seed database working-directory: ./api-repo run: docker compose exec -T app python -m transfers.seed From 5b3e1cac4c974aeb0f2330bf14c72673b1c6dfd3 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 14 Nov 2025 09:27:46 -0600 Subject: [PATCH 10/15] [CI_cypress] Add envs to docker compose up step --- .github/workflows/CI_cypress.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index 12a2d63d..ba47d517 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -41,6 +41,11 @@ jobs: working-directory: ./api-repo env: INSTALL_DEV: true + POSTGRES_USER: ${{ secrets.PG_TEST_USER }} + POSTGRES_PASSWORD: ${{ secrets.PG_TEST_PW }} + POSTGRES_DB: ${{ secrets.PG_TEST_DB }} + POSTGRES_HOST: ${{ secrets.PG_TEST_HOST }} + POSTGRES_PORT: ${{ secrets.PG_TEST_PORT }} run: | docker compose build --build-arg INSTALL_DEV=$INSTALL_DEV app docker compose up -d From 6178a9935b6e479247142e31376d978d4fa818fa Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Mon, 17 Nov 2025 11:47:47 -0600 Subject: [PATCH 11/15] [CI_cypress] Hard code test db values --- .github/workflows/CI_cypress.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index ba47d517..fd5c88dd 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -9,13 +9,17 @@ jobs: env: NODE_ENV: test + MODE: development OCOTILLO_API_URL: http://localhost:8000 VITE_OCOTILLO_API_URL: http://localhost:8000 - POSTGRES_USER: ${{ secrets.PG_TEST_USER }} + AUTHENTIK_DISABLE_AUTHENTICATION: ${{ secrets.AUTHENTIK_TEST }} + + # --- DATABASE VALUES FOR DOCKER COMPOSE --- + POSTGRES_HOST: db + POSTGRES_PORT: 5432 + POSTGRES_USER: postgres POSTGRES_PASSWORD: ${{ secrets.PG_TEST_PW }} POSTGRES_DB: ${{ secrets.PG_TEST_DB }} - MODE: development - AUTHENTIK_DISABLE_AUTHENTICATION: ${{ secrets.AUTHENTIK_TEST }} steps: - name: Checkout frontend @@ -41,11 +45,6 @@ jobs: working-directory: ./api-repo env: INSTALL_DEV: true - POSTGRES_USER: ${{ secrets.PG_TEST_USER }} - POSTGRES_PASSWORD: ${{ secrets.PG_TEST_PW }} - POSTGRES_DB: ${{ secrets.PG_TEST_DB }} - POSTGRES_HOST: ${{ secrets.PG_TEST_HOST }} - POSTGRES_PORT: ${{ secrets.PG_TEST_PORT }} run: | docker compose build --build-arg INSTALL_DEV=$INSTALL_DEV app docker compose up -d @@ -58,7 +57,7 @@ jobs: working-directory: ./api-repo run: | echo "Waiting for FastAPI to be ready..." - timeout 180 bash -c 'until curl -f http://localhost:8000/docs-auth; do sleep 3; done' + timeout 180 bash -c 'until curl -f http://localhost:8000/docs; do sleep 3; done' echo "FastAPI is up and healthy" - name: Show API logs after readiness probe From e590765b2c0fd4ba6c579d5d73970cad9b70890a Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Mon, 17 Nov 2025 11:54:26 -0600 Subject: [PATCH 12/15] [CI_cypress] Replace remaining vars --- .github/workflows/CI_cypress.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index fd5c88dd..b4233e4a 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -18,8 +18,8 @@ jobs: POSTGRES_HOST: db POSTGRES_PORT: 5432 POSTGRES_USER: postgres - POSTGRES_PASSWORD: ${{ secrets.PG_TEST_PW }} - POSTGRES_DB: ${{ secrets.PG_TEST_DB }} + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres steps: - name: Checkout frontend From 24931e0eccd9bb0154ae43be7b015e4b6f289c2d Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Mon, 17 Nov 2025 13:42:39 -0600 Subject: [PATCH 13/15] [CI_cypress] Add more debug logs --- .github/workflows/CI_cypress.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index b4233e4a..25e021ef 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -41,6 +41,15 @@ jobs: - name: Install dependencies run: npm ci + - name: Debug env inside compose step + working-directory: ./api-repo + run: | + echo "POSTGRES_USER=$POSTGRES_USER" + echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" + echo "POSTGRES_DB=$POSTGRES_DB" + echo "POSTGRES_HOST=$POSTGRES_HOST" + echo "POSTGRES_PORT=$POSTGRES_PORT" + - name: Start FastAPI backend (Docker Compose) working-directory: ./api-repo env: @@ -49,6 +58,20 @@ jobs: docker compose build --build-arg INSTALL_DEV=$INSTALL_DEV app docker compose up -d + - name: Exec inside DB container + working-directory: ./api-repo + run: docker compose exec -T db pg_isready -U $POSTGRES_USER -d $POSTGRES_DB || true + + - name: Debug DB connectivity from app container + working-directory: ./api-repo + run: | + docker compose exec -T app bash -c " + echo 'Testing ping to db container:' && + ping -c 3 db || true && + echo 'Testing port 5432...' && + nc -zv db 5432 || true + " + - name: Show early API logs (startup) working-directory: ./api-repo run: docker compose logs --tail=200 app || true From 9f5722045738de34ce09c23ec2727d3744e6224a Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Mon, 17 Nov 2025 13:50:52 -0600 Subject: [PATCH 14/15] [CI_cypress] Add logs for DB logs --- .github/workflows/CI_cypress.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index 25e021ef..b6709188 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -72,6 +72,10 @@ jobs: nc -zv db 5432 || true " + - name: Show DB logs + working-directory: ./api-repo + run: docker compose logs --tail=200 db || true + - name: Show early API logs (startup) working-directory: ./api-repo run: docker compose logs --tail=200 app || true From 8beef828a71fdda95f321c6e9c0893e4045c61ef Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Mon, 17 Nov 2025 14:00:30 -0600 Subject: [PATCH 15/15] [CI_cypress] Update the retry logic --- .github/workflows/CI_cypress.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI_cypress.yml b/.github/workflows/CI_cypress.yml index b6709188..b4cdc9ad 100644 --- a/.github/workflows/CI_cypress.yml +++ b/.github/workflows/CI_cypress.yml @@ -84,7 +84,12 @@ jobs: working-directory: ./api-repo run: | echo "Waiting for FastAPI to be ready..." - timeout 180 bash -c 'until curl -f http://localhost:8000/docs; do sleep 3; done' + timeout 720 bash -c ' + until curl -sf http://localhost:8000/docs; do + echo "FastAPI not up yet, retrying..." + sleep 3 + done + ' echo "FastAPI is up and healthy" - name: Show API logs after readiness probe