From 0cb4111972e67c80735dcd166f1db9fa9782f4f1 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 10 Apr 2026 10:56:11 -0500 Subject: [PATCH 01/52] feat(thing/list): Add contacts to well --- src/interfaces/ocotillo/IWell.ts | 4 +++- src/pages/ocotillo/thing/list.tsx | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/interfaces/ocotillo/IWell.ts b/src/interfaces/ocotillo/IWell.ts index 08fecb40..8555e9f1 100644 --- a/src/interfaces/ocotillo/IWell.ts +++ b/src/interfaces/ocotillo/IWell.ts @@ -1,4 +1,4 @@ -import type { IThing } from '@/interfaces/ocotillo' +import type { IContact, IThing } from '@/interfaces/ocotillo' import { z } from 'zod' import { zWellPurpose } from '@/generated/zod.gen' @@ -59,4 +59,6 @@ export interface IWell extends IThing { start_date: string | null end_date: string | null }[] + + contacts?: Partial[] | null } diff --git a/src/pages/ocotillo/thing/list.tsx b/src/pages/ocotillo/thing/list.tsx index ae273e71..ade022d5 100644 --- a/src/pages/ocotillo/thing/list.tsx +++ b/src/pages/ocotillo/thing/list.tsx @@ -21,7 +21,7 @@ export const SpringList: React.FC = () => { field: 'name', headerName: 'Name', type: 'string', - minWidth: 180, + minWidth: 100, flex: 1, }, { @@ -61,6 +61,11 @@ export const WellList: React.FC = () => { const { dataGridProps } = useDataGrid({ resource: 'thing/water-well', dataProviderName: 'ocotillo', + meta: { + params: { + include_contacts: true, + }, + }, pagination: { pageSize: 50 }, }) @@ -70,6 +75,7 @@ export const WellList: React.FC = () => { meta: { params: { thing_type: ['water well', 'geothermal well'], + include_contacts: true, }, }, }) @@ -80,7 +86,7 @@ export const WellList: React.FC = () => { field: 'name', headerName: 'Name', type: 'string', - minWidth: 160, + minWidth: 100, flex: 1, }, { @@ -108,7 +114,12 @@ export const WellList: React.FC = () => { flex: 1, sortable: false, valueGetter: (_: unknown, row: IWell) => - row.aquifers?.map((a) => a.aquifer_system).join(', ') ?? '', + row.aquifers + ?.map( + (a: { aquifer_system: string; aquifer_types: string[] }) => + a.aquifer_system + ) + .join(', ') ?? '', }, { field: 'release_status', @@ -138,6 +149,15 @@ export const WellList: React.FC = () => { width: 130, valueGetter: (v: string) => formatAppDate(v), }, + { + field: 'contacts', + headerName: 'Contacts', + minWidth: 180, + flex: 1, + sortable: false, + valueGetter: (_: unknown, row: IWell) => + row.contacts?.map((c) => c.name ?? '').join(', ') ?? '', + }, { field: 'well_completion_date', headerName: 'Completed', From f2b044ba9b688bbbcd2469fce35a8a1e3c3d7d86 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 10 Apr 2026 12:21:36 -0500 Subject: [PATCH 02/52] fix(contact/list): Fix broken link --- src/pages/ocotillo/contact/list.tsx | 32 ++++++++++++++++++-------- src/pages/ocotillo/thing/list.tsx | 35 ++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/pages/ocotillo/contact/list.tsx b/src/pages/ocotillo/contact/list.tsx index 8f2a8067..18c1d456 100644 --- a/src/pages/ocotillo/contact/list.tsx +++ b/src/pages/ocotillo/contact/list.tsx @@ -15,10 +15,7 @@ import { settings } from '@/settings' import { formatAppDateTime, formatPhone } from '@/utils' import { ListPage } from '@/components' import { useAccessCapabilities } from '@/hooks' -import { - filterConfidentialRows, - sanitizeContacts, -} from '@/utils' +import { filterConfidentialRows, sanitizeContacts } from '@/utils' export const ContactList: React.FC = () => { const { canViewConfidential } = useAccessCapabilities() @@ -126,7 +123,13 @@ export const ContactList: React.FC = () => { renderCell: (params) => { const things = params.row.things ?? [] return ( -
+
{things.map((thing, idx) => ( {idx > 0 && ', '} @@ -138,6 +141,7 @@ export const ContactList: React.FC = () => { id: thing.id, }, }} + onClick={(e) => e.stopPropagation()} > {thing.name} @@ -202,9 +206,15 @@ export const ContactList: React.FC = () => { /> {selectedContactId && ( <> - {canViewConfidential && } - {canViewConfidential && } - {canViewConfidential && } + {canViewConfidential && ( + + )} + {canViewConfidential && ( + + )} + {canViewConfidential && ( + + )} )} @@ -349,7 +359,11 @@ const InfoCard = ({ }) => ( - + ) diff --git a/src/pages/ocotillo/thing/list.tsx b/src/pages/ocotillo/thing/list.tsx index ade022d5..20f6ef07 100644 --- a/src/pages/ocotillo/thing/list.tsx +++ b/src/pages/ocotillo/thing/list.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react' -import { useExport, useGo } from '@refinedev/core' +import { useExport, useGo, useLink, useNavigation } from '@refinedev/core' import { ExportButton, useDataGrid } from '@refinedev/mui' import { GridColDef } from '@mui/x-data-grid' import { Button } from '@mui/material' @@ -80,6 +80,9 @@ export const WellList: React.FC = () => { }, }) + const { create } = useNavigation() + const Link = useLink() + const columns = useMemo[]>( () => [ { @@ -157,6 +160,36 @@ export const WellList: React.FC = () => { sortable: false, valueGetter: (_: unknown, row: IWell) => row.contacts?.map((c) => c.name ?? '').join(', ') ?? '', + renderCell: (params) => { + const contacts = params.row.contacts ?? [] + return ( +
+ {contacts.map((contact, idx) => ( + + {idx > 0 && ', '} + e.stopPropagation()} + > + {contact.name} + + + ))} +
+ ) + }, }, { field: 'well_completion_date', From f4690e4013fcd95d6d8683d1681a83139f60b097 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 10 Apr 2026 12:26:05 -0500 Subject: [PATCH 03/52] fix(thing/list): Rm unused import --- src/pages/ocotillo/thing/list.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/ocotillo/thing/list.tsx b/src/pages/ocotillo/thing/list.tsx index de96c6f8..d179f45a 100644 --- a/src/pages/ocotillo/thing/list.tsx +++ b/src/pages/ocotillo/thing/list.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from 'react' -import { useExport, useGo } from '@refinedev/core' +import { useExport, useGo, useLink } from '@refinedev/core' import { ExportButton, useDataGrid } from '@refinedev/mui' import { GridColDef, GridFilterModel } from '@mui/x-data-grid' import { captureEvent } from '@/analytics/posthog' @@ -97,7 +97,6 @@ export const WellList: React.FC = () => { }, }) - const { create } = useNavigation() const Link = useLink() const columns = useMemo[]>( @@ -297,7 +296,10 @@ export const WellList: React.FC = () => { ' construction depending on the local geology and intended use.' } columns={columns} - dataGridProps={{ ...dataGridProps, onFilterModelChange: handleFilterModelChange }} + dataGridProps={{ + ...dataGridProps, + onFilterModelChange: handleFilterModelChange, + }} getRowId={(row) => row.id} headerButtons={customHeaderButtons} /> From bf13b7421c2b6cb915dcb601195b9870745e7c87 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 10 Apr 2026 13:16:47 -0500 Subject: [PATCH 04/52] feat(ListPage): Impl client & server list page filtering --- src/components/ListPage.tsx | 147 ++++++++++++++++++++++++------ src/pages/ocotillo/thing/list.tsx | 17 +++- 2 files changed, 136 insertions(+), 28 deletions(-) diff --git a/src/components/ListPage.tsx b/src/components/ListPage.tsx index 51c580dc..839a59bd 100644 --- a/src/components/ListPage.tsx +++ b/src/components/ListPage.tsx @@ -13,14 +13,19 @@ import { GridFilterItem, useGridApiContext, useGridSelector, + GridColDef, } from '@mui/x-data-grid' import { settings } from '@/settings' import React, { useMemo, useState } from 'react' -import { CanAccess, useExport, useNavigation, useResourceParams } from '@refinedev/core' -import { Box, Chip, InputBase, Stack, Tooltip, Typography } from '@mui/material' +import { + CanAccess, + useExport, + useNavigation, + useResourceParams, +} from '@refinedev/core' +import { Box, Chip, InputBase, Stack, Typography } from '@mui/material' import SearchIcon from '@mui/icons-material/Search' - // Shows a dismissible chip for each active column filter. function ActiveFilterChips() { const apiRef = useGridApiContext() @@ -38,11 +43,23 @@ function ActiveFilterChips() { } return ( - + {activeFilters.map((filter) => { const column = columns[filter.field] const fieldLabel = column?.headerName ?? filter.field - const value = filter.value != null && filter.value !== '' ? ` ${filter.operator} "${filter.value}"` : ` ${filter.operator}` + const value = + filter.value != null && filter.value !== '' + ? ` ${filter.operator} "${filter.value}"` + : ` ${filter.operator}` return ( + - - - - + + + + @@ -77,17 +116,22 @@ function ListPageToolbar() { } type ListPageProps = { - title?: string | null - description?: string | null - columns: any + title?: string + description?: string + columns: GridColDef[] dataGridProps: any + getRowId?: (row: any) => string | number exportProps?: any - children?: any + children?: React.ReactNode onSelectionChange?: (selectionModel: any) => void - getRowId?: (row: any) => number - isLoading?: any + isLoading?: boolean headerButtons?: any disableRowClick?: boolean + + searchMode?: 'client' | 'server' + searchValue?: string + onSearchChange?: (value: string) => void + searchPlaceholder?: string } export const ListPage: React.FC = ({ @@ -102,12 +146,18 @@ export const ListPage: React.FC = ({ isLoading, headerButtons, disableRowClick = false, + searchMode = 'client', + searchValue, + onSearchChange, + searchPlaceholder, }) => { if (!exportProps) { exportProps = { pageSize: 1000 } } - const [quickFilter, setQuickFilter] = useState('') + const [localQuickFilter, setLocalQuickFilter] = useState('') + const quickFilter = + searchMode === 'server' ? (searchValue ?? '') : localQuickFilter const { show } = useNavigation() const { resource } = useResourceParams() @@ -133,16 +183,40 @@ export const ListPage: React.FC = ({ } const rowCount = dataGridProps.rowCount as number | undefined - const { rows: allRows, ...restDataGridProps } = dataGridProps + const getSearchableCellValue = (row: any, col: GridColDef) => { + const raw = row[col.field] + + if (raw == null) return '' + if (Array.isArray(raw)) return raw.map((v) => String(v)).join(', ') + if (typeof raw === 'object') return JSON.stringify(raw) + return String(raw) + } + const filteredRows = useMemo(() => { + if (searchMode === 'server') { + return allRows ?? [] + } + if (!quickFilter || !allRows) return allRows ?? [] - const lower = quickFilter.toLowerCase() + + const needle = quickFilter.toLowerCase().trim() + return allRows.filter((row: any) => - Object.values(row).some((val) => String(val ?? '').toLowerCase().includes(lower)) + columns.some((col) => + getSearchableCellValue(row, col).toLowerCase().includes(needle) + ) ) - }, [allRows, quickFilter]) + }, [allRows, quickFilter, columns, searchMode]) + + const handleSearchChange = (value: string) => { + if (searchMode === 'server') { + onSearchChange?.(value) + } else { + setLocalQuickFilter(value) + } + } return ( @@ -168,7 +242,12 @@ export const ListPage: React.FC = ({ breadcrumb={} wrapperProps={{ elevation: 0, - sx: { backgroundColor: 'background.wrapper', boxShadow: 'none', borderRadius: 1, padding: 0 }, + sx: { + backgroundColor: 'background.wrapper', + boxShadow: 'none', + borderRadius: 1, + padding: 0, + }, }} headerProps={{ sx: { @@ -209,13 +288,25 @@ export const ListPage: React.FC = ({ bgcolor: 'background.paper', }} > - + setQuickFilter(e.target.value)} - placeholder="Filter this page..." + onChange={(e) => handleSearchChange(e.target.value)} + placeholder={ + searchPlaceholder ?? + (searchMode === 'server' + ? 'Search all records...' + : 'Filter this page...') + } sx={{ fontSize: 14, flex: 1 }} - inputProps={{ 'aria-label': 'Filter rows on this page' }} + inputProps={{ + 'aria-label': + searchMode === 'server' + ? 'Search all records' + : 'Filter rows on this page', + }} /> {rowCount !== undefined && rowCount > 0 && ( @@ -245,7 +336,9 @@ export const ListPage: React.FC = ({ ? (params) => show(resource.name, params.id as string | number) : undefined } - loading={isLoading !== undefined ? isLoading : restDataGridProps.loading} + loading={ + isLoading !== undefined ? isLoading : restDataGridProps.loading + } columns={columns} sx={{ cursor: disableRowClick ? 'default' : 'pointer' }} /> diff --git a/src/pages/ocotillo/thing/list.tsx b/src/pages/ocotillo/thing/list.tsx index d179f45a..d846452e 100644 --- a/src/pages/ocotillo/thing/list.tsx +++ b/src/pages/ocotillo/thing/list.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useExport, useGo, useLink } from '@refinedev/core' import { ExportButton, useDataGrid } from '@refinedev/mui' import { GridColDef, GridFilterModel } from '@mui/x-data-grid' @@ -63,12 +63,24 @@ export const WellList: React.FC = () => { captureEvent('feature_used', { feature: 'wells_list' }) }, []) + const [searchInput, setSearchInput] = useState('') + const [search, setSearch] = useState('') + + useEffect(() => { + const timer = setTimeout(() => { + setSearch(searchInput.trim()) + }, 300) + + return () => clearTimeout(timer) + }, [searchInput]) + const { dataGridProps } = useDataGrid({ resource: 'thing/water-well', dataProviderName: 'ocotillo', meta: { params: { include_contacts: true, + ...(search ? { query: search } : {}), }, }, pagination: { pageSize: 50 }, @@ -302,6 +314,9 @@ export const WellList: React.FC = () => { }} getRowId={(row) => row.id} headerButtons={customHeaderButtons} + searchMode="server" + searchValue={searchInput} + onSearchChange={setSearchInput} /> ) } From 916e3833974a93fa438d547105f8476b1292ed68 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 10 Apr 2026 15:01:05 -0500 Subject: [PATCH 05/52] feat(ListPage): Improve UI layout --- src/components/ListPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ListPage.tsx b/src/components/ListPage.tsx index 839a59bd..0bf906de 100644 --- a/src/components/ListPage.tsx +++ b/src/components/ListPage.tsx @@ -270,8 +270,8 @@ export const ListPage: React.FC = ({ display: 'flex', alignItems: 'center', justifyContent: 'space-between', - px: 0.5, - pb: 0.5, + px: 0, + pb: 1.5, }} > = ({ borderRadius: 1, px: 1, py: 0.25, - width: 260, + width: 400, bgcolor: 'background.paper', }} > From 83719c76bf4d984a17ea1cb1c01f889ee2d99d81 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Thu, 16 Apr 2026 11:33:02 -0400 Subject: [PATCH 06/52] Remove FieldEventHistoryAccordion component --- src/components/WellShow/FieldEventHistory.tsx | 108 ------------------ src/components/WellShow/index.ts | 1 - src/pages/ocotillo/thing/well-show.tsx | 2 - src/test/pages/well-show.test.tsx | 1 - 4 files changed, 112 deletions(-) delete mode 100644 src/components/WellShow/FieldEventHistory.tsx diff --git a/src/components/WellShow/FieldEventHistory.tsx b/src/components/WellShow/FieldEventHistory.tsx deleted file mode 100644 index 82d423bc..00000000 --- a/src/components/WellShow/FieldEventHistory.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { Box, Paper, Stack, Typography } from '@mui/material' -import { History } from '@mui/icons-material' -import { ISample } from '@/interfaces/ocotillo' -import { formatAppDateTime } from '@/utils' - -function buildEventContent(sample: Partial | null | undefined): { - date: string | null - body: string -} { - if (!sample) return { date: null, body: '' } - - const eventDate = - sample.field_event?.event_date ?? sample.sample_date ?? null - const activityType = sample.field_activity?.activity_type ?? null - const contactName = sample.contact?.name ?? null - const contactOrg = sample.contact?.organization ?? null - const sampleMethod = sample.sample_method ?? null - const notes = sample.field_event?.notes ?? sample.notes ?? null - - const date = eventDate ? formatAppDateTime(eventDate) : null - - let body = '' - if (activityType) { - const article = activityType.match(/^[aeiou]/i) ? 'An' : 'A' - const staffPart = contactName - ? ` by ${contactName}${contactOrg ? ` (${contactOrg})` : ''}` - : '' - const methodPart = sampleMethod - ? `, using the ${sampleMethod} method` - : '' - body = `${article} ${activityType} check was performed${staffPart}${methodPart}` - } - if (body && !body.endsWith('.')) body += '.' - if (notes) body = body ? `${body} ${notes}` : notes - - if (!date && !body) return { date: null, body: '' } - - return { date, body } -} - -export const FieldEventHistoryAccordion = ({ - sample, -}: { - sample?: Partial | null -}) => { - const { date, body } = buildEventContent(sample) - const hasData = date || body - - return ( - - - - - Field Event History - - - - {!hasData ? ( - - No field event history found. - - ) : ( - - {date && ( - - - Event Date - - - {date} - - - )} - - {body && ( - - - Event Summary - - - {body} - - - )} - - )} - - - ) -} diff --git a/src/components/WellShow/index.ts b/src/components/WellShow/index.ts index cb4005c1..f900547e 100644 --- a/src/components/WellShow/index.ts +++ b/src/components/WellShow/index.ts @@ -6,7 +6,6 @@ export * from './Attachments' export * from './AlternateIds' export * from './Contacts' export * from './Equipment' -export * from './FieldEventHistory' export * from './Notes' export * from './WellScreens' export * from './WellShowTitle' diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index da2a8cfc..9f6d2793 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -36,7 +36,6 @@ import { ConstructionInfoAccordion, GeologyInformationAccordion, WellPhysicalPropertiesAccordion, - FieldEventHistoryAccordion, WellPDFDownloadButton, WellShowTitle, OwnerPermissionsCard, @@ -326,7 +325,6 @@ export const WellShow = () => { - diff --git a/src/test/pages/well-show.test.tsx b/src/test/pages/well-show.test.tsx index d5c03689..9ccfeaa2 100644 --- a/src/test/pages/well-show.test.tsx +++ b/src/test/pages/well-show.test.tsx @@ -59,7 +59,6 @@ vi.mock('@/components', () => { ConstructionInfoAccordion: () => , GeologyInformationAccordion: () => , WellPhysicalPropertiesAccordion: () => , - FieldEventHistoryAccordion: () => , WellPDFDownloadButton: () => , WellShowTitle: () => , OwnerPermissionsCard: () => , From d328cd43809bc42923dbc9381b2353a76785acde Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Thu, 16 Apr 2026 12:28:41 -0400 Subject: [PATCH 07/52] update types --- src/generated/types.gen.ts | 89 +++++++++++++++++++++++++++++++++----- src/generated/zod.gen.ts | 83 +++++++++++++++++++++++++++++------ 2 files changed, 149 insertions(+), 23 deletions(-) diff --git a/src/generated/types.gen.ts b/src/generated/types.gen.ts index 3657255e..2b2ebd71 100644 --- a/src/generated/types.gen.ts +++ b/src/generated/types.gen.ts @@ -1002,6 +1002,34 @@ export type FieldActivityResponse = { activity_type: ActivityType; }; +/** + * FieldEventParticipantResponse + */ +export type FieldEventParticipantResponse = { + /** + * Id + */ + id: number; + /** + * Created At + */ + created_at: string; + release_status: ReleaseStatus; + /** + * Field Event Id + */ + field_event_id: number; + /** + * Contact Id + */ + contact_id: number; + /** + * Participant Role + */ + participant_role: string; + participant: ContactResponse; +}; + /** * FieldEventResponse */ @@ -1285,6 +1313,7 @@ export type LocationGeoJsonResponse = { * Type */ type?: string; + release_status: ReleaseStatus; geometry: SchemasLocationGeoJsonGeometry; properties: GeoJsonProperties; }; @@ -2288,6 +2317,10 @@ export type SpringResponse = { * Name */ name: string; + /** + * Site Name + */ + site_name?: string | null; /** * Thing Type */ @@ -2376,6 +2409,10 @@ export type ThingResponse = { * Name */ name: string; + /** + * Site Name + */ + site_name?: string | null; /** * Thing Type */ @@ -2433,6 +2470,10 @@ export type ThingResponse = { * Well Depth Source */ well_depth_source: string | null; + /** + * Historic Depth To Water + */ + historic_depth_to_water?: Array; /** * Hole Depth */ @@ -2494,7 +2535,7 @@ export type ThingResponse = { /** * Open Status */ - open_status: string | null; + open_status: boolean | null; /** * Datalogger Suitability Status */ @@ -2538,6 +2579,10 @@ export type ThingResponse = { * Nma Formation Zone */ nma_formation_zone: string | null; + /** + * Well Location Note + */ + well_location_note?: Array; }; /** @@ -3310,6 +3355,10 @@ export type WellDetailsResponse = { */ recent_groundwater_level_observations?: Array; latest_field_event_sample?: SampleResponse | null; + /** + * Field Event Participants + */ + field_event_participants?: Array; }; /** @@ -3350,6 +3399,10 @@ export type WellResponse = { * Name */ name: string; + /** + * Site Name + */ + site_name?: string | null; /** * Thing Type */ @@ -3403,6 +3456,10 @@ export type WellResponse = { * Well Depth Source */ well_depth_source: string | null; + /** + * Historic Depth To Water + */ + historic_depth_to_water?: Array; /** * Hole Depth */ @@ -3464,7 +3521,7 @@ export type WellResponse = { /** * Open Status */ - open_status: string | null; + open_status: boolean | null; /** * Datalogger Suitability Status */ @@ -3508,6 +3565,10 @@ export type WellResponse = { * Nma Formation Zone */ nma_formation_zone: string | null; + /** + * Well Location Note + */ + well_location_note?: Array; }; /** @@ -6568,11 +6629,11 @@ export type GetWaterWellsThingWaterWellGetData = { /** * Sort */ - sort?: string; + sort?: string | null; /** * Order */ - order?: string; + order?: string | null; /** * Filter */ @@ -6580,11 +6641,15 @@ export type GetWaterWellsThingWaterWellGetData = { /** * Query */ - query?: string; + query?: string | null; /** * Name */ - name?: string; + name?: string | null; + /** + * Include Contacts + */ + include_contacts?: boolean; /** * Page * @@ -7205,19 +7270,23 @@ export type GetThingsThingGetData = { /** * Within */ - within?: string; + within?: string | null; /** * Query */ - query?: string; + query?: string | null; /** * Sort */ - sort?: string; + sort?: string | null; /** * Order */ - order?: string; + order?: string | null; + /** + * Include Contacts + */ + include_contacts?: boolean; /** * Filter */ diff --git a/src/generated/zod.gen.ts b/src/generated/zod.gen.ts index d4b87bbe..66c697c8 100644 --- a/src/generated/zod.gen.ts +++ b/src/generated/zod.gen.ts @@ -1486,6 +1486,19 @@ export const zFieldActivityResponse = z.object({ activity_type: zActivityType }); +/** + * FieldEventParticipantResponse + */ +export const zFieldEventParticipantResponse = z.object({ + id: z.int(), + created_at: z.string(), + release_status: zReleaseStatus, + field_event_id: z.int(), + contact_id: z.int(), + participant_role: z.string(), + participant: zContactResponse +}); + /** * FieldEventResponse */ @@ -1889,6 +1902,7 @@ export const zSchemasLocationGeoJsonGeometry = z.object({ */ export const zLocationGeoJsonResponse = z.object({ type: z.optional(z.string()).default('Feature'), + release_status: zReleaseStatus, geometry: zSchemasLocationGeoJsonGeometry, properties: zGeoJsonProperties }); @@ -2503,6 +2517,10 @@ export const zThingResponse = z.object({ created_at: z.string(), release_status: zReleaseStatus, name: z.string(), + site_name: z.optional(z.union([ + z.string(), + z.null() + ])), thing_type: z.string(), current_location: zLocationGeoJsonResponse, first_visit_date: z.union([ @@ -2533,6 +2551,7 @@ export const zThingResponse = z.object({ z.string(), z.null() ]), + historic_depth_to_water: z.optional(z.array(z.string())).default([]), hole_depth: z.optional(z.union([ z.number(), z.null() @@ -2583,7 +2602,7 @@ export const zThingResponse = z.object({ z.null() ]), open_status: z.union([ - z.string(), + z.boolean(), z.null() ]), datalogger_suitability_status: z.union([ @@ -2611,7 +2630,8 @@ export const zThingResponse = z.object({ nma_formation_zone: z.union([ z.string(), z.null() - ]) + ]), + well_location_note: z.optional(z.array(z.string())).default([]) }); /** @@ -2686,6 +2706,10 @@ export const zSpringResponse = z.object({ created_at: z.string(), release_status: zReleaseStatus, name: z.string(), + site_name: z.optional(z.union([ + z.string(), + z.null() + ])), thing_type: z.string(), current_location: zLocationGeoJsonResponse, first_visit_date: z.union([ @@ -2846,6 +2870,10 @@ export const zWellResponse = z.object({ created_at: z.string(), release_status: zReleaseStatus, name: z.string(), + site_name: z.optional(z.union([ + z.string(), + z.null() + ])), thing_type: z.string(), current_location: zLocationGeoJsonResponse, first_visit_date: z.union([ @@ -2872,6 +2900,7 @@ export const zWellResponse = z.object({ z.string(), z.null() ]), + historic_depth_to_water: z.optional(z.array(z.string())).default([]), hole_depth: z.optional(z.union([ z.number(), z.null() @@ -2922,7 +2951,7 @@ export const zWellResponse = z.object({ z.null() ]), open_status: z.union([ - z.string(), + z.boolean(), z.null() ]), datalogger_suitability_status: z.union([ @@ -2950,7 +2979,8 @@ export const zWellResponse = z.object({ nma_formation_zone: z.union([ z.string(), z.null() - ]) + ]), + well_location_note: z.optional(z.array(z.string())).default([]) }); /** @@ -3714,7 +3744,8 @@ export const zWellDetailsResponse = z.object({ latest_field_event_sample: z.optional(z.union([ zSampleResponse, z.null() - ])) + ])), + field_event_participants: z.optional(z.array(zFieldEventParticipantResponse)) }); /** @@ -4948,11 +4979,24 @@ export const zGetWaterWellsThingWaterWellGetData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - sort: z.optional(z.string()), - order: z.optional(z.string()), + sort: z.optional(z.union([ + z.string(), + z.null() + ])), + order: z.optional(z.union([ + z.string(), + z.null() + ])), filter: z.optional(z.string()), - query: z.optional(z.string()), - name: z.optional(z.string()), + query: z.optional(z.union([ + z.string(), + z.null() + ])), + name: z.optional(z.union([ + z.string(), + z.null() + ])), + include_contacts: z.optional(z.boolean()).default(false), page: z.optional(z.int().gte(1)).default(1), size: z.optional(z.int().gte(1).lte(10000)).default(25) })) @@ -5207,10 +5251,23 @@ export const zGetThingsThingGetData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - within: z.optional(z.string()), - query: z.optional(z.string()), - sort: z.optional(z.string()), - order: z.optional(z.string()), + within: z.optional(z.union([ + z.string(), + z.null() + ])), + query: z.optional(z.union([ + z.string(), + z.null() + ])), + sort: z.optional(z.union([ + z.string(), + z.null() + ])), + order: z.optional(z.union([ + z.string(), + z.null() + ])), + include_contacts: z.optional(z.boolean()).default(false), filter: z.optional(z.string()), page: z.optional(z.int().gte(1)).default(1), size: z.optional(z.int().gte(1).lte(10000)).default(25) From 1bc1dc884a70f51939d4451226f1e4976e80aa24 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Thu, 16 Apr 2026 12:54:10 -0400 Subject: [PATCH 08/52] Move elevation info from Core Well Information to Physical Properties --- .../WellShow/WellPhysicalProperties.tsx | 31 ++++++++++++++ src/components/card/CoreWellInfo.tsx | 40 ++----------------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 2a460f4e..8073eebe 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -2,6 +2,11 @@ import { Box, Paper, Stack, Typography } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { + const elevation = well?.current_location?.properties?.elevation + const elevationUnit = well?.current_location?.properties?.elevation_unit + const elevationMethod = well?.current_location?.properties?.elevation_method + const verticalDatum = well?.current_location?.properties?.vertical_datum + return ( @@ -58,6 +63,32 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { {well?.well_pump_depth ? ` ${well?.well_pump_depth_unit}` : null} + + + Elevation: + + + {elevation != null + ? `${elevation.toFixed(2)}${elevationUnit ? ` ${elevationUnit}` : ''}` + : 'N/A'} + + + + + Elevation Method: + + + {elevationMethod || 'N/A'} + + + + + Vertical Datum: + + + {verticalDatum || 'N/A'} + + diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index 12e85316..30567192 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -55,7 +55,7 @@ export const CoreWellInfoCard = ({ well }: { well: IWell }) => { } /> - +
{ />
- +
{ />
- -
- - - -
-
@@ -269,21 +242,16 @@ const LoadingCard = () => ( } /> - +
- +
- -
- -
-
From b5402180f665c40e0ec487a416706802fbbaa67a Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Thu, 16 Apr 2026 15:39:51 -0400 Subject: [PATCH 09/52] Reorganize well detail page cards and standardize inline text layout - Move location info from CoreWellInfo to InteractiveSatelliteMap (renamed to Location) - Move elevation info from CoreWellInfo and WellSummaryBar to Physical Properties - Convert CoreWellInfo to compact 3-column stat bar (Hole Depth, Well Depth, Measuring Point) - Standardize ConstructionInfo, PhysicalProperties, and GeologyInformation to inline text style - Add site_name to IWell and surface it as Contacts card heading --- src/components/WellShow/ConstructionInfo.tsx | 104 +++--- src/components/WellShow/Contacts.tsx | 4 +- .../WellShow/GeologyInformation.tsx | 65 ++-- .../WellShow/WellPhysicalProperties.tsx | 120 +++---- src/components/card/CoreWellInfo.tsx | 311 ++++-------------- .../card/InteractiveSatelliteMap.tsx | 76 ++++- src/interfaces/ocotillo/IWell.ts | 2 + src/pages/ocotillo/thing/well-show.tsx | 2 +- 8 files changed, 266 insertions(+), 418 deletions(-) diff --git a/src/components/WellShow/ConstructionInfo.tsx b/src/components/WellShow/ConstructionInfo.tsx index df2200c7..7b44415a 100644 --- a/src/components/WellShow/ConstructionInfo.tsx +++ b/src/components/WellShow/ConstructionInfo.tsx @@ -11,82 +11,56 @@ export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => { - -
- - -
- -
- + + + + - + {well.well_completion_date_source} + + )} + + + -
+ {well?.well_construction_method_source && ( + + {well.well_construction_method_source} + + )} +
) } -const Section = ({ children }: { children: React.ReactNode }) => ( - - {children} - -) - -const FieldRow = ({ label, value }: { label: string; value: string }) => ( - - - {label} +const InlineRow = ({ label, value }: { label: string; value: string }) => ( + + {label}:{' '} + + {value} - {value} - -) - -const FieldGroup = ({ - label, - value, - metaValue, -}: { - label: string - value: string - metaValue: string -}) => ( - - - - - {metaValue} - - - + ) diff --git a/src/components/WellShow/Contacts.tsx b/src/components/WellShow/Contacts.tsx index b7f01da7..0b6db83a 100644 --- a/src/components/WellShow/Contacts.tsx +++ b/src/components/WellShow/Contacts.tsx @@ -114,15 +114,17 @@ const ContactBlock = ({ contact }: { contact: IContact }) => { export const ContactsCard = ({ contacts, isLoading, + siteName, }: { contacts: IContact[] isLoading: boolean + siteName?: string | null }) => { return ( - Contacts + {siteName || 'Contacts'} diff --git a/src/components/WellShow/GeologyInformation.tsx b/src/components/WellShow/GeologyInformation.tsx index c21e9200..4e930370 100644 --- a/src/components/WellShow/GeologyInformation.tsx +++ b/src/components/WellShow/GeologyInformation.tsx @@ -1,4 +1,4 @@ -import { Box, Paper, Stack, Typography } from '@mui/material' +import { Paper, Box, Stack, Typography } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' export const GeologyInformationAccordion = ({ well }: { well?: IWell }) => { @@ -10,40 +10,39 @@ export const GeologyInformationAccordion = ({ well }: { well?: IWell }) => { - - - - Formation Completion Code: - - - {well?.formation_completion_code || 'N/A'} - - - - - Aquifer Systems: - - - {(well?.aquifers ?? []) - ?.map((a) => a?.aquifer_system) - ?.filter(Boolean) - ?.join(', ') || 'N/A'} - - - - - Aquifer Types: - - - {well?.aquifers && well.aquifers.length > 0 - ? [ - ...new Set(well.aquifers.flatMap((a) => a.aquifer_types)), - ].join(', ') - : 'N/A'} - - + + + a?.aquifer_system) + .filter(Boolean) + .join(', ') || 'N/A' + } + /> + 0 + ? [...new Set(well.aquifers.flatMap((a) => a.aquifer_types))].join(', ') + : 'N/A' + } + /> ) } + +const InlineRow = ({ label, value }: { label: string; value: string }) => ( + + {label}:{' '} + + {value} + + +) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 8073eebe..a65ef3ba 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -1,4 +1,4 @@ -import { Box, Paper, Stack, Typography } from '@mui/material' +import { Paper, Box, Stack, Typography } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { @@ -15,82 +15,50 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { - - - - Casing Diameter: - - - {well?.well_casing_diameter?.toFixed(2) || 'N/A'} - {well?.well_casing_diameter - ? ` ${well?.well_casing_diameter_unit}` - : null} - - - - - Casing Depth: - - - {well?.well_casing_depth?.toFixed(2) || 'N/A'} - {well?.well_casing_depth - ? ` ${well?.well_casing_depth_unit}` - : null} - - - - - Casing Materials: - - - {well?.well_casing_materials?.join(', ') || 'N/A'} - - - - - Pump Type: - - - {well?.well_pump_type || 'N/A'} - - - - - Pump Depth: - - - {well?.well_pump_depth?.toFixed(2) || 'N/A'} - {well?.well_pump_depth ? ` ${well?.well_pump_depth_unit}` : null} - - - - - Elevation: - - - {elevation != null - ? `${elevation.toFixed(2)}${elevationUnit ? ` ${elevationUnit}` : ''}` - : 'N/A'} - - - - - Elevation Method: - - - {elevationMethod || 'N/A'} - - - - - Vertical Datum: - - - {verticalDatum || 'N/A'} - - - + + + + + + + + + + ) } + +const InlineRow = ({ label, value }: { label: string; value: string }) => ( + + {label}:{' '} + + {value} + + +) diff --git a/src/components/card/CoreWellInfo.tsx b/src/components/card/CoreWellInfo.tsx index 30567192..a7f8a441 100644 --- a/src/components/card/CoreWellInfo.tsx +++ b/src/components/card/CoreWellInfo.tsx @@ -1,258 +1,89 @@ -import { - Box, - Card, - CardContent, - CardHeader, - IconButton, - Skeleton, - Stack, - Tooltip, - Typography, -} from '@mui/material' -import Grid from '@mui/material/Grid2' +import { Box, Paper, Skeleton, Typography } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' -import { ContentCopy, Directions, Info } from '@mui/icons-material' -import { CardHeaderTitle } from '@/components' -const HeaderTitle = () => ( - } - title="Core Well Information" - /> -) - -export const CoreWellInfoCard = ({ well }: { well: IWell }) => { +export const CoreWellInfoCard = ({ well }: { well?: IWell }) => { if (!well) { - return + return } - const coords = well?.current_location?.geometry?.coordinates as - | [number, number, number?] - | undefined - - const [lon, lat] = coords ?? [] - - const { easting, northing } = well?.current_location?.properties - ?.utm_coordinates ?? { easting: null, northing: null } - const latLonValue = - well?.current_location?.geometry && lat != null && lon != null - ? `${lat.toFixed(6)}, ${lon.toFixed(6)}` - : 'N/A' - const utmValue = - easting != null && northing != null - ? `${easting.toFixed(0)}, ${northing.toFixed(0)}` - : 'N/A' - const googleMapsUrl = - lat != null && lon != null - ? `https://www.google.com/maps/dir/?api=1&destination=${lat},${lon}` - : null + const stats: { label: string; value: string }[] = [ + { + label: 'Hole Depth', + value: well?.hole_depth + ? `${well.hole_depth} ${well.hole_depth_unit ?? ''}`.trim() + : 'N/A', + }, + { + label: 'Well Depth', + value: well?.well_depth + ? `${well.well_depth} ${well.well_depth_unit ?? ''}`.trim() + : 'N/A', + }, + { + label: 'Measuring Point', + value: + [ + well?.measuring_point_description || null, + well?.measuring_point_height + ? `${well.measuring_point_height} ${well.measuring_point_height_unit ?? ''}`.trim() + : null, + ] + .filter(Boolean) + .join(' | ') || 'N/A', + }, + ] return ( - - } /> - - - -
- - - -
-
- -
- - - - - ) : null - } + + + {stats.map((stat, i) => ( + 0 ? '1px solid' : 'none', + borderColor: 'divider', + }} + > + + {stat.label} + + - - - note.note_type === 'Coordinate') - .map((note) => note.content) - .filter(Boolean) - .join('\n') || 'N/A' - } - /> -
-
-
-
-
+ {stat.value} + + + ))} + + ) } -const Section = ({ - title, - children, - action, -}: { - title: string - children: React.ReactNode - action?: React.ReactNode -}) => ( - - - - {title} - - - {action} - - - {children} - -) - -const InfoRow = ({ - label, - value, - copyValue, -}: { - label: string - value: string - copyValue?: string -}) => { - const handleCopy = async () => { - if (!copyValue) return - - try { - await navigator.clipboard.writeText(copyValue) - } catch (error) { - console.error(`Failed to copy ${label}`, error) - } - } - - return ( - - - {label} - - - {value} +const LoadingBar = () => ( + + + {Array.from({ length: 3 }).map((_, i) => ( 0 ? '1px solid' : 'none', + borderColor: 'divider', }} > - {copyValue && ( - - - - - - )} + + - + ))} - ) -} - -const LoadingCard = () => ( - - } /> - - - -
- -
-
- -
- -
-
-
-
-
+ ) diff --git a/src/components/card/InteractiveSatelliteMap.tsx b/src/components/card/InteractiveSatelliteMap.tsx index ac54ff68..60609ded 100644 --- a/src/components/card/InteractiveSatelliteMap.tsx +++ b/src/components/card/InteractiveSatelliteMap.tsx @@ -6,10 +6,13 @@ import { Card, CardContent, CardHeader, + IconButton, Skeleton, + Stack, + Tooltip, Typography, } from '@mui/material' -import { Directions, Map } from '@mui/icons-material' +import { ContentCopy, Directions, Map } from '@mui/icons-material' import { Layer, MapRef, Source } from 'react-map-gl' import { MapComponent, MapPopup, CardHeaderTitle } from '@/components' import { useLayer } from '@/hooks' @@ -20,7 +23,7 @@ const MAP_HEIGHT = 450 const HeaderTitle = () => ( } - title="Interactive Satellite Map" + title="Location" /> ) @@ -46,6 +49,23 @@ export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { const [lon, lat, _elevation] = coords ?? [] + const { easting, northing } = well?.current_location?.properties + ?.utm_coordinates ?? { easting: null, northing: null } + const latLonValue = + lat != null && lon != null + ? `${lat.toFixed(6)}, ${lon.toFixed(6)}` + : 'N/A' + const utmValue = + easting != null && northing != null + ? `${easting.toFixed(0)}, ${northing.toFixed(0)}` + : 'N/A' + const coordinateNotes = + well?.current_location?.properties?.notes + ?.filter((note) => note.note_type === 'Coordinate') + .map((note) => note.content) + .filter(Boolean) + .join('\n') || null + useEffect(() => { const timer = window.setTimeout(() => setLoadNearbyWells(true), 0) return () => window.clearTimeout(timer) @@ -239,11 +259,63 @@ export const InteractiveSatelliteMapCard = ({ well }: { well: IWell }) => { )} + + + + {coordinateNotes && ( + + )} + ) } +const CoordRow = ({ + label, + value, + copyValue, +}: { + label: string + value: string + copyValue?: string +}) => { + const handleCopy = async () => { + if (!copyValue) return + try { + await navigator.clipboard.writeText(copyValue) + } catch (error) { + console.error(`Failed to copy ${label}`, error) + } + } + + return ( + + + {label}: + + + {value} + + {copyValue && ( + + + + + + )} + + ) +} + const LoadingCard = () => { return ( [] | null + + site_name?: string | null } diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 9f6d2793..dd222aab 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -320,7 +320,7 @@ export const WellShow = () => { {/* Right column: 2 cols */} - + From ddd15e21318e1fa839146d7c335346d8be0f70e4 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Mon, 20 Apr 2026 12:30:47 -0400 Subject: [PATCH 10/52] update bug reporting copy --- public/content/report-a-bug.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/content/report-a-bug.md b/public/content/report-a-bug.md index 08c74f43..ab2f2837 100644 --- a/public/content/report-a-bug.md +++ b/public/content/report-a-bug.md @@ -5,7 +5,7 @@ deck: Found something broken or have a suggestion? Let us know. ## How to report an issue -If you've encountered an error, unexpected behavior, or have a suggestion for improvement, please submit an issue through one of the channels below. +If you've encountered an error, unexpected behavior, or have a suggestion for improvement, we want to know about it! Your feedback is essential to help us improve Ocotillo. Please email us with bug reports or feature requests at [ocotillo-nmbg@nmt.edu](mailto:ocotillo-nmbg@nmt.edu). ## What to include @@ -15,8 +15,8 @@ A good bug report includes: - **What actually happened** - **Steps to reproduce** -- the more specific the better - **Browser and operating system** (e.g. Chrome on macOS) -- **Screenshots** if the issue is visual +- **Screenshots are extremely helpful** if the issue is visual ## Contact -For urgent issues or questions, reach out directly to the development team at [newmexicowaterdata@nmt.edu](mailto:newmexicowaterdata@nmt.edu). \ No newline at end of file +For urgent issues or questions, reach out directly to the development team at [newmexicowaterdata@nmt.edu](mailto:ocotillo-nmbg@nmt.edu). \ No newline at end of file From ab159557a86665af0a0a6bb52493b4aa794528bf Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Mon, 20 Apr 2026 16:58:02 -0400 Subject: [PATCH 11/52] Update well details to use field_events API response shape - Update IWellDetails to replace removed fields with field_events list - Expand IFieldEvent with nested field_event_participants and contact types - Derive first visit participants from oldest field event (last in desc-sorted list) - Wire firstVisitParticipants into MonitoringInfoCard as First Visit Staff - Resolve merge conflict in well-show.tsx --- src/components/WellShow/MonitoringInfo.tsx | 165 +++++++++++++++++++++ src/components/WellShow/index.ts | 1 + src/interfaces/ocotillo/IFieldEvent.ts | 19 +++ src/interfaces/ocotillo/IWellDetails.ts | 6 +- src/pages/ocotillo/thing/well-show.tsx | 22 ++- 5 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 src/components/WellShow/MonitoringInfo.tsx diff --git a/src/components/WellShow/MonitoringInfo.tsx b/src/components/WellShow/MonitoringInfo.tsx new file mode 100644 index 00000000..a42480e2 --- /dev/null +++ b/src/components/WellShow/MonitoringInfo.tsx @@ -0,0 +1,165 @@ +import { Chip, Divider, Paper, Box, Skeleton, Stack, Typography } from '@mui/material' +import { IWell } from '@/interfaces/ocotillo' +import { IFieldEventParticipant } from '@/interfaces/ocotillo/IFieldEvent' +import { formatAppDate } from '@/utils' + +function getMeasuringDuration(firstVisitDate: string | null | undefined): string { + if (!firstVisitDate) return 'N/A' + const start = new Date(firstVisitDate) + const now = new Date() + const totalMonths = + (now.getFullYear() - start.getFullYear()) * 12 + + (now.getMonth() - start.getMonth()) + if (totalMonths <= 0) return 'Less than a month' + const years = Math.floor(totalMonths / 12) + const months = totalMonths % 12 + if (years === 0) return `${months} month${months !== 1 ? 's' : ''}` + if (months === 0) return `${years} year${years !== 1 ? 's' : ''}` + return `${years} year${years !== 1 ? 's' : ''}, ${months} month${months !== 1 ? 's' : ''}` +} + +export const MonitoringInfoCard = ({ + well, + firstVisitParticipants, + isLoading, +}: { + well?: IWell + firstVisitParticipants?: IFieldEventParticipant[] + isLoading?: boolean +}) => { + if (isLoading) { + return ( + + + + Monitoring Info + + + + + {[...Array(5)].map((_, i) => ( + + ))} + + + + ) + } + + const firstVisitDate = well?.first_visit_date + const duration = getMeasuringDuration(firstVisitDate) + + const hasParticipants = firstVisitParticipants && firstVisitParticipants.length > 0 + + const monitoringFrequencies = well?.monitoring_frequencies ?? [] + const activeFrequencies = monitoringFrequencies.filter((f) => !f.end_date) + const historicalFrequencies = monitoringFrequencies.filter((f) => f.end_date) + + return ( + + + + Monitoring Info + + + + + + + + + + + + + + 0 ? 0.75 : 0 }}> + Monitoring Frequency:{' '} + {monitoringFrequencies.length === 0 && ( + + N/A + + )} + + {monitoringFrequencies.length > 0 && ( + + {activeFrequencies.map((f, i) => ( + + ))} + {historicalFrequencies.map((f, i) => ( + + ))} + + )} + + + + + + + First Visit Staff:{' '} + {!hasParticipants && ( + + N/A + + )} + + {hasParticipants && ( + + {firstVisitParticipants!.map((p) => ( + + {p.participant?.contact_name || 'Unknown'} + {p.participant_role && ( + + {' '}({p.participant_role}) + + )} + + ))} + + )} + + + + + ) +} + +const FieldRow = ({ label, value }: { label: string; value: string }) => ( + + {label}:{' '} + + {value} + + +) + +const FrequencyRow = ({ + freq, + active, +}: { + freq: { monitoring_frequency: string; start_date: string; end_date: string | null } + active: boolean +}) => ( + + {active && ( + + )} + {freq.monitoring_frequency}{' '} + + {formatAppDate(freq.start_date)} + {freq.end_date ? ` - ${formatAppDate(freq.end_date)}` : ''} + + +) diff --git a/src/components/WellShow/index.ts b/src/components/WellShow/index.ts index f900547e..b96fd8a1 100644 --- a/src/components/WellShow/index.ts +++ b/src/components/WellShow/index.ts @@ -1,4 +1,5 @@ export * from './ConstructionInfo' +export * from './MonitoringInfo' export * from './GeologyInformation' export * from './OwnerPermissions' export * from './WellPhysicalProperties' diff --git a/src/interfaces/ocotillo/IFieldEvent.ts b/src/interfaces/ocotillo/IFieldEvent.ts index 4602328d..1d542511 100644 --- a/src/interfaces/ocotillo/IFieldEvent.ts +++ b/src/interfaces/ocotillo/IFieldEvent.ts @@ -1,3 +1,21 @@ +export interface IFieldEventParticipantContact { + id: number + created_at?: string + release_status?: string + contact_name?: string | null + contact_organization?: string | null +} + +export interface IFieldEventParticipant { + id: number + created_at?: string + release_status?: string + field_event_id: number + contact_id: number + participant_role: string + participant?: IFieldEventParticipantContact +} + export interface IFieldEvent { id: number created_at?: string @@ -5,4 +23,5 @@ export interface IFieldEvent { thing_id: number event_date?: string notes?: string | null + field_event_participants?: IFieldEventParticipant[] } diff --git a/src/interfaces/ocotillo/IWellDetails.ts b/src/interfaces/ocotillo/IWellDetails.ts index 21f5d832..ea8a8340 100644 --- a/src/interfaces/ocotillo/IWellDetails.ts +++ b/src/interfaces/ocotillo/IWellDetails.ts @@ -1,6 +1,5 @@ import type { IContact } from './IContact' -import type { IObservation } from './IObservation' -import type { ISample } from './ISample' +import type { IFieldEvent } from './IFieldEvent' import type { ISensor } from './ISensor' import type { IWell } from './IWell' import type { IWellScreen } from './IWellScreen' @@ -11,6 +10,5 @@ export type IWellDetails = { sensors: ISensor[] deployments: any[] well_screens: IWellScreen[] - recent_groundwater_level_observations: IObservation[] - latest_field_event_sample: ISample | null + field_events: IFieldEvent[] } diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index dd222aab..67af852a 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -10,7 +10,6 @@ import { IContact, IWellDetails, IObservation, - ISample, ISensor, IWell, IWellScreen, @@ -39,6 +38,7 @@ import { WellPDFDownloadButton, WellShowTitle, OwnerPermissionsCard, + MonitoringInfoCard, } from '@/components' export const WellShow = () => { @@ -90,14 +90,17 @@ export const WellShow = () => { document.title = prev } }, [well?.name]) - const observations = - detailsQuery.data?.recent_groundwater_level_observations ?? [] const assets = assetResult?.data ?? [] const contacts = detailsQuery.data?.contacts ?? [] const sensors = detailsQuery.data?.sensors ?? [] const deployments = detailsQuery.data?.deployments ?? [] const wellScreens = detailsQuery.data?.well_screens ?? [] - const fieldEventSample = detailsQuery.data?.latest_field_event_sample ?? null + const fieldEvents = detailsQuery.data?.field_events ?? [] + // field_events are sorted newest-first; last entry is the earliest visit + const firstVisitParticipants = + fieldEvents.length > 0 + ? (fieldEvents[fieldEvents.length - 1].field_event_participants ?? []) + : [] const sensorDeployments = useSensorDeploymentRows({ deployments, @@ -269,10 +272,10 @@ export const WellShow = () => {
@@ -294,7 +297,7 @@ export const WellShow = () => { /> @@ -321,6 +324,11 @@ export const WellShow = () => { + From 2e9bb91d18e0a5678dfc7d2047d968529415e08d Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 11:44:44 -0400 Subject: [PATCH 12/52] Wire RecentWaterLevelObservationsCard and WellPDFDownloadButton to field_events data Add nested sample/observation types to IFieldActivity and field_activities to IFieldEvent. Derive recentObservations (flattened from all field_events) and latestSample (from newest field event) in well-show, replacing the empty placeholder props previously passed to both components. --- src/interfaces/ocotillo/IFieldActivity.ts | 35 +++++++++++++++++++++++ src/interfaces/ocotillo/IFieldEvent.ts | 3 ++ src/pages/ocotillo/thing/well-show.tsx | 27 +++++++++++++++-- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/interfaces/ocotillo/IFieldActivity.ts b/src/interfaces/ocotillo/IFieldActivity.ts index 669f5a5f..fd0ace58 100644 --- a/src/interfaces/ocotillo/IFieldActivity.ts +++ b/src/interfaces/ocotillo/IFieldActivity.ts @@ -1,7 +1,42 @@ +export interface IFieldActivitySampleObservation { + id: number + created_at?: string + release_status?: string + sample_id?: number + sensor_id?: number | null + observation_datetime?: string + observed_property?: string + value?: number | null + unit?: string + depth_to_water_bgs?: number | null + measuring_point_height?: number | null + level_status?: string | null + groundwater_level_reason?: string | null + nma_data_quality?: string | null +} + +export interface IFieldActivitySample { + id: number + created_at?: string + release_status?: string + sample_date?: string + sample_name?: string + sampler_name?: string | null + sample_matrix?: string | null + sample_method?: string | null + qc_type?: string + notes?: string | null + depth_top?: number | null + depth_bottom?: number | null + observations?: IFieldActivitySampleObservation[] +} + export interface IFieldActivity { id: number created_at?: string release_status?: string field_event_id: number activity_type?: string + notes?: string | null + samples?: IFieldActivitySample[] } diff --git a/src/interfaces/ocotillo/IFieldEvent.ts b/src/interfaces/ocotillo/IFieldEvent.ts index 1d542511..b0d500ce 100644 --- a/src/interfaces/ocotillo/IFieldEvent.ts +++ b/src/interfaces/ocotillo/IFieldEvent.ts @@ -16,6 +16,8 @@ export interface IFieldEventParticipant { participant?: IFieldEventParticipantContact } +import type { IFieldActivity } from './IFieldActivity' + export interface IFieldEvent { id: number created_at?: string @@ -24,4 +26,5 @@ export interface IFieldEvent { event_date?: string notes?: string | null field_event_participants?: IFieldEventParticipant[] + field_activities?: IFieldActivity[] } diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 67af852a..b68c9946 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -10,6 +10,7 @@ import { IContact, IWellDetails, IObservation, + ISample, ISensor, IWell, IWellScreen, @@ -102,6 +103,26 @@ export const WellShow = () => { ? (fieldEvents[fieldEvents.length - 1].field_event_participants ?? []) : [] + const recentObservations = useMemo(() => { + return fieldEvents + .flatMap((event) => event.field_activities ?? []) + .flatMap((activity) => activity.samples ?? []) + .flatMap((sample) => sample.observations ?? []) + .filter((obs) => obs.observation_datetime != null) + .sort((a, b) => { + const dateA = new Date(a.observation_datetime!).getTime() + const dateB = new Date(b.observation_datetime!).getTime() + return dateB - dateA + }) + }, [fieldEvents]) + + const latestSample = useMemo(() => { + const newestEvent = fieldEvents[0] + if (!newestEvent) return undefined + const firstActivity = newestEvent.field_activities?.[0] + return firstActivity?.samples?.[0] ?? undefined + }, [fieldEvents]) + const sensorDeployments = useSensorDeploymentRows({ deployments, sensors, @@ -272,10 +293,10 @@ export const WellShow = () => { []} assets={assets} contacts={contacts} - sample={null} + sample={latestSample as Partial | undefined} sensorDeployments={sensorDeployments} /> @@ -297,7 +318,7 @@ export const WellShow = () => { /> From 1d10c1f9e5088dac86ae7aaa74af30b128c7c761 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 14 Apr 2026 11:02:39 -0500 Subject: [PATCH 13/52] chore(well-show): Rm unused import & clean up code fmt --- .../WellShow/WellPhysicalProperties.tsx | 16 +++++++--------- src/pages/ocotillo/thing/well-show.tsx | 15 +++------------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index a65ef3ba..55488cab 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -28,26 +28,24 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { label="Casing Materials" value={well?.well_casing_materials?.join(', ') || 'N/A'} /> - + - + diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index dd222aab..f4ea61a5 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -5,16 +5,7 @@ import { useQuery } from '@tanstack/react-query' import { Show, useDataGrid } from '@refinedev/mui' import { AppBreadcrumb } from '@/components/AppBreadcrumb' import { TransducerObservationWithBlockResponse } from '@/generated/types.gen' -import { - IAsset, - IContact, - IWellDetails, - IObservation, - ISample, - ISensor, - IWell, - IWellScreen, -} from '@/interfaces/ocotillo' +import { IAsset, IWellDetails, IObservation } from '@/interfaces/ocotillo' import { Box, Stack } from '@mui/material' import { IHydrographDatasource } from '@/interfaces/st2' import { useAccessCapabilities, useSensorDeploymentRows } from '@/hooks' @@ -51,10 +42,10 @@ export const WellShow = () => { const { id } = useResourceParams() useEffect(() => { - if (id) captureEvent('feature_used', { feature: 'well_detail', well_id: id }) + if (id) + captureEvent('feature_used', { feature: 'well_detail', well_id: id }) }, [id]) - const detailsQuery = useQuery({ queryKey: ['well-details', id], enabled: Boolean(id), From e0aa85726f83dec3a398ba1d0a80b99b2b639408 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 12:11:58 -0400 Subject: [PATCH 14/52] Fix first visit staff using first_field_event API field The paged field_events list (25 newest) does not include the oldest visit for wells with many field events. Consume the new first_field_event field returned by the API to reliably source first-visit participants regardless of history length. Also fixes participant contact name rendering: the API returns name/organization on ContactResponse, not contact_name/contact_organization. --- src/components/WellShow/MonitoringInfo.tsx | 2 +- src/interfaces/ocotillo/IFieldEvent.ts | 4 ++-- src/interfaces/ocotillo/IWellDetails.ts | 1 + src/pages/ocotillo/thing/well-show.tsx | 7 +++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/WellShow/MonitoringInfo.tsx b/src/components/WellShow/MonitoringInfo.tsx index a42480e2..59167f22 100644 --- a/src/components/WellShow/MonitoringInfo.tsx +++ b/src/components/WellShow/MonitoringInfo.tsx @@ -114,7 +114,7 @@ export const MonitoringInfoCard = ({ {firstVisitParticipants!.map((p) => ( - {p.participant?.contact_name || 'Unknown'} + {p.participant?.name || 'Unknown'} {p.participant_role && ( {' '}({p.participant_role}) diff --git a/src/interfaces/ocotillo/IFieldEvent.ts b/src/interfaces/ocotillo/IFieldEvent.ts index b0d500ce..ba4a7201 100644 --- a/src/interfaces/ocotillo/IFieldEvent.ts +++ b/src/interfaces/ocotillo/IFieldEvent.ts @@ -2,8 +2,8 @@ export interface IFieldEventParticipantContact { id: number created_at?: string release_status?: string - contact_name?: string | null - contact_organization?: string | null + name?: string | null + organization?: string | null } export interface IFieldEventParticipant { diff --git a/src/interfaces/ocotillo/IWellDetails.ts b/src/interfaces/ocotillo/IWellDetails.ts index ea8a8340..becb78d5 100644 --- a/src/interfaces/ocotillo/IWellDetails.ts +++ b/src/interfaces/ocotillo/IWellDetails.ts @@ -11,4 +11,5 @@ export type IWellDetails = { deployments: any[] well_screens: IWellScreen[] field_events: IFieldEvent[] + first_field_event?: IFieldEvent | null } diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index b68c9946..6ce4e4c1 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -97,11 +97,10 @@ export const WellShow = () => { const deployments = detailsQuery.data?.deployments ?? [] const wellScreens = detailsQuery.data?.well_screens ?? [] const fieldEvents = detailsQuery.data?.field_events ?? [] - // field_events are sorted newest-first; last entry is the earliest visit + // first_field_event is the oldest field event, returned separately by the API + // to avoid being cut off by the field_events page limit const firstVisitParticipants = - fieldEvents.length > 0 - ? (fieldEvents[fieldEvents.length - 1].field_event_participants ?? []) - : [] + detailsQuery.data?.first_field_event?.field_event_participants ?? [] const recentObservations = useMemo(() => { return fieldEvents From 5cd2236fc1a501b0cb5dbc4b867a4267f670e3bf Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 21 Apr 2026 11:25:07 -0500 Subject: [PATCH 15/52] feat(WellPhysicalProperties): Impl basic unit conversion toggle --- .../WellShow/WellPhysicalProperties.tsx | 114 +++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 55488cab..bf4ba670 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -1,5 +1,13 @@ -import { Paper, Box, Stack, Typography } from '@mui/material' +import { + Paper, + Box, + Stack, + Typography, + ToggleButtonGroup, + ToggleButton, +} from '@mui/material' import { IWell } from '@/interfaces/ocotillo' +import { useEffect, useMemo, useState } from 'react' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { const elevation = well?.current_location?.properties?.elevation @@ -16,9 +24,10 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { - ( ) + +const INCHES_IN_A_FOOT = 12 + +const roundToTwo = (num: number): number => { + return Math.round(num * 100) / 100 +} + +const convertInchesToFeet = (value: number): number => { + return roundToTwo(value / INCHES_IN_A_FOOT) +} + +const convertFeetToInches = (value: number): number => { + return roundToTwo(value * INCHES_IN_A_FOOT) +} + +const formatNumber = (num: number): string => { + return num.toFixed(2) +} + +type SupportedUnit = 'in' | 'ft' + +const InlineRowWithUnitConversion = ({ + label, + value, + unit, +}: { + label: string + value: number + unit: SupportedUnit | string +}) => { + const normalizedUnit: SupportedUnit | null = + unit === 'in' || unit === 'ft' ? unit : null + + const defaultDisplayUnit: SupportedUnit = + normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' + + const [displayUnit, setDisplayUnit] = + useState(defaultDisplayUnit) + + useEffect(() => { + const nextDefault: SupportedUnit = + normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' + + setDisplayUnit(nextDefault) + }, [value, normalizedUnit]) + + const displayValue = useMemo(() => { + if (normalizedUnit === 'in') { + return displayUnit === 'ft' + ? convertInchesToFeet(value) + : roundToTwo(value) + } + + if (normalizedUnit === 'ft') { + return displayUnit === 'in' + ? convertFeetToInches(value) + : roundToTwo(value) + } + + return roundToTwo(value) + }, [displayUnit, normalizedUnit, value]) + + const handleUnitChange = ( + _event: React.MouseEvent, + nextUnit: SupportedUnit | null + ) => { + if (nextUnit) { + setDisplayUnit(nextUnit) + } + } + + return ( + + + {label}:{' '} + + {formatNumber(displayValue)} {displayUnit} + + + + {normalizedUnit && ( + + + in + + + ft + + + )} + + ) +} From 374600ed8e13aaa41023d89c98e8f04afbfdb248 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 21 Apr 2026 11:42:11 -0500 Subject: [PATCH 16/52] refactor(config & constant): Mv configs & contants in WellShow component to their respective files --- .../WellShow/WellPhysicalProperties.tsx | 55 ++++++--------- src/config/index.ts | 1 + src/config/unit.ts | 1 + src/constants.ts | 2 + src/utils/Unit.ts | 70 +++++++++++++++++++ 5 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 src/config/unit.ts create mode 100644 src/utils/Unit.ts diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index bf4ba670..2ae1f4c7 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -8,6 +8,13 @@ import { } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' import { useEffect, useMemo, useState } from 'react' +import { INCHES_IN_A_FOOT } from '@/constants' +import { SupportedUnits } from '@/config' +import { + convertFeetToInches, + convertInchesToFeet, + formatNumber, +} from '@/utils/Unit' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { const elevation = well?.current_location?.properties?.elevation @@ -26,8 +33,8 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { ( ) -const INCHES_IN_A_FOOT = 12 - -const roundToTwo = (num: number): number => { - return Math.round(num * 100) / 100 -} - -const convertInchesToFeet = (value: number): number => { - return roundToTwo(value / INCHES_IN_A_FOOT) -} - -const convertFeetToInches = (value: number): number => { - return roundToTwo(value * INCHES_IN_A_FOOT) -} - -const formatNumber = (num: number): string => { - return num.toFixed(2) -} - -type SupportedUnit = 'in' | 'ft' - const InlineRowWithUnitConversion = ({ label, value, @@ -97,19 +84,19 @@ const InlineRowWithUnitConversion = ({ }: { label: string value: number - unit: SupportedUnit | string + unit: SupportedUnits | string }) => { - const normalizedUnit: SupportedUnit | null = + const normalizedUnit: SupportedUnits | null = unit === 'in' || unit === 'ft' ? unit : null - const defaultDisplayUnit: SupportedUnit = + const defaultDisplayUnit: SupportedUnits = normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' const [displayUnit, setDisplayUnit] = - useState(defaultDisplayUnit) + useState(defaultDisplayUnit) useEffect(() => { - const nextDefault: SupportedUnit = + const nextDefault: SupportedUnits = normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' setDisplayUnit(nextDefault) @@ -118,22 +105,22 @@ const InlineRowWithUnitConversion = ({ const displayValue = useMemo(() => { if (normalizedUnit === 'in') { return displayUnit === 'ft' - ? convertInchesToFeet(value) - : roundToTwo(value) + ? convertInchesToFeet(value, { precision: 2 }) + : value?.toFixed(2) } if (normalizedUnit === 'ft') { return displayUnit === 'in' - ? convertFeetToInches(value) - : roundToTwo(value) + ? convertFeetToInches(value, { precision: 2 }) + : value?.toFixed(2) } - return roundToTwo(value) + return value.toFixed(2) }, [displayUnit, normalizedUnit, value]) const handleUnitChange = ( _event: React.MouseEvent, - nextUnit: SupportedUnit | null + nextUnit: SupportedUnits | null ) => { if (nextUnit) { setDisplayUnit(nextUnit) @@ -145,7 +132,7 @@ const InlineRowWithUnitConversion = ({ {label}:{' '} - {formatNumber(displayValue)} {displayUnit} + {formatNumber(displayValue, { precision: 2 })} {displayUnit} diff --git a/src/config/index.ts b/src/config/index.ts index 5cc123f7..aee79eed 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -2,3 +2,4 @@ export * from './auth' export * from './storage-key' export * from './pdf' export * from './time' +export * from './unit' diff --git a/src/config/unit.ts b/src/config/unit.ts new file mode 100644 index 00000000..3b3e3d76 --- /dev/null +++ b/src/config/unit.ts @@ -0,0 +1 @@ +export type SupportedUnits = 'in' | 'ft' diff --git a/src/constants.ts b/src/constants.ts index d46ed763..09e14398 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -36,3 +36,5 @@ export enum GroupType { Messages = 'Messages', Assets = 'Assets', } + +export const INCHES_IN_A_FOOT = 12 diff --git a/src/utils/Unit.ts b/src/utils/Unit.ts new file mode 100644 index 00000000..2705e81b --- /dev/null +++ b/src/utils/Unit.ts @@ -0,0 +1,70 @@ +import { INCHES_IN_A_FOOT } from '@/constants' + +type ConversionOptions = { + precision?: number // e.g. 2 → rounds to 2 decimals + format?: boolean // if true → returns string +} + +type FormatOptions = { + precision?: number +} + +// Internal helper to optionally round +const maybeRound = (num: number, precision?: number): number => { + if (precision === undefined) return num + const factor = Math.pow(10, precision) + return Math.round(num * factor) / factor +} + +// Internal helper to optionally format +const maybeFormat = ( + num: number, + precision?: number, + format?: boolean +): number | string => { + if (!format) return num + return precision !== undefined ? num.toFixed(precision) : String(num) +} + +export const convertInchesToFeet = ( + value: number, + options?: ConversionOptions +): number | string => { + const result = value / INCHES_IN_A_FOOT + const rounded = maybeRound(result, options?.precision) + return maybeFormat(rounded, options?.precision, options?.format) +} + +export const convertFeetToInches = ( + value: number, + options?: ConversionOptions +): number | string => { + const result = value * INCHES_IN_A_FOOT + const rounded = maybeRound(result, options?.precision) + return maybeFormat(rounded, options?.precision, options?.format) +} + +// Generic formatter +export const formatNumber = ( + value: number | string, + options?: FormatOptions +): string => { + let numericValue: number + + if (typeof value === 'number') { + numericValue = value + } else { + // Try to convert string → number + numericValue = Number(value) + + if (Number.isNaN(numericValue)) { + throw new Error(`Invalid number string: "${value}"`) + } + } + + if (options?.precision !== undefined) { + return numericValue.toFixed(options.precision) + } + + return String(numericValue) +} From 28f7e2f969f9fab0c4a4819b92ce0d18212eb79a Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 12:46:19 -0400 Subject: [PATCH 17/52] Refine Monitoring Info card layout and labels Reorganize card into two sections: status fields above the divider, visit history below. Add Last Visit Date from newest field event. Relabel duration as Measured For. Add bullet points to First Visit Staff list. --- src/components/WellShow/MonitoringInfo.tsx | 29 +++++++++++++--------- src/pages/ocotillo/thing/well-show.tsx | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/WellShow/MonitoringInfo.tsx b/src/components/WellShow/MonitoringInfo.tsx index 59167f22..be7d6600 100644 --- a/src/components/WellShow/MonitoringInfo.tsx +++ b/src/components/WellShow/MonitoringInfo.tsx @@ -21,10 +21,12 @@ function getMeasuringDuration(firstVisitDate: string | null | undefined): string export const MonitoringInfoCard = ({ well, firstVisitParticipants, + lastVisitDate, isLoading, }: { well?: IWell firstVisitParticipants?: IFieldEventParticipant[] + lastVisitDate?: string | null isLoading?: boolean }) => { if (isLoading) { @@ -49,6 +51,7 @@ export const MonitoringInfoCard = ({ const firstVisitDate = well?.first_visit_date const duration = getMeasuringDuration(firstVisitDate) + const hasParticipants = firstVisitParticipants && firstVisitParticipants.length > 0 const monitoringFrequencies = well?.monitoring_frequencies ?? [] @@ -64,14 +67,6 @@ export const MonitoringInfoCard = ({ - - - - - + + + + - + First Visit Staff:{' '} {!hasParticipants && ( @@ -111,10 +116,10 @@ export const MonitoringInfoCard = ({ )} {hasParticipants && ( - + {firstVisitParticipants!.map((p) => ( - - {p.participant?.name || 'Unknown'} + + •{' '}{p.participant?.name || 'Unknown'} {p.participant_role && ( {' '}({p.participant_role}) diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 6ce4e4c1..24c45759 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -347,6 +347,7 @@ export const WellShow = () => { From 207cda2dadacbcf8317b3510bff5150a17fdb83f Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 21 Apr 2026 11:50:36 -0500 Subject: [PATCH 18/52] fix(InlineRowWithUnitConversion): Add support for NaN inputs --- .../WellShow/WellPhysicalProperties.tsx | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 2ae1f4c7..326826d1 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -83,40 +83,56 @@ const InlineRowWithUnitConversion = ({ unit, }: { label: string - value: number - unit: SupportedUnits | string + value: number | null | undefined + unit: SupportedUnits | string | null | undefined }) => { const normalizedUnit: SupportedUnits | null = unit === 'in' || unit === 'ft' ? unit : null + const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) + const defaultDisplayUnit: SupportedUnits = - normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' + normalizedUnit === 'in' && hasNumericValue + ? value >= INCHES_IN_A_FOOT + ? 'ft' + : 'in' + : normalizedUnit === 'ft' + ? 'ft' + : 'ft' const [displayUnit, setDisplayUnit] = useState(defaultDisplayUnit) useEffect(() => { const nextDefault: SupportedUnits = - normalizedUnit === 'in' ? (value >= INCHES_IN_A_FOOT ? 'ft' : 'in') : 'ft' + normalizedUnit === 'in' && hasNumericValue + ? value >= INCHES_IN_A_FOOT + ? 'ft' + : 'in' + : normalizedUnit === 'ft' + ? 'ft' + : 'ft' setDisplayUnit(nextDefault) - }, [value, normalizedUnit]) + }, [value, normalizedUnit, hasNumericValue]) const displayValue = useMemo(() => { + if (!hasNumericValue) return null + if (normalizedUnit === 'in') { return displayUnit === 'ft' ? convertInchesToFeet(value, { precision: 2 }) - : value?.toFixed(2) + : value } if (normalizedUnit === 'ft') { return displayUnit === 'in' ? convertFeetToInches(value, { precision: 2 }) - : value?.toFixed(2) + : value } - return value.toFixed(2) - }, [displayUnit, normalizedUnit, value]) + return value + }, [displayUnit, normalizedUnit, value, hasNumericValue]) const handleUnitChange = ( _event: React.MouseEvent, @@ -127,16 +143,27 @@ const InlineRowWithUnitConversion = ({ } } + if (!hasNumericValue) { + return + } + + const shouldShowToggle = normalizedUnit === 'in' || normalizedUnit === 'ft' + return ( {label}:{' '} - {formatNumber(displayValue, { precision: 2 })} {displayUnit} + {formatNumber(displayValue, { precision: 2 })} + {shouldShowToggle + ? ` ${displayUnit}` + : normalizedUnit + ? ` ${normalizedUnit}` + : ''} - {normalizedUnit && ( + {shouldShowToggle && ( Date: Tue, 21 Apr 2026 12:53:54 -0400 Subject: [PATCH 19/52] update types --- src/generated/types.gen.ts | 190 +++++++++++++++++++++++++++++++++++-- src/generated/zod.gen.ts | 131 +++++++++++++++++++++++-- 2 files changed, 302 insertions(+), 19 deletions(-) diff --git a/src/generated/types.gen.ts b/src/generated/types.gen.ts index 2b2ebd71..fc2813fd 100644 --- a/src/generated/types.gen.ts +++ b/src/generated/types.gen.ts @@ -3329,6 +3329,112 @@ export type WellContactSummaryResponse = { contact_type: ContactType; }; +/** + * WellDetailsFieldActivityResponse + */ +export type WellDetailsFieldActivityResponse = { + /** + * Id + */ + id: number; + /** + * Created At + */ + created_at: string; + release_status: ReleaseStatus; + /** + * Field Event Id + */ + field_event_id: number; + activity_type: ActivityType; + /** + * Notes + */ + notes?: string | null; + /** + * Samples + */ + samples?: Array; +}; + +/** + * WellDetailsFieldEventResponse + */ +export type WellDetailsFieldEventResponse = { + /** + * Id + */ + id: number; + /** + * Created At + */ + created_at: string; + release_status: ReleaseStatus; + /** + * Thing Id + */ + thing_id: number; + /** + * Event Date + */ + event_date: string; + /** + * Notes + */ + notes?: string | null; + /** + * Field Event Participants + */ + field_event_participants?: Array; + /** + * Field Activities + */ + field_activities?: Array; +}; + +/** + * WellDetailsFieldEventSampleResponse + */ +export type WellDetailsFieldEventSampleResponse = { + /** + * Id + */ + id: number; + /** + * Created At + */ + created_at: string; + release_status: ReleaseStatus; + contact?: ContactResponse | null; + /** + * Sample Date + */ + sample_date: string; + /** + * Sample Name + */ + sample_name: string; + sample_matrix: SampleMatrix; + sample_method: SampleMethod; + qc_type: QcType; + /** + * Notes + */ + notes?: string | null; + /** + * Depth Top + */ + depth_top?: number | null; + /** + * Depth Bottom + */ + depth_bottom?: number | null; + /** + * Observations + */ + observations?: Array; +}; + /** * WellDetailsResponse */ @@ -3349,16 +3455,12 @@ export type WellDetailsResponse = { /** * Well Screens */ - well_screens?: Array; + well_screens?: Array; /** - * Recent Groundwater Level Observations + * Field Events */ - recent_groundwater_level_observations?: Array; - latest_field_event_sample?: SampleResponse | null; - /** - * Field Event Participants - */ - field_event_participants?: Array; + field_events?: Array; + first_field_event?: WellDetailsFieldEventResponse | null; }; /** @@ -3571,6 +3673,69 @@ export type WellResponse = { well_location_note?: Array; }; +/** + * WellScreenBaseResponse + */ +export type WellScreenBaseResponse = { + /** + * Id + */ + id: number; + /** + * Created At + */ + created_at: string; + release_status: ReleaseStatus; + /** + * Thing Id + */ + thing_id: number; + /** + * Aquifer System Id + */ + aquifer_system_id?: number | null; + /** + * Aquifer System + */ + aquifer_system?: string | null; + /** + * Aquifer Type + */ + aquifer_type?: string | null; + /** + * Geologic Formation Id + */ + geologic_formation_id?: number | null; + /** + * Geologic Formation + */ + geologic_formation?: string | null; + /** + * Screen Depth Bottom + */ + screen_depth_bottom?: number | null; + /** + * Screen Depth Bottom Unit + */ + screen_depth_bottom_unit?: string; + /** + * Screen Depth Top + */ + screen_depth_top?: number | null; + /** + * Screen Depth Top Unit + */ + screen_depth_top_unit?: string; + /** + * Screen Type + */ + screen_type?: string | null; + /** + * Screen Description + */ + screen_description?: string | null; +}; + /** * WellScreenResponse * @@ -3590,7 +3755,6 @@ export type WellScreenResponse = { * Thing Id */ thing_id: number; - thing: WellResponse; /** * Aquifer System Id */ @@ -3635,6 +3799,7 @@ export type WellScreenResponse = { * Screen Description */ screen_description?: string | null; + thing: WellResponse; }; /** @@ -6775,7 +6940,12 @@ export type GetWellDetailsThingWaterWellThingIdDetailsGetData = { */ thing_id: number; }; - query?: never; + query?: { + /** + * Field Event Limit + */ + field_event_limit?: number; + }; url: '/thing/water-well/{thing_id}/details'; }; diff --git a/src/generated/zod.gen.ts b/src/generated/zod.gen.ts index 66c697c8..88b206a2 100644 --- a/src/generated/zod.gen.ts +++ b/src/generated/zod.gen.ts @@ -3004,7 +3004,6 @@ export const zWellScreenResponse = z.object({ created_at: z.string(), release_status: zReleaseStatus, thing_id: z.int(), - thing: zWellResponse, aquifer_system_id: z.optional(z.union([ z.int(), z.null() @@ -3042,7 +3041,8 @@ export const zWellScreenResponse = z.object({ screen_description: z.optional(z.union([ z.string(), z.null() - ])) + ])), + thing: zWellResponse }); /** @@ -3731,6 +3731,118 @@ export const zWaterLevelBulkUploadResponse = z.object({ validation_errors: z.array(z.string()) }); +/** + * WellDetailsFieldEventSampleResponse + */ +export const zWellDetailsFieldEventSampleResponse = z.object({ + id: z.int(), + created_at: z.string(), + release_status: zReleaseStatus, + contact: z.optional(z.union([ + zContactResponse, + z.null() + ])), + sample_date: z.string(), + sample_name: z.string(), + sample_matrix: zSampleMatrix, + sample_method: zSampleMethod, + qc_type: zQcType, + notes: z.optional(z.union([ + z.string(), + z.null() + ])), + depth_top: z.optional(z.union([ + z.number(), + z.null() + ])), + depth_bottom: z.optional(z.union([ + z.number(), + z.null() + ])), + observations: z.optional(z.array(zObservationResponse)) +}); + +/** + * WellDetailsFieldActivityResponse + */ +export const zWellDetailsFieldActivityResponse = z.object({ + id: z.int(), + created_at: z.string(), + release_status: zReleaseStatus, + field_event_id: z.int(), + activity_type: zActivityType, + notes: z.optional(z.union([ + z.string(), + z.null() + ])), + samples: z.optional(z.array(zWellDetailsFieldEventSampleResponse)) +}); + +/** + * WellDetailsFieldEventResponse + */ +export const zWellDetailsFieldEventResponse = z.object({ + id: z.int(), + created_at: z.string(), + release_status: zReleaseStatus, + thing_id: z.int(), + event_date: z.string(), + notes: z.optional(z.union([ + z.string(), + z.null() + ])), + field_event_participants: z.optional(z.array(zFieldEventParticipantResponse)), + field_activities: z.optional(z.array(zWellDetailsFieldActivityResponse)) +}); + +/** + * WellScreenBaseResponse + */ +export const zWellScreenBaseResponse = z.object({ + id: z.int(), + created_at: z.string(), + release_status: zReleaseStatus, + thing_id: z.int(), + aquifer_system_id: z.optional(z.union([ + z.int(), + z.null() + ])), + aquifer_system: z.optional(z.union([ + z.string(), + z.null() + ])), + aquifer_type: z.optional(z.union([ + z.string(), + z.null() + ])), + geologic_formation_id: z.optional(z.union([ + z.int(), + z.null() + ])), + geologic_formation: z.optional(z.union([ + z.string(), + z.null() + ])), + screen_depth_bottom: z.optional(z.union([ + z.number(), + z.null() + ])), + screen_depth_bottom_unit: z.optional(z.string()).default('ft'), + screen_depth_top: z.optional(z.union([ + z.number(), + z.null() + ])), + screen_depth_top_unit: z.optional(z.string()).default('ft'), + screen_type: z.optional(z.union([ + z.string(), + z.null() + ])), + screen_description: z.optional(z.union([ + z.string(), + z.null() + ])) +}); + /** * WellDetailsResponse */ @@ -3739,13 +3851,12 @@ export const zWellDetailsResponse = z.object({ contacts: z.optional(z.array(zContactResponse)), sensors: z.optional(z.array(zSensorResponse)), deployments: z.optional(z.array(zDeploymentResponse)), - well_screens: z.optional(z.array(zWellScreenResponse)), - recent_groundwater_level_observations: z.optional(z.array(zGroundwaterLevelObservationResponse)), - latest_field_event_sample: z.optional(z.union([ - zSampleResponse, + well_screens: z.optional(z.array(zWellScreenBaseResponse)), + field_events: z.optional(z.array(zWellDetailsFieldEventResponse)), + first_field_event: z.optional(z.union([ + zWellDetailsFieldEventResponse, z.null() - ])), - field_event_participants: z.optional(z.array(zFieldEventParticipantResponse)) + ])) }); /** @@ -5049,7 +5160,9 @@ export const zGetWellDetailsThingWaterWellThingIdDetailsGetData = z.object({ path: z.object({ thing_id: z.int() }), - query: z.optional(z.never()) + query: z.optional(z.object({ + field_event_limit: z.optional(z.int().gte(1).lte(100)).default(25) + })) }); /** From a8677fbe8f35f6c3ca1b16ff461f2ddea3e542bd Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Tue, 21 Apr 2026 11:57:46 -0500 Subject: [PATCH 20/52] chore(utils/index): Add Unit utilies to utils folder index --- src/components/WellShow/WellPhysicalProperties.tsx | 6 +----- src/utils/index.ts | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 326826d1..551bb52b 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -10,11 +10,7 @@ import { IWell } from '@/interfaces/ocotillo' import { useEffect, useMemo, useState } from 'react' import { INCHES_IN_A_FOOT } from '@/constants' import { SupportedUnits } from '@/config' -import { - convertFeetToInches, - convertInchesToFeet, - formatNumber, -} from '@/utils/Unit' +import { convertFeetToInches, convertInchesToFeet, formatNumber } from '@/utils' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { const elevation = well?.current_location?.properties?.elevation diff --git a/src/utils/index.ts b/src/utils/index.ts index 7abe4f11..948f44f2 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -22,6 +22,7 @@ export * from './ParseWktPoint' export * from './RemoveEmptyFields' export * from './SensorDeploymentRows' export * from './Transform' +export * from './Unit' export * from './UpdateMapView' export * from './UtmToLonLat' export * from './WellBatchExport' From 3d2c60b6fba5a1894f93e34851e11bedfb878b6a Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 12:58:00 -0400 Subject: [PATCH 21/52] Fix well-show test mock for MonitoringInfoCard and field_events shape --- src/test/pages/well-show.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/pages/well-show.test.tsx b/src/test/pages/well-show.test.tsx index 9ccfeaa2..01294cb6 100644 --- a/src/test/pages/well-show.test.tsx +++ b/src/test/pages/well-show.test.tsx @@ -62,6 +62,7 @@ vi.mock('@/components', () => { WellPDFDownloadButton: () => , WellShowTitle: () => , OwnerPermissionsCard: () => , + MonitoringInfoCard: () => , } }) @@ -96,8 +97,8 @@ describe('WellShow data loading', () => { sensors: [], deployments: [], well_screens: [], - recent_groundwater_level_observations: [], - latest_field_event_sample: null, + field_events: [], + first_field_event: null, }, isLoading: false, } From ba74e48d1cf82039e9e2ccb3f42591bfdb62b29d Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 13:20:58 -0400 Subject: [PATCH 22/52] Guard getMeasuringDuration against invalid date strings --- src/components/WellShow/MonitoringInfo.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/WellShow/MonitoringInfo.tsx b/src/components/WellShow/MonitoringInfo.tsx index be7d6600..3814dfe8 100644 --- a/src/components/WellShow/MonitoringInfo.tsx +++ b/src/components/WellShow/MonitoringInfo.tsx @@ -6,6 +6,7 @@ import { formatAppDate } from '@/utils' function getMeasuringDuration(firstVisitDate: string | null | undefined): string { if (!firstVisitDate) return 'N/A' const start = new Date(firstVisitDate) + if (Number.isNaN(start.getTime())) return 'N/A' const now = new Date() const totalMonths = (now.getFullYear() - start.getFullYear()) * 12 + From 1775b443d27efc44e253dd92c29d64bd952faab2 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 17:03:32 -0400 Subject: [PATCH 23/52] Improve unit toggle button styling in WellPhysicalProperties - Remove vertical padding to align with surrounding inline rows - Highlight selected unit with primary color for clarity - Fix border visibility in dark mode using theme-aware rgba value - Reduce toggle button font size to 0.7rem --- .../WellShow/WellPhysicalProperties.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 551bb52b..774ba8a5 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -166,11 +166,27 @@ const InlineRowWithUnitConversion = ({ value={displayUnit} onChange={handleUnitChange} aria-label={`${label} unit toggle`} + sx={(theme) => ({ + '& .MuiToggleButton-root': { + color: 'text.secondary', + border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, + }, + '& .MuiToggleButton-root + .MuiToggleButton-root': { + borderLeft: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, + marginLeft: 0, + }, + '& .MuiToggleButton-root.Mui-selected': { + bgcolor: 'primary.main', + color: 'primary.contrastText', + border: `1px solid ${theme.palette.primary.main} !important`, + '&:hover': { bgcolor: 'primary.dark' }, + }, + })} > - + in - + ft From 6a0f97e81d9b6ad4f911f5ee5214a63f84f38c12 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Tue, 21 Apr 2026 17:07:30 -0400 Subject: [PATCH 24/52] Restore ISample import removed by cleanup ISample is still used as a type cast in well-show.tsx on staging; removing the import causes a TS2304 build error when branches merge. --- src/pages/ocotillo/thing/well-show.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index f4ea61a5..17c6edec 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -5,7 +5,7 @@ import { useQuery } from '@tanstack/react-query' import { Show, useDataGrid } from '@refinedev/mui' import { AppBreadcrumb } from '@/components/AppBreadcrumb' import { TransducerObservationWithBlockResponse } from '@/generated/types.gen' -import { IAsset, IWellDetails, IObservation } from '@/interfaces/ocotillo' +import { IAsset, IWellDetails, IObservation, ISample } from '@/interfaces/ocotillo' import { Box, Stack } from '@mui/material' import { IHydrographDatasource } from '@/interfaces/st2' import { useAccessCapabilities, useSensorDeploymentRows } from '@/hooks' From 5632e3d6683715d008de911ee76d557cf8ddc61d Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Wed, 22 Apr 2026 10:30:05 -0500 Subject: [PATCH 25/52] refactor(WellPhysicalProperties): Extract the default-unit logic into a helper --- .../WellShow/WellPhysicalProperties.tsx | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 774ba8a5..3eb6a1fb 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -87,30 +87,13 @@ const InlineRowWithUnitConversion = ({ const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) - const defaultDisplayUnit: SupportedUnits = - normalizedUnit === 'in' && hasNumericValue - ? value >= INCHES_IN_A_FOOT - ? 'ft' - : 'in' - : normalizedUnit === 'ft' - ? 'ft' - : 'ft' - - const [displayUnit, setDisplayUnit] = - useState(defaultDisplayUnit) + const [displayUnit, setDisplayUnit] = useState(() => + getDefaultDisplayUnit(value, normalizedUnit) + ) useEffect(() => { - const nextDefault: SupportedUnits = - normalizedUnit === 'in' && hasNumericValue - ? value >= INCHES_IN_A_FOOT - ? 'ft' - : 'in' - : normalizedUnit === 'ft' - ? 'ft' - : 'ft' - - setDisplayUnit(nextDefault) - }, [value, normalizedUnit, hasNumericValue]) + setDisplayUnit(getDefaultDisplayUnit(value, normalizedUnit)) + }, [value, normalizedUnit]) const displayValue = useMemo(() => { if (!hasNumericValue) return null @@ -183,10 +166,18 @@ const InlineRowWithUnitConversion = ({ }, })} > - + in - + ft @@ -194,3 +185,16 @@ const InlineRowWithUnitConversion = ({ ) } + +const getDefaultDisplayUnit = ( + value: number | null | undefined, + normalizedUnit: SupportedUnits | null +): SupportedUnits => { + const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) + + if (normalizedUnit === 'in' && hasNumericValue) { + return value >= INCHES_IN_A_FOOT ? 'ft' : 'in' + } + + return 'ft' +} From bfde27e0d5ef3290b5a732a86b6ca2090461be31 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Wed, 22 Apr 2026 10:06:42 -0500 Subject: [PATCH 26/52] fix(WellPhysicalProperties): Add guard to normalize elevation to null if zero --- src/components/WellShow/WellPhysicalProperties.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx index 3eb6a1fb..fa7d1e62 100644 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ b/src/components/WellShow/WellPhysicalProperties.tsx @@ -14,6 +14,8 @@ import { convertFeetToInches, convertInchesToFeet, formatNumber } from '@/utils' export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { const elevation = well?.current_location?.properties?.elevation + const normalizedElevation = + elevation != null && elevation !== 0 ? elevation : null const elevationUnit = well?.current_location?.properties?.elevation_unit const elevationMethod = well?.current_location?.properties?.elevation_method const verticalDatum = well?.current_location?.properties?.vertical_datum @@ -48,8 +50,8 @@ export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { From 6e880aa042219b506629aa788d0e21e1d5e9a27b Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Wed, 22 Apr 2026 14:45:10 -0400 Subject: [PATCH 27/52] Add Get Help button to global header Adds a pre-filled Google Form bug report button to the app header, visible on every page. Auto-populates page URL, user identity, browser/OS, and timestamp on open. --- src/components/Button/ReportBugButton.tsx | 43 +++++++++++++++++++++++ src/components/Button/index.ts | 1 + src/components/layout/header.tsx | 2 ++ src/config/bug-report.ts | 10 ++++++ src/config/index.ts | 1 + src/utils/BuildBugReportUrl.ts | 22 ++++++++++++ src/utils/index.ts | 1 + 7 files changed, 80 insertions(+) create mode 100644 src/components/Button/ReportBugButton.tsx create mode 100644 src/config/bug-report.ts create mode 100644 src/utils/BuildBugReportUrl.ts diff --git a/src/components/Button/ReportBugButton.tsx b/src/components/Button/ReportBugButton.tsx new file mode 100644 index 00000000..9b56436d --- /dev/null +++ b/src/components/Button/ReportBugButton.tsx @@ -0,0 +1,43 @@ +import { Button } from '@mui/material' +import { BugReportOutlined } from '@mui/icons-material' +import { buildBugReportUrl } from '@/utils' + +interface ReportBugButtonProps { + user?: { + name?: string + email?: string + } +} + +export const ReportBugButton = ({ user }: ReportBugButtonProps) => { + const handleClick = () => { + const url = buildBugReportUrl({ + userName: user?.name, + userEmail: user?.email, + }) + window.open(url, '_blank', 'noopener,noreferrer') + } + + return ( + + ) +} diff --git a/src/components/Button/index.ts b/src/components/Button/index.ts index f8aa8081..36b3c1d7 100644 --- a/src/components/Button/index.ts +++ b/src/components/Button/index.ts @@ -1,2 +1,3 @@ +export * from './ReportBugButton' export * from './WellPDFPreview' export * from './WellPDFDownload' diff --git a/src/components/layout/header.tsx b/src/components/layout/header.tsx index e335cfbf..d51742de 100644 --- a/src/components/layout/header.tsx +++ b/src/components/layout/header.tsx @@ -28,6 +28,7 @@ import { import type { RefineThemedLayoutHeaderProps } from '@refinedev/mui' import { HamburgerMenu } from './hamburgerMenu' import SearchBar from '@/components/SearchBar' +import { ReportBugButton } from '@/components/Button' import { Underline } from 'react-flaticons' export const ThemedHeaderV2: React.FC = () => { @@ -102,6 +103,7 @@ export const ThemedHeaderV2: React.FC = () => { alignItems="center" justifyContent="center" > + {isLoading ? ( ` : ''].filter(Boolean) + return parts.length > 0 ? parts.join(' ') : 'unknown' +} + +export function buildBugReportUrl(context: { + userName?: string + userEmail?: string +}): string { + const params = new URLSearchParams({ + [BUG_REPORT_FIELDS.pageUrl]: window.location.href, + [BUG_REPORT_FIELDS.reportedBy]: formatReportedBy( + context.userName, + context.userEmail + ), + [BUG_REPORT_FIELDS.browser]: navigator.userAgent, + [BUG_REPORT_FIELDS.timestamp]: new Date().toISOString(), + }) + return `https://docs.google.com/forms/d/e/${BUG_REPORT_FORM_ID}/viewform?usp=pp_url&${params}` +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 948f44f2..58074553 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -26,5 +26,6 @@ export * from './Unit' export * from './UpdateMapView' export * from './UtmToLonLat' export * from './WellBatchExport' +export * from './BuildBugReportUrl' export * from './docsSearch' export * from './searchModal' From 1d4303a2bb2b664f6995435f13fde0b365a6dc45 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Wed, 22 Apr 2026 17:38:51 -0400 Subject: [PATCH 28/52] Show organization, phone type, and address type in ContactsCard Each contact now displays organization (or 'No organization listed'), phone type labels beside each number, and physical/mailing address type above each address. --- src/components/WellShow/Contacts.tsx | 94 ++++++++++++++++++---------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/src/components/WellShow/Contacts.tsx b/src/components/WellShow/Contacts.tsx index 0b6db83a..3c6f0aa0 100644 --- a/src/components/WellShow/Contacts.tsx +++ b/src/components/WellShow/Contacts.tsx @@ -18,16 +18,26 @@ const getGoogleMapsAddressUrl = (address: string) => { return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(address)}` } +const formatAddressType = (type: string): string => { + const lower = type.toLowerCase() + if (lower.includes('physical') && lower.includes('mail')) return 'Physical & Mailing' + if (lower.includes('physical')) return 'Physical' + if (lower.includes('mail')) return 'Mailing' + return type +} + +const formatPhoneType = (type: string): string => { + if (!type) return '' + return type.charAt(0).toUpperCase() + type.slice(1).toLowerCase() +} + const ContactBlock = ({ contact }: { contact: IContact }) => { const roleType = [contact.role, contact.contact_type].filter(Boolean).join(' / ') || null const emails = contact.emails?.map((e: { email?: string }) => e.email).filter(Boolean) ?? [] - const phones = - contact.phones - ?.map((p: { phone_number?: string }) => p.phone_number) - .filter(Boolean) ?? [] + const phones = contact.phones ?? [] const addresses = contact.addresses ?? [] return ( @@ -56,6 +66,9 @@ const ContactBlock = ({ contact }: { contact: IContact }) => { {contact.name} )} + + {contact.organization || 'No organization listed'} + {emails.map((email, idx) => ( { ))} {phones.map((phone, idx) => ( - - {formatPhone(phone)} - + + + {formatPhone(phone.phone_number ?? '')} + + {phone.phone_type && ( + + {formatPhoneType(phone.phone_type)} + + )} + ))} {addresses.map((addr, idx) => ( - - - {formatContactAddress(addr)} - - {getGoogleMapsAddressUrl(formatAddress(addr)) && ( - - - - - + + {addr.address_type && ( + + {formatAddressType(addr.address_type)} + )} + + + {formatContactAddress(addr)} + + {getGoogleMapsAddressUrl(formatAddress(addr)) && ( + + + + + + )} + ))} From 98c9cf6b602b08dc9e94efc06e2058e4cb381e08 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Thu, 23 Apr 2026 11:09:18 -0500 Subject: [PATCH 29/52] feat(RecentWaterLevelObservations): Disable table selection & left aligned all columns --- .../card/RecentWaterLevelObservations.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/card/RecentWaterLevelObservations.tsx b/src/components/card/RecentWaterLevelObservations.tsx index 7d31912a..db631dac 100644 --- a/src/components/card/RecentWaterLevelObservations.tsx +++ b/src/components/card/RecentWaterLevelObservations.tsx @@ -34,15 +34,31 @@ export const RecentWaterLevelObservationsCard = ({ headerName: 'Date/Time', valueGetter: (isoDate: string) => formatAppDateTime(isoDate), minWidth: 200, + headerAlign: 'left', + align: 'left', }, { field: 'depth_to_water_bgs', headerName: 'Depth To Water (ft bgs)', type: 'number', + minWidth: 175, + headerAlign: 'left', + align: 'left', + }, + { + field: 'release_status', + headerName: 'Release Status', + minWidth: 150, + headerAlign: 'left', + align: 'left', + }, + { + field: 'level_status', + headerName: 'Level Status', minWidth: 150, + headerAlign: 'left', + align: 'left', }, - { field: 'release_status', headerName: 'Release Status', minWidth: 150 }, - { field: 'level_status', headerName: 'Level Status', minWidth: 150 }, ] }, []) @@ -87,6 +103,7 @@ export const RecentWaterLevelObservationsCard = ({ getRowId={(row) => row.id} rowHeight={settings.rowHeight} columns={cols} + disableRowSelectionOnClick pageSizeOptions={[10, 25, 50]} initialState={{ pagination: { From 2c0b5db7cd0b88286d3a4a06c1383a58c44c9a0e Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Thu, 23 Apr 2026 11:22:30 -0500 Subject: [PATCH 30/52] fix(well-show): Filter out null observations so they don't show up on the hydrograph --- src/pages/ocotillo/thing/well-show.tsx | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 69c56cb1..cb17869c 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -5,7 +5,12 @@ import { useQuery } from '@tanstack/react-query' import { Show, useDataGrid } from '@refinedev/mui' import { AppBreadcrumb } from '@/components/AppBreadcrumb' import { TransducerObservationWithBlockResponse } from '@/generated/types.gen' -import { IAsset, IWellDetails, IObservation, ISample } from '@/interfaces/ocotillo' +import { + IAsset, + IWellDetails, + IObservation, + ISample, +} from '@/interfaces/ocotillo' import { Box, Stack } from '@mui/material' import { IHydrographDatasource } from '@/interfaces/st2' import { useAccessCapabilities, useSensorDeploymentRows } from '@/hooks' @@ -211,7 +216,12 @@ export const WellShow = () => { name: 'Groundwater Level', style: 'scatter', data: manualHydrographRows - .filter((obs) => obs.observation_datetime) + .filter( + (obs) => + obs.observation_datetime != null && + obs.depth_to_water_bgs != null && + !Number.isNaN(Number(obs.depth_to_water_bgs)) + ) .map((obs) => ({ phenomenonTime: new Date(obs.observation_datetime), result: Number(obs.depth_to_water_bgs), @@ -230,7 +240,11 @@ export const WellShow = () => { name: 'Transducer Groundwater Level', style: 'line', data: transducerHydrographRows - .filter(({ observation }) => observation?.observation_datetime) + .filter( + ({ observation }) => + observation?.observation_datetime != null && + observation?.value != null + ) .map(({ observation }) => ({ phenomenonTime: new Date(observation.observation_datetime), result: Number(observation.value), @@ -283,7 +297,9 @@ export const WellShow = () => { []} + observations={ + recentObservations as unknown as Partial[] + } assets={assets} contacts={contacts} sample={latestSample as Partial | undefined} @@ -334,7 +350,11 @@ export const WellShow = () => { {/* Right column: 2 cols */} - + Date: Thu, 23 Apr 2026 13:47:28 -0400 Subject: [PATCH 31/52] Hide home test-site banner when VITE_APP_ENV is production The info drawer only appears for signed-in users on staging and local dev. Production builds with VITE_APP_ENV=production no longer show the test site message. Permission denied warning is unchanged. --- src/pages/home/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 9aa784e7..e467e008 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -42,9 +42,17 @@ export const Home = () => { ) } +const appEnv = import.meta.env.VITE_APP_ENV || 'production' +const showTestSiteBanner = + import.meta.env.DEV || appEnv !== 'production' + const HomeNotification = ({ noPermissions }) => { const [notificationOpen, setNotificationOpen] = useState(true) + if (!noPermissions && !showTestSiteBanner) { + return null + } + return ( { )} - {!noPermissions && ( + {!noPermissions && showTestSiteBanner && ( Date: Fri, 24 Apr 2026 09:08:31 -0500 Subject: [PATCH 32/52] fix(utils/accessControl): Lowered the permissions needed to view field sheets --- src/resources/ocotillo.tsx | 18 +++++++++--------- src/utils/accessControl.ts | 7 ++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/resources/ocotillo.tsx b/src/resources/ocotillo.tsx index 5380310d..2586ca66 100644 --- a/src/resources/ocotillo.tsx +++ b/src/resources/ocotillo.tsx @@ -1,23 +1,23 @@ import { - Apps, + // Apps, Construction, DatasetLinked, Contacts, - DynamicFormOutlined, - Image, + // DynamicFormOutlined, + // Image, LibraryBooksOutlined, - Link, + // Link, Map, - MoreVertOutlined, + // MoreVertOutlined, Opacity, PictureAsPdfOutlined, Place, ScaleOutlined, - ScienceOutlined, - SettingsInputAntenna, - Spa, + // ScienceOutlined, + // SettingsInputAntenna, + // Spa, Timeline, - Workspaces, + // Workspaces, } from '@mui/icons-material' let tables: { diff --git a/src/utils/accessControl.ts b/src/utils/accessControl.ts index 65e6b149..f80c3786 100644 --- a/src/utils/accessControl.ts +++ b/src/utils/accessControl.ts @@ -51,10 +51,7 @@ const geothermalEditorRoles: PortalRole[] = [ 'Geothermal.Admin', ] const geothermalAdminRoles: PortalRole[] = ['Geothermal.Admin'] -const adminOnlyRoles = new Set([ - 'AMP.Admin', - 'Geothermal.Admin', -]) +const adminOnlyRoles = new Set(['AMP.Admin', 'Geothermal.Admin']) const resourcePolicies: Record = { ocotillo: { list: viewerRoles, show: viewerRoles }, @@ -94,7 +91,7 @@ const resourcePolicies: Record = { }, 'ocotillo.hydrograph-correction': { list: adminRoles, show: adminRoles }, 'ocotillo.thing-well-pdf-preview': { list: adminRoles, show: adminRoles }, - 'ocotillo.thing-well-batch-export': { list: editorRoles, show: editorRoles }, + 'ocotillo.thing-well-batch-export': { list: viewerRoles, show: viewerRoles }, 'ocotillo.groundwater-level-observation': { list: viewerRoles, show: viewerRoles, From a30404ae539b379654047d271c112fdc2939f3e8 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 09:51:40 -0500 Subject: [PATCH 33/52] fix(RecentWaterLevelObservations): Update flatmap logic to get all the information the card needed --- .../card/RecentWaterLevelObservations.tsx | 43 +++++++++++++++++-- src/interfaces/ocotillo/IFieldActivity.ts | 3 ++ src/pages/ocotillo/thing/well-show.tsx | 23 ++++++++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/components/card/RecentWaterLevelObservations.tsx b/src/components/card/RecentWaterLevelObservations.tsx index db631dac..94a9696a 100644 --- a/src/components/card/RecentWaterLevelObservations.tsx +++ b/src/components/card/RecentWaterLevelObservations.tsx @@ -14,20 +14,29 @@ import { DataGrid, GridColDef } from '@mui/x-data-grid' import { settings } from '@/settings' import { formatAppDateTime } from '@/utils' +export type WaterLevelObservationRow = Omit & { + created_at?: string | null + water_level_method?: string | null + water_level_status?: string | null + water_level_measuring_staff?: string | null + water_level_notes?: string | null + water_level_data_quality?: string | null +} + export const RecentWaterLevelObservationsCard = ({ well, rows, isLoading = false, }: { well: IWell - rows: readonly IObservation[] + rows: readonly WaterLevelObservationRow[] isLoading: boolean }) => { if (!well || isLoading) { return } - const cols: GridColDef[] = useMemo(() => { + const cols: GridColDef[] = useMemo(() => { return [ { field: 'observation_datetime', @@ -53,12 +62,40 @@ export const RecentWaterLevelObservationsCard = ({ align: 'left', }, { - field: 'level_status', + field: 'water_level_method', + headerName: 'Method', + minWidth: 250, + headerAlign: 'left', + align: 'left', + }, + { + field: 'water_level_status', headerName: 'Level Status', minWidth: 150, headerAlign: 'left', align: 'left', }, + { + field: 'water_level_measuring_staff', + headerName: 'Measuring Staff', + minWidth: 150, + headerAlign: 'left', + align: 'left', + }, + { + field: 'water_level_notes', + headerName: 'Notes', + minWidth: 375, + headerAlign: 'left', + align: 'left', + }, + { + field: 'water_level_data_quality', + headerName: 'Data Quality', + minWidth: 375, + headerAlign: 'left', + align: 'left', + }, ] }, []) diff --git a/src/interfaces/ocotillo/IFieldActivity.ts b/src/interfaces/ocotillo/IFieldActivity.ts index fd0ace58..5440647c 100644 --- a/src/interfaces/ocotillo/IFieldActivity.ts +++ b/src/interfaces/ocotillo/IFieldActivity.ts @@ -29,6 +29,9 @@ export interface IFieldActivitySample { depth_top?: number | null depth_bottom?: number | null observations?: IFieldActivitySampleObservation[] + contact?: { + name?: string | null + } | null } export interface IFieldActivity { diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index cb17869c..3e211f88 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -36,6 +36,7 @@ import { WellShowTitle, OwnerPermissionsCard, MonitoringInfoCard, + WaterLevelObservationRow, } from '@/components' export const WellShow = () => { @@ -98,11 +99,25 @@ export const WellShow = () => { const firstVisitParticipants = detailsQuery.data?.first_field_event?.field_event_participants ?? [] - const recentObservations = useMemo(() => { + const recentObservations = useMemo< + Partial[] + >(() => { return fieldEvents - .flatMap((event) => event.field_activities ?? []) - .flatMap((activity) => activity.samples ?? []) - .flatMap((sample) => sample.observations ?? []) + .flatMap((event) => + (event.field_activities ?? []).flatMap((activity) => + (activity.samples ?? []).flatMap((sample) => + (sample.observations ?? []).map((observation) => ({ + ...observation, + water_level_method: sample.sample_method, + water_level_status: observation.groundwater_level_reason, + water_level_measuring_staff: sample.contact?.name, + water_level_notes: + sample.notes ?? activity.notes ?? event.notes ?? null, + water_level_data_quality: observation.nma_data_quality, + })) + ) + ) + ) .filter((obs) => obs.observation_datetime != null) .sort((a, b) => { const dateA = new Date(a.observation_datetime!).getTime() From 9267c5fc35e5978078afe82f04bbcaaae629d949 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 10:25:24 -0500 Subject: [PATCH 34/52] fix(src): patch IObservation type across the well show --- src/components/Button/WellPDFDownload.tsx | 2 +- src/components/card/RecentWaterLevelObservations.tsx | 2 +- src/pages/ocotillo/thing/well-show.tsx | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/Button/WellPDFDownload.tsx b/src/components/Button/WellPDFDownload.tsx index 2cd9bec9..c419af29 100644 --- a/src/components/Button/WellPDFDownload.tsx +++ b/src/components/Button/WellPDFDownload.tsx @@ -23,7 +23,7 @@ export const WellPDFDownloadButton = ({ }: { well: IWell isLoading: boolean - observations: readonly Partial[] + observations: readonly Partial>[] assets: BaseRecord[] contacts: IContact[] sample?: Partial diff --git a/src/components/card/RecentWaterLevelObservations.tsx b/src/components/card/RecentWaterLevelObservations.tsx index 94a9696a..8fe8bf6e 100644 --- a/src/components/card/RecentWaterLevelObservations.tsx +++ b/src/components/card/RecentWaterLevelObservations.tsx @@ -29,7 +29,7 @@ export const RecentWaterLevelObservationsCard = ({ isLoading = false, }: { well: IWell - rows: readonly WaterLevelObservationRow[] + rows: readonly Partial[] isLoading: boolean }) => { if (!well || isLoading) { diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 3e211f88..49414f36 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -312,9 +312,7 @@ export const WellShow = () => { [] - } + observations={recentObservations} assets={assets} contacts={contacts} sample={latestSample as Partial | undefined} @@ -339,7 +337,7 @@ export const WellShow = () => { /> From 0137570229ab8ad5fb101134ee756a20431c72dc Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 10:56:31 -0500 Subject: [PATCH 35/52] chore(test/utils/accessControl): Update tests to match new logic --- src/test/utils/accessControl.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/utils/accessControl.test.ts b/src/test/utils/accessControl.test.ts index aa66faeb..e045fb16 100644 --- a/src/test/utils/accessControl.test.ts +++ b/src/test/utils/accessControl.test.ts @@ -68,6 +68,7 @@ const expectedAccessByScenario: Scenario[] = [ 'ocotillo.collections', 'ocotillo.map', 'ocotillo.thing-well', + 'ocotillo.thing-well-batch-export', ], }, { @@ -110,6 +111,7 @@ const expectedAccessByScenario: Scenario[] = [ 'ocotillo.collections', 'ocotillo.map', 'ocotillo.thing-well', + 'ocotillo.thing-well-batch-export', ], }, ] From 6f6589d3f6a9235ac755d6c02c986b4271c8936d Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 11:52:04 -0500 Subject: [PATCH 36/52] fix(utils/accessControl): Add contact list & show to viewer group permission set --- src/test/utils/accessControl.test.ts | 6 ++++-- src/utils/accessControl.ts | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/utils/accessControl.test.ts b/src/test/utils/accessControl.test.ts index e045fb16..e0c0c495 100644 --- a/src/test/utils/accessControl.test.ts +++ b/src/test/utils/accessControl.test.ts @@ -67,6 +67,7 @@ const expectedAccessByScenario: Scenario[] = [ allowedResources: [ 'ocotillo.collections', 'ocotillo.map', + 'ocotillo.contact', 'ocotillo.thing-well', 'ocotillo.thing-well-batch-export', ], @@ -111,6 +112,7 @@ const expectedAccessByScenario: Scenario[] = [ 'ocotillo.collections', 'ocotillo.map', 'ocotillo.thing-well', + 'ocotillo.contact', 'ocotillo.thing-well-batch-export', ], }, @@ -138,11 +140,11 @@ const specialResourceExpectations: Array<{ expected: true, }, { - name: 'AMP viewer cannot see contacts', + name: 'AMP viewer can see contacts', groups: ['AMP.Viewer'], resource: 'ocotillo.contact', action: 'list', - expected: false, + expected: true, }, { name: 'AMP editor cannot see ocotillo.location', diff --git a/src/utils/accessControl.ts b/src/utils/accessControl.ts index f80c3786..ad7afb59 100644 --- a/src/utils/accessControl.ts +++ b/src/utils/accessControl.ts @@ -58,8 +58,8 @@ const resourcePolicies: Record = { 'ocotillo.map': { list: viewerRoles, show: viewerRoles }, 'ocotillo.collections': { list: viewerRoles, show: viewerRoles }, 'ocotillo.contact': { - list: editorRoles, - show: editorRoles, + list: viewerRoles, + show: viewerRoles, edit: editorRoles, create: editorRoles, delete: editorRoles, From e9674f6b40949eec86fefbb75653ab8f0791c779 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Fri, 24 Apr 2026 14:19:31 -0400 Subject: [PATCH 37/52] update ocotillo.lexicon to adminRoles --- src/utils/accessControl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/accessControl.ts b/src/utils/accessControl.ts index ad7afb59..ce9232bb 100644 --- a/src/utils/accessControl.ts +++ b/src/utils/accessControl.ts @@ -74,8 +74,8 @@ const resourcePolicies: Record = { manage: ['AMP.Admin', 'Geothermal.Admin'], }, 'ocotillo.lexicon': { - list: editorRoles, - show: editorRoles, + list: adminRoles, + show: adminRoles, edit: editorRoles, create: adminRoles, delete: adminRoles, From 4bb6e440d3737b92c8c1da5d8f5d128d642b3ecd Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Fri, 24 Apr 2026 14:29:12 -0400 Subject: [PATCH 38/52] Fix access control tests for admin-only lexicon list and show Lexicon list and show use adminRoles; update matrix expectations, isResourceListAdminOnly for ocotillo.lexicon, and provider test to use edit instead of show for AMP.Editor. --- src/test/utils/accessControl.test.ts | 3 +-- src/test/utils/accessControlProvider.test.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/utils/accessControl.test.ts b/src/test/utils/accessControl.test.ts index e0c0c495..cb65e962 100644 --- a/src/test/utils/accessControl.test.ts +++ b/src/test/utils/accessControl.test.ts @@ -79,7 +79,6 @@ const expectedAccessByScenario: Scenario[] = [ 'ocotillo.collections', 'ocotillo.map', 'ocotillo.thing-well', - 'ocotillo.lexicon', 'ocotillo.contact', 'ocotillo.thing-well-batch-export', 'water.wellinventoryform', @@ -412,13 +411,13 @@ describe('isResourceListAdminOnly', () => { it('returns true for list resources restricted to admin roles', () => { expect(isResourceListAdminOnly('ocotillo.location')).toBe(true) expect(isResourceListAdminOnly('ocotillo.hydrograph-correction')).toBe(true) + expect(isResourceListAdminOnly('ocotillo.lexicon')).toBe(true) expect(isResourceListAdminOnly('Sandbox')).toBe(true) expect(isResourceListAdminOnly('water.locations')).toBe(true) }) it('returns false for non-admin list resources and unknown resources', () => { expect(isResourceListAdminOnly('ocotillo.thing-well')).toBe(false) - expect(isResourceListAdminOnly('ocotillo.lexicon')).toBe(false) expect(isResourceListAdminOnly('unknown.resource')).toBe(false) }) }) diff --git a/src/test/utils/accessControlProvider.test.ts b/src/test/utils/accessControlProvider.test.ts index 2dbaa6ac..3b295251 100644 --- a/src/test/utils/accessControlProvider.test.ts +++ b/src/test/utils/accessControlProvider.test.ts @@ -15,7 +15,7 @@ describe('accessControlProvider', () => { await expect( accessControlProvider.can({ resource: 'ocotillo.lexicon', - action: 'show', + action: 'edit', }) ).resolves.toEqual({ can: true }) From 3201e5cca14c01aa4d02c4315ca2252e8fbcbc13 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 13:40:58 -0500 Subject: [PATCH 39/52] fix(accessControl): Account for name mismatch --- src/components/layout/sider.tsx | 16 +++++++++------- src/utils/accessControl.ts | 9 +++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/layout/sider.tsx b/src/components/layout/sider.tsx index c3011e11..2622c7c0 100644 --- a/src/components/layout/sider.tsx +++ b/src/components/layout/sider.tsx @@ -1,13 +1,15 @@ import React, { type CSSProperties, useContext, useState } from 'react' import { CanAccess, useMenu, type TreeMenuItem } from '@refinedev/core' import { ThemedTitle, useThemedLayoutContext } from '@refinedev/mui' -import ChevronLeft from '@mui/icons-material/ChevronLeft' -import DarkModeOutlined from '@mui/icons-material/DarkModeOutlined' -import ExpandLess from '@mui/icons-material/ExpandLess' -import ExpandMore from '@mui/icons-material/ExpandMore' -import LightModeOutlined from '@mui/icons-material/LightModeOutlined' -import ListOutlined from '@mui/icons-material/ListOutlined' -import LockOutlined from '@mui/icons-material/LockOutlined' +import { + ChevronLeft, + DarkModeOutlined, + ExpandLess, + ExpandMore, + LightModeOutlined, + ListOutlined, + LockOutlined, +} from '@mui/icons-material' import { Box, Collapse, diff --git a/src/utils/accessControl.ts b/src/utils/accessControl.ts index ce9232bb..d332713f 100644 --- a/src/utils/accessControl.ts +++ b/src/utils/accessControl.ts @@ -125,8 +125,13 @@ const matchesPolicy = ( roles: PortalRole[] ): boolean => Boolean(allowedRoles?.some((role) => roles.includes(role))) -export const isResourceListAdminOnly = (resource: string): boolean => { - const listPolicy = resourcePolicies[resource]?.list +export const isResourceListAdminOnly = (resource?: string): boolean => { + if (!resource) return false + + const listPolicy = + resourcePolicies[resource]?.list ?? + resourcePolicies[resource.toLowerCase()]?.list + if (!listPolicy || listPolicy.length === 0) return false return listPolicy.every((role) => adminOnlyRoles.has(role)) From 06c99d1910e75b240ab24d07cebb135afcb42930 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 13:56:31 -0500 Subject: [PATCH 40/52] chore(sider): Update things that could lead to a bug --- src/components/layout/sider.tsx | 40 +++++++++++++-------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/components/layout/sider.tsx b/src/components/layout/sider.tsx index 2622c7c0..40650641 100644 --- a/src/components/layout/sider.tsx +++ b/src/components/layout/sider.tsx @@ -71,7 +71,12 @@ export const ThemedSiderV2: React.FC = ({ name, route, } = item - const isOpen = open[key] || false + + const itemKey = key ?? name ?? route ?? '' + const resourceName = name ?? key ?? '' + const isOpen = open[itemKey] ?? false + const hasChildren = (children?.length ?? 0) > 0 + const isAdminOnly = isResourceListAdminOnly(resourceName) const icon = deprecatedIcon ?? meta?.icon const derivedLabel = meta?.label || deprecatedLabel || name @@ -81,31 +86,23 @@ export const ThemedSiderV2: React.FC = ({ const isNested = meta?.parent !== undefined const nestedLevel = isNested ? meta?.nestedLevel || 1 : 0 const disabled = meta?.disabled || false - const isAdminOnly = isResourceListAdminOnly(name) + const tooltipTitle = siderCollapsed && isAdminOnly ? `${label ?? name} (Admin only)` : (label ?? name) - // const allowedCategories = new Set([ - // 'Water', - // 'Batch Upload', - // 'Lookup Tables', - // 'DataForge: Coming Soon', - // 'Observations', - // ]) - - if (children.length > 0) { + if (hasChildren) { return ( -
+
= ({ if (siderCollapsed) { setSiderCollapsed(false) if (!isOpen) { - handleClick(key || '') + handleClick(itemKey) } } else { - handleClick(key || '') + handleClick(itemKey) } }} sx={{ @@ -142,7 +139,6 @@ export const ThemedSiderV2: React.FC = ({ justifyContent: 'center', minWidth: '20px', transition: 'margin-right 0.3s', - // marginRight: siderCollapsed ? '0px' : '12px', mr: siderCollapsed ? 0 : 1, color: 'currentColor', }} @@ -189,11 +185,7 @@ export const ThemedSiderV2: React.FC = ({ {!siderCollapsed && ( - + {renderTreeView(children, selectedKey)} @@ -209,8 +201,8 @@ export const ThemedSiderV2: React.FC = ({ return ( From 78c2c7b7c71d8c1c4f782b9129f186723f554db1 Mon Sep 17 00:00:00 2001 From: Tyler Adam Martinez Date: Fri, 24 Apr 2026 14:00:41 -0500 Subject: [PATCH 41/52] chore(sider): Add new abstract here too --- src/components/layout/sider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/layout/sider.tsx b/src/components/layout/sider.tsx index 40650641..039669d2 100644 --- a/src/components/layout/sider.tsx +++ b/src/components/layout/sider.tsx @@ -185,7 +185,7 @@ export const ThemedSiderV2: React.FC = ({ {!siderCollapsed && ( - + {renderTreeView(children, selectedKey)} From b326e2d3b489113ccbf12542b7d47b43ccf39b71 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Fri, 24 Apr 2026 15:54:50 -0400 Subject: [PATCH 42/52] update email address to ocotillo-nmbg@nmt.edu --- public/content/about.md | 2 +- public/content/report-a-bug.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/content/about.md b/public/content/about.md index 1b231a58..8e949792 100644 --- a/public/content/about.md +++ b/public/content/about.md @@ -36,4 +36,4 @@ One of the things the process revealed was that data sharing problems exist with ## Questions or feedback? -Use the [Report a Bug](/report-a-bug) page to submit issues or suggestions, or reach out to the Data Services team at [newmexicowaterdata@nmt.edu](mailto:newmexicowaterdata@nmt.edu). +Use the [Report a Bug](/report-a-bug) page to submit issues or suggestions, or reach out to the Data Services team at [ocotillo-nmbg@nmt.edu](mailto:ocotillo-nmbg@nmt.edu). diff --git a/public/content/report-a-bug.md b/public/content/report-a-bug.md index ab2f2837..1411f5eb 100644 --- a/public/content/report-a-bug.md +++ b/public/content/report-a-bug.md @@ -19,4 +19,4 @@ A good bug report includes: ## Contact -For urgent issues or questions, reach out directly to the development team at [newmexicowaterdata@nmt.edu](mailto:ocotillo-nmbg@nmt.edu). \ No newline at end of file +For urgent issues or questions, reach out directly to the development team at [ocotillo-nmbg@nmt.edu](mailto:ocotillo-nmbg@nmt.edu). \ No newline at end of file From fffe71107f6abaad2a27b301851ba2ebf4aa3d41 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Fri, 24 Apr 2026 17:29:44 -0400 Subject: [PATCH 43/52] Stop mutating measuring_notes on each render in recent water level card. Use the first note for display instead of shift(), which was altering cached well data and could cause flicker when the parent re-rendered. --- src/components/card/RecentWaterLevelObservations.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/card/RecentWaterLevelObservations.tsx b/src/components/card/RecentWaterLevelObservations.tsx index 8fe8bf6e..15839b76 100644 --- a/src/components/card/RecentWaterLevelObservations.tsx +++ b/src/components/card/RecentWaterLevelObservations.tsx @@ -99,7 +99,7 @@ export const RecentWaterLevelObservationsCard = ({ ] }, []) - const measuringNote = well?.measuring_notes?.shift() + const measuringNote = well.measuring_notes?.[0] return ( Date: Fri, 24 Apr 2026 17:29:46 -0400 Subject: [PATCH 44/52] Use stable empty array references for well detail fallbacks. Inline ?? [] created new arrays every render when details or hydrograph data was missing, which broke memo and effect dependencies and could make DataGrid rows churn during load. --- src/pages/ocotillo/thing/well-show.tsx | 37 +++++++++++++++++++------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 49414f36..9a66ac85 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -7,9 +7,14 @@ import { AppBreadcrumb } from '@/components/AppBreadcrumb' import { TransducerObservationWithBlockResponse } from '@/generated/types.gen' import { IAsset, + IContact, + IFieldEvent, + IFieldEventParticipant, IWellDetails, IObservation, ISample, + ISensor, + IWellScreen, } from '@/interfaces/ocotillo' import { Box, Stack } from '@mui/material' import { IHydrographDatasource } from '@/interfaces/st2' @@ -39,6 +44,17 @@ import { WaterLevelObservationRow, } from '@/components' +const EMPTY_ASSETS: IAsset[] = [] +const EMPTY_CONTACTS: IContact[] = [] +const EMPTY_SENSORS: ISensor[] = [] +const EMPTY_DEPLOYMENTS: IWellDetails['deployments'] = [] +const EMPTY_WELL_SCREENS: IWellScreen[] = [] +const EMPTY_FIELD_EVENTS: IFieldEvent[] = [] +const EMPTY_PARTICIPANTS: IFieldEventParticipant[] = [] +const EMPTY_MANUAL_HYDRO_ROWS: IObservation[] = [] +const EMPTY_TRANSDUCER_HYDRO_ROWS: TransducerObservationWithBlockResponse[] = + [] + export const WellShow = () => { const dataProvider = useDataProvider() const ocotilloDataProvider = useMemo( @@ -88,16 +104,17 @@ export const WellShow = () => { document.title = prev } }, [well?.name]) - const assets = assetResult?.data ?? [] - const contacts = detailsQuery.data?.contacts ?? [] - const sensors = detailsQuery.data?.sensors ?? [] - const deployments = detailsQuery.data?.deployments ?? [] - const wellScreens = detailsQuery.data?.well_screens ?? [] - const fieldEvents = detailsQuery.data?.field_events ?? [] + const assets = assetResult?.data ?? EMPTY_ASSETS + const contacts = detailsQuery.data?.contacts ?? EMPTY_CONTACTS + const sensors = detailsQuery.data?.sensors ?? EMPTY_SENSORS + const deployments = detailsQuery.data?.deployments ?? EMPTY_DEPLOYMENTS + const wellScreens = detailsQuery.data?.well_screens ?? EMPTY_WELL_SCREENS + const fieldEvents = detailsQuery.data?.field_events ?? EMPTY_FIELD_EVENTS // first_field_event is the oldest field event, returned separately by the API // to avoid being cut off by the field_events page limit const firstVisitParticipants = - detailsQuery.data?.first_field_event?.field_event_participants ?? [] + detailsQuery.data?.first_field_event?.field_event_participants ?? + EMPTY_PARTICIPANTS const recentObservations = useMemo< Partial[] @@ -220,8 +237,10 @@ export const WellShow = () => { }, }) - const manualHydrographRows = hydrographQuery.data?.manualRows ?? [] - const transducerHydrographRows = hydrographQuery.data?.transducerRows ?? [] + const manualHydrographRows = + hydrographQuery.data?.manualRows ?? EMPTY_MANUAL_HYDRO_ROWS + const transducerHydrographRows = + hydrographQuery.data?.transducerRows ?? EMPTY_TRANSDUCER_HYDRO_ROWS const hydrographDatasource = useMemo(() => { const manualSource = From 49e19f248938aeb8b6d0e1cab7f359d07376b8e9 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Fri, 24 Apr 2026 17:52:35 -0400 Subject: [PATCH 45/52] Improve well attachments grid and file table. Render storage URIs as links that open in a new tab. Wrap masonry thumbnails in ButtonBase so choosing an image switches to slideshow view at that index. Tighten DataGrid column typing for assets. --- src/components/WellShow/Attachments.tsx | 84 ++++++++++++++++++------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/components/WellShow/Attachments.tsx b/src/components/WellShow/Attachments.tsx index 26217a6c..c55cb9b1 100644 --- a/src/components/WellShow/Attachments.tsx +++ b/src/components/WellShow/Attachments.tsx @@ -1,7 +1,9 @@ import { useMemo, useState } from 'react' import { Box, + ButtonBase, IconButton, + Link, Paper, Stack, Typography, @@ -36,10 +38,42 @@ export const AttachmentsAccordion = ({ [assets] ) - const columns = useMemo( + const columns = useMemo[]>( () => [ { field: 'name', headerName: 'Name', minWidth: 150 }, - { field: 'uri', headerName: 'URL', flex: 1 }, + { + field: 'uri', + headerName: 'URL', + flex: 1, + minWidth: 200, + renderCell: ({ value }) => { + const href = typeof value === 'string' ? value : '' + if (!href) { + return ( + + N/A + + ) + } + return ( + + {href} + + ) + }, + }, ], [] ) @@ -112,28 +146,36 @@ export const AttachmentsAccordion = ({ {imageViewMode === 'grid' ? ( - {imageAssets.map( - ( - img: { signed_url: string; name?: string }, - idx: number - ) => ( + {imageAssets.map((img, idx) => ( + { + setSlideshowIndex(idx) + setImageViewMode('slideshow') + }} + sx={{ + display: 'block', + width: '100%', + borderRadius: 2, + overflow: 'hidden', + boxShadow: 2, + textAlign: 'left', + }} + > - - - ) - )} + /> + + ))} ) : ( Date: Fri, 24 Apr 2026 18:02:27 -0400 Subject: [PATCH 46/52] Reduce Equipment DataGrid loading overlay flicker on well detail. Drive the grid loading state from well-details isPending instead of isLoading so background refetches do not flash the skeleton. Only show the overlay while pending and deployment rows are still empty. Memoize rowSelectionModel and resync selection when deployment row ids change instead of on every new rows array reference. --- src/components/WellShow/Equipment.tsx | 48 ++++++++++++++++++-------- src/pages/ocotillo/thing/well-show.tsx | 2 +- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/components/WellShow/Equipment.tsx b/src/components/WellShow/Equipment.tsx index 190ed5d1..268b7a3f 100644 --- a/src/components/WellShow/Equipment.tsx +++ b/src/components/WellShow/Equipment.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { Box, Chip, Paper, Stack, Typography } from '@mui/material' import { SettingsInputAntenna } from '@mui/icons-material' import { @@ -23,11 +23,12 @@ const EquipmentToolbar = () => ( export const EquipmentAccordion = ({ sensors, deployments, - isLoading, + isDetailsPending, }: { sensors: ISensor[] deployments: any[] - isLoading: boolean + /** True only until the first well-details result exists. Avoids refetch flicker on the DataGrid loading overlay. */ + isDetailsPending: boolean }) => { const [selectedEquipmentId, setSelectedEquipmentId] = useState(null) @@ -37,17 +38,40 @@ export const EquipmentAccordion = ({ sensors, }) + const deploymentSelectionKey = useMemo( + () => + sensorDeployments.length === 0 + ? '' + : sensorDeployments.map((row) => String(row.id)).join('|'), + [sensorDeployments] + ) + + const sensorDeploymentsRef = useRef(sensorDeployments) + sensorDeploymentsRef.current = sensorDeployments + useEffect(() => { - if (!sensorDeployments.length) { + const rows = sensorDeploymentsRef.current + if (!rows.length) { setSelectedEquipmentId(null) return } setSelectedEquipmentId((current) => { - const stillExists = sensorDeployments.some((row) => row.id === current) - return stillExists ? current : sensorDeployments[0].id + const stillExists = rows.some((row) => row.id === current) + return stillExists ? current : rows[0].id }) - }, [sensorDeployments]) + }, [deploymentSelectionKey]) + + const rowSelectionModel = useMemo( + () => + selectedEquipmentId != null + ? { type: 'include' as const, ids: new Set([selectedEquipmentId]) } + : { type: 'include' as const, ids: new Set() }, + [selectedEquipmentId] + ) + + const showGridLoadingOverlay = + Boolean(isDetailsPending) && sensorDeployments.length === 0 const selectedEquipment = sensorDeployments.find((row) => row.id === selectedEquipmentId) ?? null @@ -122,7 +146,7 @@ export const EquipmentAccordion = ({ rowHeight={28} - rows={sensorDeployments ?? []} + rows={sensorDeployments} columns={columns} slots={{ toolbar: EquipmentToolbar }} pageSizeOptions={[10, 25, 50]} @@ -132,12 +156,8 @@ export const EquipmentAccordion = ({ paginationModel: { pageSize: 10, page: 0 }, }, }} - loading={isLoading} - rowSelectionModel={ - selectedEquipmentId != null - ? { type: 'include', ids: new Set([selectedEquipmentId]) } - : { type: 'include', ids: new Set() } - } + loading={showGridLoadingOverlay} + rowSelectionModel={rowSelectionModel} onRowClick={(params) => setSelectedEquipmentId(params.id)} sx={{ border: 'none', diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 9a66ac85..1e33c9b4 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -363,7 +363,7 @@ export const WellShow = () => { Date: Mon, 27 Apr 2026 10:54:41 -0400 Subject: [PATCH 47/52] Point Prism mock servers at committed openapi-auth.json. CI was failing on Node 20 when Prism fetched the spec over HTTPS, hit a json-schema-ref-parser timeout/abort path, and never listened before the health check. The repo already includes the same spec as openapi-auth.json, so load it from disk and document that in the README. --- README.md | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 167fac47..f67d4757 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,8 @@ VITE_AUTHENTIK_REDIRECT_URI="https://your-athentik-redirect" ## Scripts/Commands - Mock Servers, Testing, Type/Zod Generation -- `npm run mock:server:vitest`: Runs a Prism mock server to run the vitest test suite. -- `npm run mock:server:cypress`: Runs a Prism mock server to run the cypress test suite. +- `npm run mock:server:vitest`: Runs a Prism mock server to run the vitest test suite. Uses the committed `openapi-auth.json` in the repo root (no network fetch for startup). +- `npm run mock:server:cypress`: Runs a Prism mock server to run the cypress test suite. Same spec file as vitest. - `npm run test:run`: Runs the Vitest test suite a single time. - `npx cypress open`: Opens the Cypress browser to run and interact with Cypress tests. - `npx cypress run`: Runs the Cypress test suite in headless mode a single time. diff --git a/package.json b/package.json index bdc6a68d..d83d7846 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "test:run": "vitest run", "test:coverage": "vitest run --coverage", "typecheck": "tsc", - "mock:server:vitest": "prism mock https://ocotillo-api-staging.newmexicowaterdata.org/openapi-auth.json --dynamic=false --port 4010", - "mock:server:cypress": "prism mock https://ocotillo-api-staging.newmexicowaterdata.org/openapi-auth.json --dynamic=true --port 4010 --seed 12345", + "mock:server:vitest": "prism mock openapi-auth.json --dynamic=false --port 4010", + "mock:server:cypress": "prism mock openapi-auth.json --dynamic=true --port 4010 --seed 12345", "openapi:generate": "npx @hey-api/openapi-ts" }, "browserslist": { From bd2ff3dae356d033e8d96ba25f101356d4c19772 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Mon, 27 Apr 2026 11:16:06 -0400 Subject: [PATCH 48/52] Refresh OpenAPI spec from staging and align codegen with Prism. Replace the stale committed openapi-auth.json so Prism mocks include required nullable well fields and contract Zod parsing passes. Point openapi-ts at the local spec so mocks and hey-api generation stay in sync. Document curling staging into openapi-auth.json before regenerate. --- README.md | 22 +++++++++++++++++----- openapi-auth.json | 2 +- openapi-ts.config.ts | 2 +- src/generated/types.gen.ts | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f67d4757..21aed4b9 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,18 @@ VITE_AUTHENTIK_REDIRECT_URI="https://your-athentik-redirect" - `npm run test:run`: Runs the Vitest test suite a single time. - `npx cypress open`: Opens the Cypress browser to run and interact with Cypress tests. - `npx cypress run`: Runs the Cypress test suite in headless mode a single time. -- `npm run openapi:generate`: Runs hey-api typescript generation for types and zod schemas in `/generated` +- `npm run openapi:generate`: Runs hey-api TypeScript and Zod generation using `./openapi-auth.json` into `src/generated`. + +## Refreshing the OpenAPI spec + +Prism mocks and codegen both use **`openapi-auth.json`** at the repo root. When the staging API adds or changes schemas, refresh the file from staging and regenerate so contract tests and `zWellResponse` validation stay aligned: + +```bash +curl -fsSL "https://ocotillo-api-staging.newmexicowaterdata.org/openapi-auth.json" -o openapi-auth.json +npm run openapi:generate +``` + +Then run tests and commit `openapi-auth.json` plus `src/generated/` updates as needed. ## Running the Vitest Test Suite @@ -150,14 +161,15 @@ npx cypress run ## Tests in CI and Openapi-TS Generation -Both the Vitest and Cypress test suites run via a Github action on PR. The Vitest contract tests may fail because of changes to the Ocotillo API if you have not recently run the test suite locally. -In the case of failing contract tests, you'll have to make sure your types and zod schemas are up to date with the openapi.json spec by: +Both the Vitest and Cypress test suites run via a Github action on PR. The Vitest contract tests may fail when the committed **`openapi-auth.json`** is older than the API schemas your Zod types expect. + +When the API changes, refresh **`openapi-auth.json`** from staging (see **Refreshing the OpenAPI spec** above), run: -- Running the opnenapi-ts generation from the Ocotillo Staging API `openapi.json` spec: ```bash npm run openapi:generate ``` -- Fixing any failing tests and related code + +Fix any failing tests and related code, then commit `openapi-auth.json` and `src/generated/` together with your changes. ## Building and Serving Production Build diff --git a/openapi-auth.json b/openapi-auth.json index dabe586a..38407bf1 100644 --- a/openapi-auth.json +++ b/openapi-auth.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Ocotillo API (Full)","description":"Full API schema (authorized users)","version":"0.0.1"},"paths":{"/asset/upload":{"post":{"tags":["asset"],"summary":"Upload Asset","operationId":"upload_asset_asset_upload_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"client","in":"query","required":false,"schema":{"title":"Client"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_asset_asset_upload_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Asset Asset Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset":{"post":{"tags":["asset"],"summary":"Add Asset","operationId":"add_asset_asset_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAsset"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["asset"],"summary":"List Assets","description":"List all assets or assets associated with a specific thing.","operationId":"list_assets_asset_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AssetResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/{asset_id}":{"get":{"tags":["asset"],"summary":"Get Asset","description":"Retrieve an asset by its ID.","operationId":"get_asset_asset__asset_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}},{"name":"client","in":"query","required":false,"schema":{"title":"Client"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["asset"],"summary":"Update Asset","description":"Update an existing asset.","operationId":"update_asset_asset__asset_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAsset"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["asset"],"summary":"Delete Asset","operationId":"delete_asset_asset__asset_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/{asset_id}/remove":{"delete":{"tags":["asset"],"summary":"Remove Asset","operationId":"remove_asset_asset__asset_id__remove_delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}},{"name":"client","in":"query","required":false,"schema":{"title":"Client"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/author/{author_id}/publications":{"get":{"tags":["author"],"summary":"Get Author Publications","description":"Retrieve all publications for a specific author.","operationId":"get_author_publications_author__author_id__publications_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"author_id","in":"path","required":true,"schema":{"type":"integer","title":"Author Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicationResponse"},"title":"Response Get Author Publications Author Author Id Publications Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact":{"post":{"tags":["contact"],"summary":"Create a new contact","operationId":"create_contact_contact_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContact"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get contacts","description":"Retrieve all contacts from the database.\n:param session:\n:return:","operationId":"get_contacts_contact_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ContactResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/address":{"post":{"tags":["contact"],"summary":"Add an address to a contact","description":"Add a new address to an existing contact in the database.\n:param contact_id: ID of the contact to add the address to\n:param address_data: Data for the new address\n:param session: Database session\n:return: Response containing the added address","operationId":"create_address_contact_address_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAddress"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all addresses","description":"Retrieve all addresses from the database.\n:param session:\n:return:","operationId":"get_addresses_contact_address_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AddressResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/email":{"post":{"tags":["contact"],"summary":"Add an email to a contact","operationId":"create_email_contact_email_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmail"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all emails","description":"Retrieve all emails from the database.\n:param session:\n:return:","operationId":"get_emails_contact_email_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_EmailResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/phone":{"post":{"tags":["contact"],"summary":"Add a phone number to a contact","operationId":"create_phone_contact_phone_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePhone"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all phones","description":"Retrieve all phone numbers from the database.\n:param session:\n:return:","operationId":"get_phones_contact_phone_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_PhoneResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/email/{email_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Email","description":"Update an existing contact's email in the database.","operationId":"update_contact_email_contact_email__email_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmail"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get email by ID","description":"Retrieve an email by ID from the database.","operationId":"get_email_by_id_contact_email__email_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact email","description":"Delete a contact email by ID from the database.","operationId":"delete_contact_email_contact_email__email_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/phone/{phone_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Phone","description":"Update an existing contact's phone number in the database.\n:param contact_id: ID of the contact to update\n:param phone_type: Type of the phone to update\n:param phone_number: New phone number\n:param session: Database session\n:return: Updated contact response","operationId":"update_contact_phone_contact_phone__phone_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePhone"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get phone by ID","description":"Retrieve a phone by ID from the database.","operationId":"get_phone_by_id_contact_phone__phone_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact phone","description":"Delete a contact phone by ID from the database.","operationId":"delete_contact_phone_contact_phone__phone_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/address/{address_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Address","description":"Update an existing contact's address in the database.\n\n:param address_id:\n:param address_data:\n:param session:\n:return:","operationId":"update_contact_address_contact_address__address_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAddress"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get address by ID","description":"Retrieve an address by ID from the database.","operationId":"get_address_by_id_contact_address__address_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact address","description":"Delete a contact address by ID from the database.","operationId":"delete_contact_address_contact_address__address_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}":{"patch":{"tags":["contact"],"summary":"Update contact","description":"Update an existing contact in the database.\n:param contact_id: ID of the contact to update\n:param contact_data: Data to update the contact with\n:param session: Database session\n:return: Updated contact response","operationId":"update_contact_contact__contact_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContact"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get contact by ID","description":"Retrieve a contact by ID from the database.","operationId":"get_contact_by_id_contact__contact_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact","description":"Delete a contact by ID from the database.","operationId":"delete_contact_contact__contact_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/email":{"get":{"tags":["contact"],"summary":"Get contact emails","description":"Retrieve all emails associated with a contact.","operationId":"get_contact_emails_contact__contact_id__email_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_EmailResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/phone":{"get":{"tags":["contact"],"summary":"Get contact phones","description":"Retrieve all phone numbers associated with a contact.","operationId":"get_contact_phones_contact__contact_id__phone_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_PhoneResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/address":{"get":{"tags":["contact"],"summary":"Get contact addresses","description":"Retrieve all addresses associated with a contact.","operationId":"get_contact_addresses_contact__contact_id__address_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AddressResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geospatial":{"get":{"tags":["geospatial"],"summary":"Get Geospatial","description":"Endpoint to retrieve a GeoJSON FeatureCollection or a shapefile.\nIf the request is for a shapefile, it will return a zip file containing the shapefile.\nOtherwise, it returns a GeoJSON FeatureCollection.","operationId":"get_geospatial_geospatial_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_type","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"title":"thing_type"}},{"name":"group","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"integer"}],"title":"group"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","pattern":"^(geojson|shapefile)$","title":"format","description":"Format of the response. 'geojson' for GeoJSON FeatureCollection, 'shapefile' for a shapefile.","default":"geojson"},"description":"Format of the response. 'geojson' for GeoJSON FeatureCollection, 'shapefile' for a shapefile."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geospatial/project-area/{group_id}":{"get":{"tags":["geospatial"],"summary":"Get project area for group","operationId":"get_project_area_geospatial_project_area__group_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureCollectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/group":{"post":{"tags":["group"],"summary":"Create a new group","description":"Create a new group in the database.","operationId":"create_group_group_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroup"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["group"],"summary":"Get groups","description":"Retrieve all groups from the database.","operationId":"get_groups_group_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/group/{group_id}":{"get":{"tags":["group"],"summary":"Get group by ID","description":"Retrieve a group by ID from the database.","operationId":"get_group_by_id_group__group_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["group"],"summary":"Update a group by ID","description":"Update a group by ID in the database.","operationId":"update_group_group__group_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroup"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["group"],"summary":"Delete a group by ID","operationId":"delete_group_group__group_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/category":{"post":{"tags":["lexicon"],"summary":"Add Category","description":"Endpoint to add a category to the lexicon.","operationId":"add_category_lexicon_category_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconCategory"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Categories","description":"Endpoint to retrieve lexicon categories.","operationId":"get_lexicon_categories_lexicon_category_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"name","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"asc","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconCategoryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/term":{"post":{"tags":["lexicon"],"summary":"Add term","description":"Endpoint to add a term to the lexicon.","operationId":"add_term_lexicon_term_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconTerm"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get lexicon terms","description":"Endpoint to retrieve lexicon terms.","operationId":"get_lexicon_terms_lexicon_term_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"term","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Term"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconTermResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/triple":{"post":{"tags":["lexicon"],"summary":"Add triple","operationId":"add_triple_lexicon_triple_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconTriple"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get lexicon triples","description":"Endpoint to retrieve lexicon triples.","operationId":"get_lexicon_triples_lexicon_triple_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"subject","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"asc","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconTripleResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/term/{term_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Term","operationId":"update_lexicon_term_lexicon_term__term_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconTerm"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Term","operationId":"get_lexicon_term_lexicon_term__term_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon term by ID","operationId":"delete_lexicon_term_lexicon_term__term_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/category/{category_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Category","operationId":"update_lexicon_category_lexicon_category__category_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconCategory"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Category","operationId":"get_lexicon_category_lexicon_category__category_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon category by ID","operationId":"delete_lexicon_category_lexicon_category__category_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/triple/{triple_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Triple","operationId":"update_lexicon_triple_lexicon_triple__triple_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconTriple"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Triple","operationId":"get_lexicon_triple_lexicon_triple__triple_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon triple by ID","operationId":"delete_lexicon_triple_lexicon_triple__triple_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/location":{"post":{"tags":["location"],"summary":"Create a new sample location","description":"Create a new sample location in the database.","operationId":"create_location_location_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLocation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["location"],"summary":"Get all locations","description":"Retrieve all wells from the database.","operationId":"get_location_location_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"nearby_point","in":"query","required":false,"schema":{"type":"string","title":"Nearby Point"}},{"name":"nearby_distance_km","in":"query","required":false,"schema":{"type":"number","default":1,"title":"Nearby Distance Km"}},{"name":"within","in":"query","required":false,"schema":{"type":"string","title":"Within"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LocationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/location/{location_id}":{"patch":{"tags":["location"],"summary":"Update a location","description":"Update a sample location in the database.","operationId":"update_location_location__location_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["location"],"summary":"Get location by ID","description":"Retrieve a sample location by ID from the database.","operationId":"get_location_by_id_location__location_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["location"],"summary":"Delete location by ID","description":"Delete a sample location by ID from the database.","operationId":"delete_location_location__location_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/groundwater-level":{"post":{"tags":["observation"],"summary":"Add Groundwater Level Observation","description":"Add a new groundwater observation to the database.","operationId":"add_groundwater_level_observation_observation_groundwater_level_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroundwaterLevelObservation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get groundwater level observations","description":"Retrieve all groundwater level observations from the database.","operationId":"get_groundwater_level_observations_observation_groundwater_level_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_GroundwaterLevelObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/water-chemistry":{"post":{"tags":["observation"],"summary":"Add Water Chemistry Observation","description":"Add a new water chemistry observation to the database.\nThis endpoint is currently a placeholder and does not implement any functionality.","operationId":"add_water_chemistry_observation_observation_water_chemistry_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWaterChemistryObservation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get water chemistry observations","description":"Retrieve all water chemistry observations from the database.","operationId":"get_water_chemistry_observations_observation_water_chemistry_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WaterChemistryObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/groundwater-level/{observation_id}":{"patch":{"tags":["observation"],"summary":"Update Groundwater Level Observation","description":"Update an existing groundwater level observation in the database.","operationId":"update_groundwater_level_observation_observation_groundwater_level__observation_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroundwaterLevelObservation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get groundwater level observation by ID","operationId":"get_groundwater_level_observation_by_id_observation_groundwater_level__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/water-chemistry/{observation_id}":{"patch":{"tags":["observation"],"summary":"Update Water Chemistry Observation","description":"Update an existing water chemistry observation in the database.","operationId":"update_water_chemistry_observation_observation_water_chemistry__observation_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWaterChemistryObservation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get water chemistry observation by ID","operationId":"get_water_chemistry_observation_by_id_observation_water_chemistry__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/transducer-groundwater-level":{"get":{"tags":["observation"],"summary":"Get transducer groundwater level observations","operationId":"get_transducer_groundwater_level_observations_observation_transducer_groundwater_level_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"parameter_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parameter Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_TransducerObservationWithBlockResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation":{"get":{"tags":["observation"],"summary":"Get all observations","operationId":"get_all_observations_observation_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/{observation_id}":{"get":{"tags":["observation"],"summary":"Get an observation by its ID","operationId":"get_observation_by_id_observation__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["observation"],"summary":"Delete an observation","operationId":"delete_observation_observation__observation_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/publication/add":{"post":{"tags":["publication"],"summary":"Post Publication","description":"Add a new publication.","operationId":"post_publication_publication_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePublication"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2AuthorizationCodeBearer":[]}]}},"/sample":{"post":{"tags":["sample"],"summary":"Add Sample","description":"Endpoint to add a sample.","operationId":"add_sample_sample_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSample"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SampleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sample"],"summary":"Get Samples","description":"Endpoint to retrieve samples.","operationId":"get_samples_sample_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SampleResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sample/{sample_id}":{"patch":{"tags":["sample"],"summary":"Update Sample","description":"Endpoint to update a sample.","operationId":"update_sample_sample__sample_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSample"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SampleResponse"},{"$ref":"#/components/schemas/ResourceNotFoundResponse"}],"title":"Response Update Sample Sample Sample Id Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sample"],"summary":"Get Sample by ID","description":"Endpoint to retrieve a sample by its ID.","operationId":"get_sample_by_id_sample__sample_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SampleResponse"},{"$ref":"#/components/schemas/ResourceNotFoundResponse"}],"title":"Response Get Sample By Id Sample Sample Id Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sample"],"summary":"Delete Sample by ID","operationId":"delete_sample_by_id_sample__sample_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sensor":{"post":{"tags":["sensor"],"summary":"Add Sensor","description":"Add a sensor to the system.","operationId":"add_sensor_sensor_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSensor"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sensor"],"summary":"Get Sensors","description":"Retrieve all sensors from the system.\nThis endpoint is a placeholder and should be implemented with actual logic.","operationId":"get_sensors_sensor_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"parameter_id","in":"query","required":false,"schema":{"type":"integer","title":"Parameter Id"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SensorResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sensor/{sensor_id}":{"patch":{"tags":["sensor"],"summary":"Update Sensor","description":"Update a sensor in the system.","operationId":"update_sensor_sensor__sensor_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSensor"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sensor"],"summary":"Delete Sensor","description":"Delete a sensor in the system","operationId":"delete_sensor_sensor__sensor_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sensor"],"summary":"Get Sensor","description":"Retrieve a sensor by its ID.","operationId":"get_sensor_sensor__sensor_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search":{"get":{"tags":["search"],"summary":"Search Api","description":"Search endpoint for the collaborative network.","operationId":"search_api_search_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"title":"Limit"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_dict_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well":{"get":{"tags":["thing"],"summary":"Get all water wells","description":"Retrieve all wells from the database.","operationId":"get_water_wells_thing_water_well_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"name","in":"query","required":false,"schema":{"type":"string","title":"Name"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a water well","description":"Create a new water well in the database.","operationId":"create_well_thing_water_well_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWell"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}":{"get":{"tags":["thing"],"summary":"Get water well by ID","description":"Retrieve a water well by ID from the database.","operationId":"get_well_by_id_thing_water_well__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update well by parent thing ID","description":"Update an existing well by ID.","operationId":"update_water_well_thing_water_well__thing_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWell"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}/well-screen":{"get":{"tags":["thing"],"summary":"Get well screens by water well ID","description":"Retrieve all well screens for a specific water well by its ID.","operationId":"get_well_screens_by_well_id_thing_water_well__thing_id__well_screen_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellScreenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen":{"get":{"tags":["thing"],"summary":"Get well screens","description":"Retrieve all well screens from the database.","operationId":"get_well_screens_thing_well_screen_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellScreenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new well screen","description":"Create a new well screen in the database.","operationId":"create_wellscreen_thing_well_screen_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWellScreen"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen/{wellscreen_id}":{"get":{"tags":["thing"],"summary":"Get well screen by ID","description":"Retrieve a well screen by ID from the database.","operationId":"get_well_screen_by_id_thing_well_screen__wellscreen_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"wellscreen_id","in":"path","required":true,"schema":{"type":"integer","title":"Wellscreen Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/spring":{"get":{"tags":["thing"],"summary":"Get all springs","description":"Retrieve all springs from the database.","operationId":"get_springs_thing_spring_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SpringResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new spring","description":"Create a new well in the database.","operationId":"create_spring_thing_spring_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpring"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/spring/{thing_id}":{"get":{"tags":["thing"],"summary":"Get spring by ID","description":"Retrieve a spring by ID from the database.","operationId":"get_spring_by_id_thing_spring__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update spring by parent thing ID","description":"Update an existing spring by ID.","operationId":"update_spring_thing_spring__thing_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpring"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/id-link":{"get":{"tags":["thing"],"summary":"Get all thing links","description":"Retrieve all thing links, optionally filtered and sorted.","operationId":"get_thing_id_links_thing_id_link_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingIdLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new thing link","description":"Create a new link between a thing and an alternate ID.","operationId":"create_thing_id_link_thing_id_link_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThingIdLink"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/id-link/{link_id}":{"get":{"tags":["thing"],"summary":"Get thing links by link ID","description":"Retrieve all links for a specific thing by its ID.","operationId":"get_thing_id_links_thing_id_link__link_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update thing link by ID","operationId":"update_thing_id_link_thing_id_link__link_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateThingIdLink"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete thing link by ID","description":"Delete a thing link by ID.","operationId":"delete_thing_id_link_thing_id_link__link_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing":{"get":{"tags":["thing"],"summary":"Get all things","description":"Retrieve all things or filter by type.","operationId":"get_things_thing_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"within","in":"query","required":false,"schema":{"type":"string","title":"Within"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}":{"get":{"tags":["thing"],"summary":"Get thing by ID","description":"Retrieve a thing by ID from the database.","operationId":"get_thing_by_id_thing__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete thing by ID","description":"Delete a thing by ID.","operationId":"delete_thing_thing__thing_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}/id-link":{"get":{"tags":["thing"],"summary":"Get thing links by thing ID","description":"Retrieve all links for a specific thing by its ID.","operationId":"get_thing_id_links_thing__thing_id__id_link_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingIdLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}/deployment":{"get":{"tags":["thing"],"summary":"Get deployments by thing ID","description":"Retrieve all deployments for a specific thing by its ID.","operationId":"get_thing_deployments_thing__thing_id__deployment_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_DeploymentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen/{well_screen_id}":{"patch":{"tags":["thing"],"summary":"Update Well Screen by ID","operationId":"update_well_screen_thing_well_screen__well_screen_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"well_screen_id","in":"path","required":true,"schema":{"type":"integer","title":"Well Screen Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWellScreen"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete well screen by ID","description":"Delete a well screen by ID.","operationId":"delete_well_screen_thing_well_screen__well_screen_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"well_screen_id","in":"path","required":true,"schema":{"type":"integer","title":"Well Screen Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AddressResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"address_line_1":{"type":"string","title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State"},"postal_code":{"type":"string","title":"Postal Code"},"country":{"type":"string","title":"Country"},"address_type":{"$ref":"#/components/schemas/address_type"}},"type":"object","required":["id","created_at","release_status","contact_id","address_line_1","city","state","postal_code","country","address_type"],"title":"AddressResponse","description":"Response schema for address details."},"AssetResponse":{"properties":{"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"storage_path":{"type":"string","title":"Storage Path"},"mime_type":{"type":"string","title":"Mime Type"},"size":{"type":"integer","title":"Size"},"uri":{"type":"string","title":"Uri"},"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"storage_service":{"type":"string","title":"Storage Service"},"signed_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed Url"}},"type":"object","required":["name","storage_path","mime_type","size","uri","id","created_at","release_status","storage_service"],"title":"AssetResponse"},"AuthorResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"affiliation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Affiliation"}},"type":"object","required":["id","name"],"title":"AuthorResponse","description":"Schema for the response of an author."},"Body_upload_asset_asset_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_asset_asset_upload_post"},"ContactResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"role":{"$ref":"#/components/schemas/role"},"contact_type":{"$ref":"#/components/schemas/contact_type"},"emails":{"items":{"$ref":"#/components/schemas/EmailResponse"},"type":"array","title":"Emails","default":[]},"phones":{"items":{"$ref":"#/components/schemas/PhoneResponse"},"type":"array","title":"Phones","default":[]},"addresses":{"items":{"$ref":"#/components/schemas/AddressResponse"},"type":"array","title":"Addresses","default":[]},"things":{"items":{"$ref":"#/components/schemas/ThingResponse"},"type":"array","title":"Things","default":[]}},"type":"object","required":["id","created_at","release_status","name","organization","role","contact_type"],"title":"ContactResponse","description":"Response schema for contact details."},"CreateAddress":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"address_line_1":{"type":"string","title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"type":"string","title":"City"},"state":{"type":"string","title":"State","default":"NM"},"postal_code":{"type":"string","title":"Postal Code"},"country":{"type":"string","title":"Country","default":"United States"},"address_type":{"$ref":"#/components/schemas/address_type","default":"Primary"}},"type":"object","required":["address_line_1","city","postal_code"],"title":"CreateAddress","description":"Schema for creating an address."},"CreateAsset":{"properties":{"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"storage_path":{"type":"string","title":"Storage Path"},"mime_type":{"type":"string","title":"Mime Type"},"size":{"type":"integer","title":"Size"},"uri":{"type":"string","title":"Uri"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},"type":"object","required":["name","storage_path","mime_type","size","uri"],"title":"CreateAsset"},"CreateContact":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"type":"integer","title":"Thing Id"},"role":{"$ref":"#/components/schemas/role"},"contact_type":{"$ref":"#/components/schemas/contact_type","default":"Primary"},"emails":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateEmail"},"type":"array"},{"type":"null"}],"title":"Emails"},"phones":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreatePhone"},"type":"array"},{"type":"null"}],"title":"Phones"},"addresses":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateAddress"},"type":"array"},{"type":"null"}],"title":"Addresses"}},"type":"object","required":["thing_id","role"],"title":"CreateContact","description":"Schema for creating a contact."},"CreateEmail":{"properties":{"email":{"type":"string","title":"Email"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"email_type":{"$ref":"#/components/schemas/email_type","default":"Primary"}},"type":"object","required":["email"],"title":"CreateEmail","description":"Schema for creating an email."},"CreateGroundwaterLevelObservation":{"properties":{"parameter_id":{"type":"integer","title":"Parameter Id"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"type":"integer","title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]},"measuring_point_height":{"type":"number","title":"Measuring Point Height"},"groundwater_level_reason":{"type":"string","title":"Groundwater Level Reason"}},"type":"object","required":["parameter_id","observation_datetime","sample_id","sensor_id","value","unit","measuring_point_height","groundwater_level_reason"],"title":"CreateGroundwaterLevelObservation"},"CreateGroup":{"properties":{"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"CreateGroup","description":"Schema for creating a group."},"CreateLexiconCategory":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"CreateLexiconCategory","description":"Pydantic model for creating a lexicon category.\nThis model can be extended to include additional fields as needed."},"CreateLexiconTerm":{"properties":{"term":{"type":"string","title":"Term"},"definition":{"type":"string","title":"Definition"},"categories":{"items":{"type":"string"},"type":"array","title":"Categories"}},"type":"object","required":["term","definition","categories"],"title":"CreateLexiconTerm","description":"Pydantic model for creating a lexicon term.\nThis model can be extended to include additional fields as needed."},"CreateLexiconTriple":{"properties":{"subject":{"$ref":"#/components/schemas/CreateLexiconTerm"},"predicate":{"type":"string","title":"Predicate"},"object_":{"$ref":"#/components/schemas/CreateLexiconTerm"}},"type":"object","required":["subject","predicate","object_"],"title":"CreateLexiconTriple","description":"Pydantic model for creating a triple.\nThis model can be extended to include additional fields as needed."},"CreateLocation":{"properties":{"point":{"type":"string","title":"Point"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"elevation":{"type":"number","title":"Elevation"},"elevation_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation Accuracy"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"coordinate_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Coordinate Accuracy"},"coordinate_method":{"anyOf":[{"$ref":"#/components/schemas/coordinate_method"},{"type":"null"}]}},"type":"object","required":["point","elevation"],"title":"CreateLocation","description":"Schema for creating a sample location."},"CreatePhone":{"properties":{"phone_number":{"type":"string","title":"Phone Number"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"phone_type":{"$ref":"#/components/schemas/phone_type","default":"Primary"},"nma_phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Phone Number"}},"type":"object","required":["phone_number"],"title":"CreatePhone","description":"Schema for creating a phone number."},"CreatePublication":{"properties":{"title":{"type":"string","title":"Title"},"authors":{"items":{"type":"string"},"type":"array","title":"Authors"},"year":{"type":"integer","title":"Year"},"doi":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Doi"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"publication_type":{"$ref":"#/components/schemas/publication_type"}},"type":"object","required":["title","authors","year","publication_type"],"title":"CreatePublication","description":"Schema for creating a new publication."},"CreateSample":{"properties":{"sample_date":{"type":"string","format":"date-time","title":"Sample Date"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"field_activity_id":{"type":"integer","title":"Field Activity Id"},"field_event_participant_id":{"type":"integer","title":"Field Event Participant Id"},"sample_name":{"type":"string","title":"Sample Name"},"sample_matrix":{"$ref":"#/components/schemas/sample_matrix"},"sample_method":{"$ref":"#/components/schemas/sample_method"},"qc_type":{"$ref":"#/components/schemas/qc_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["sample_date","field_activity_id","field_event_participant_id","sample_name","sample_matrix","sample_method","qc_type"],"title":"CreateSample"},"CreateSensor":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"name":{"type":"string","title":"Name"},"sensor_type":{"$ref":"#/components/schemas/sensor_type"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["name","sensor_type"],"title":"CreateSensor","description":"Schema for creating a new sensor."},"CreateSpring":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"location_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Location Id"},"group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group Id"},"name":{"type":"string","title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"spring_type":{"anyOf":[{"$ref":"#/components/schemas/spring_type"},{"type":"null"}]}},"type":"object","required":["location_id","name"],"title":"CreateSpring","description":"Schema for creating a spring."},"CreateThingIdLink":{"properties":{"thing_id":{"type":"integer","title":"Thing Id"},"relation":{"type":"string","title":"Relation"},"alternate_id":{"type":"string","title":"Alternate Id"},"alternate_organization":{"type":"string","title":"Alternate Organization"}},"type":"object","required":["thing_id","relation","alternate_id","alternate_organization"],"title":"CreateThingIdLink","description":"Schema for creating a link between a thing and its ID."},"CreateWaterChemistryObservation":{"properties":{"parameter_id":{"type":"integer","title":"Parameter Id"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"type":"integer","title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","required":["parameter_id","observation_datetime","sample_id","sensor_id","value","unit"],"title":"CreateWaterChemistryObservation"},"CreateWell":{"properties":{"well_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Depth","description":"Well depth in feet"},"hole_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Hole Depth","description":"Hole depth in feet"},"well_casing_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Casing Depth","description":"Well casing depth in feet"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"location_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Location Id"},"group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group Id"},"name":{"type":"string","title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"well_purposes":{"anyOf":[{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array"},{"type":"null"}],"title":"Well Purposes"},"well_construction_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Notes"},"well_casing_diameter":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Casing Diameter","description":"Well casing diameter in inches"},"well_casing_materials":{"anyOf":[{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array"},{"type":"null"}],"title":"Well Casing Materials"}},"type":"object","required":["location_id","name"],"title":"CreateWell","description":"Schema for creating a well."},"CreateWellScreen":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"type":"integer","title":"Thing Id"},"screen_depth_bottom":{"type":"number","exclusiveMinimum":0.0,"title":"Screen Depth Bottom","description":"Screen depth bottom in feet"},"screen_depth_top":{"type":"number","exclusiveMinimum":0.0,"title":"Screen Depth Top","description":"Screen depth top in feet"},"screen_type":{"anyOf":[{"$ref":"#/components/schemas/screen_type"},{"type":"null"}]},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"}},"type":"object","required":["thing_id","screen_depth_bottom","screen_depth_top"],"title":"CreateWellScreen","description":"Schema for creating a well screen."},"DeploymentResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"sensor":{"$ref":"#/components/schemas/SensorResponse"},"installation_date":{"type":"string","format":"date","title":"Installation Date"},"removal_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Removal Date"},"recording_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Recording Interval"},"recording_interval_units":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Interval Units"},"hanging_cable_length":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hanging Cable Length"},"hanging_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hanging Point Height"},"hanging_point_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hanging Point Description"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","thing_id","sensor","installation_date","removal_date","recording_interval","recording_interval_units","hanging_cable_length","hanging_point_height","hanging_point_description","notes"],"title":"DeploymentResponse"},"EmailResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"email":{"type":"string","title":"Email"},"email_type":{"$ref":"#/components/schemas/email_type"}},"type":"object","required":["id","created_at","release_status","contact_id","email","email_type"],"title":"EmailResponse","description":"Response schema for email details."},"Feature":{"properties":{"type":{"type":"string","title":"Type","default":"Feature"},"geometry":{"$ref":"#/components/schemas/GeoJSONGeometry"},"properties":{"additionalProperties":true,"type":"object","title":"Properties","default":{}}},"type":"object","required":["geometry"],"title":"Feature","description":"Feature schema for GeoJSON response."},"FeatureCollectionResponse":{"properties":{"type":{"type":"string","title":"Type","default":"FeatureCollection"},"features":{"items":{"$ref":"#/components/schemas/Feature"},"type":"array","title":"Features","default":[]}},"type":"object","title":"FeatureCollectionResponse","description":"Response schema for GeoJSON FeatureCollection."},"FieldActivityResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"field_event_id":{"type":"integer","title":"Field Event Id"},"activity_type":{"$ref":"#/components/schemas/activity_type"}},"type":"object","required":["id","created_at","release_status","field_event_id","activity_type"],"title":"FieldActivityResponse"},"FieldEventResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"event_date":{"type":"string","format":"date-time","title":"Event Date"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","thing_id","event_date","notes"],"title":"FieldEventResponse"},"GeoJSONGeometry":{"properties":{"type":{"type":"string","title":"Type"},"coordinates":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},{"items":{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},"type":"array"},{"items":{"items":{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},"type":"array"},"type":"array"}],"title":"Coordinates"}},"type":"object","required":["type","coordinates"],"title":"GeoJSONGeometry","description":"Geometry schema for GeoJSON response."},"GroundwaterLevelObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"},"depth_to_water_bgs":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth To Water Bgs"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit","depth_to_water_bgs","measuring_point_height","groundwater_level_reason"],"title":"GroundwaterLevelObservationResponse"},"GroupResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"}},"type":"object","required":["id","created_at","release_status","name","project_area","description","parent_group_id"],"title":"GroupResponse","description":"Pydantic model for the response of a group.\nThis model can be extended to include additional fields as needed."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LexiconCategoryResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["id","created_at","name"],"title":"LexiconCategoryResponse","description":"Pydantic model for the response of a lexicon category.\nThis model can be extended to include additional fields as needed."},"LexiconTermResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"term":{"type":"string","title":"Term"},"definition":{"type":"string","title":"Definition"},"categories":{"items":{"$ref":"#/components/schemas/LexiconCategoryResponse"},"type":"array","title":"Categories","default":[]}},"type":"object","required":["id","created_at","term","definition"],"title":"LexiconTermResponse","description":"Pydantic model for the response of a lexicon term.\nThis model can be extended to include additional fields as needed."},"LexiconTripleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"subject":{"type":"string","title":"Subject"},"predicate":{"type":"string","title":"Predicate"},"object_":{"type":"string","title":"Object"}},"type":"object","required":["id","created_at","subject","predicate","object_"],"title":"LexiconTripleResponse"},"LocationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"point":{"type":"string","title":"Point"},"elevation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation"},"horizontal_datum":{"type":"string","title":"Horizontal Datum","default":"WGS84"},"vertical_datum":{"type":"string","title":"Vertical Datum","default":"NAVD88"},"elevation_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation Accuracy"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"coordinate_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Coordinate Accuracy"},"coordinate_method":{"anyOf":[{"$ref":"#/components/schemas/coordinate_method"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"county":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"County"},"quad_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quad Name"}},"type":"object","required":["id","created_at","release_status","notes","point","elevation","elevation_accuracy","elevation_method","coordinate_accuracy","coordinate_method","state","county","quad_name"],"title":"LocationResponse","description":"Response schema for sample location details."},"ObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"},"depth_to_water_bgs":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth To Water Bgs"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit","depth_to_water_bgs","measuring_point_height","groundwater_level_reason"],"title":"ObservationResponse","description":"Response model for observations.\nCombines groundwater level and geothermal observation responses."},"Page_AddressResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AddressResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[AddressResponse]"},"Page_AssetResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AssetResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[AssetResponse]"},"Page_ContactResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ContactResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ContactResponse]"},"Page_DeploymentResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DeploymentResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[DeploymentResponse]"},"Page_EmailResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/EmailResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[EmailResponse]"},"Page_GroundwaterLevelObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[GroundwaterLevelObservationResponse]"},"Page_GroupResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[GroupResponse]"},"Page_LexiconCategoryResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconCategoryResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconCategoryResponse]"},"Page_LexiconTermResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconTermResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconTermResponse]"},"Page_LexiconTripleResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconTripleResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconTripleResponse]"},"Page_LocationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LocationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LocationResponse]"},"Page_ObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ObservationResponse]"},"Page_PhoneResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PhoneResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[PhoneResponse]"},"Page_SampleResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SampleResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SampleResponse]"},"Page_SensorResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SensorResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SensorResponse]"},"Page_SpringResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SpringResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SpringResponse]"},"Page_ThingIdLinkResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ThingIdLinkResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ThingIdLinkResponse]"},"Page_ThingResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ThingResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ThingResponse]"},"Page_TransducerObservationWithBlockResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TransducerObservationWithBlockResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[TransducerObservationWithBlockResponse]"},"Page_WaterChemistryObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WaterChemistryObservationResponse]"},"Page_WellResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WellResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WellResponse]"},"Page_WellScreenResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WellScreenResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WellScreenResponse]"},"Page_dict_":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[dict]"},"ParameterResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"parameter_name":{"$ref":"#/components/schemas/parameter_name"},"matrix":{"type":"string","title":"Matrix"},"parameter_type":{"anyOf":[{"$ref":"#/components/schemas/parameter_type"},{"type":"null"}]},"cas_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cas Number"},"default_unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","required":["id","created_at","release_status","parameter_name","matrix","parameter_type","cas_number","default_unit"],"title":"ParameterResponse","description":"Pydantic model for the response of a parameter.\nThis model can be extended to include additional fields as needed."},"PhoneResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number"},"phone_type":{"type":"string","title":"Phone Type"},"nma_phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Phone Number"}},"type":"object","required":["id","created_at","release_status","contact_id","phone_type"],"title":"PhoneResponse","description":"Response schema for phone details."},"PublicationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"title":{"type":"string","title":"Title"},"authors":{"items":{"$ref":"#/components/schemas/AuthorResponse"},"type":"array","title":"Authors"},"year":{"type":"integer","title":"Year"},"doi":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Doi"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"publication_type":{"$ref":"#/components/schemas/publication_type"}},"type":"object","required":["id","title","authors","year","publication_type"],"title":"PublicationResponse","description":"Schema for the response of a publication."},"ResourceNotFoundResponse":{"properties":{"detail":{"type":"string","title":"Detail"}},"type":"object","required":["detail"],"title":"ResourceNotFoundResponse"},"SampleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing":{"$ref":"#/components/schemas/ThingResponse"},"field_event":{"$ref":"#/components/schemas/FieldEventResponse"},"field_activity":{"$ref":"#/components/schemas/FieldActivityResponse"},"contact":{"$ref":"#/components/schemas/ContactResponse"},"sample_date":{"type":"string","title":"Sample Date"},"sample_name":{"type":"string","title":"Sample Name"},"sample_matrix":{"$ref":"#/components/schemas/sample_matrix"},"sample_method":{"$ref":"#/components/schemas/sample_method"},"qc_type":{"$ref":"#/components/schemas/qc_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"}},"type":"object","required":["id","created_at","release_status","thing","field_event","field_activity","contact","sample_date","sample_name","sample_matrix","sample_method","qc_type","notes","depth_top","depth_bottom"],"title":"SampleResponse","description":"Developer's note\n\nThe frontend uses multiple fields for a thing, field_even, and field_activity,\nwhich is why full ThingResponse, FieldEventResponse, and FieldActivityResponse\nare returned. If the response becomes too large and slow, we can use\n.model_dump() and exlude fields to reduce the size."},"SensorResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"sensor_type":{"$ref":"#/components/schemas/sensor_type"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","name","sensor_type","model","serial_no","pcn_number","owner_agency","sensor_status","notes"],"title":"SensorResponse"},"SpringResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"anyOf":[{"$ref":"#/components/schemas/LocationResponse"},{"type":"null"}]},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date"],"title":"SpringResponse","description":"Response schema for spring details."},"ThingIdLinkResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"thing":{"$ref":"#/components/schemas/ThingResponse"},"relation":{"type":"string","title":"Relation"},"alternate_id":{"type":"string","title":"Alternate Id"},"alternate_organization":{"type":"string","title":"Alternate Organization"}},"type":"object","required":["id","created_at","release_status","thing_id","thing","relation","alternate_id","alternate_organization"],"title":"ThingIdLinkResponse"},"ThingResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"anyOf":[{"$ref":"#/components/schemas/LocationResponse"},{"type":"null"}]},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"},"well_purposes":{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array","title":"Well Purposes","default":[]},"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"well_depth_unit":{"type":"string","title":"Well Depth Unit","default":"ft"},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"hole_depth_unit":{"type":"string","title":"Hole Depth Unit","default":"ft"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_diameter_unit":{"type":"string","title":"Well Casing Diameter Unit","default":"in"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"well_casing_depth_unit":{"type":"string","title":"Well Casing Depth Unit","default":"ft"},"well_casing_materials":{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array","title":"Well Casing Materials","default":[]},"well_construction_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Notes"}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date"],"title":"ThingResponse"},"TransducerObservationBlockResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"review_status":{"$ref":"#/components/schemas/review_status"},"start_datetime":{"type":"string","format":"date-time","title":"Start Datetime"},"end_datetime":{"type":"string","format":"date-time","title":"End Datetime"},"parameter_id":{"type":"integer","title":"Parameter Id"}},"type":"object","required":["id","created_at","release_status","review_status","start_datetime","end_datetime","parameter_id"],"title":"TransducerObservationBlockResponse"},"TransducerObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"value":{"type":"number","title":"Value"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"parameter_id":{"type":"integer","title":"Parameter Id"},"deployment_id":{"type":"integer","title":"Deployment Id"}},"type":"object","required":["id","created_at","release_status","value","observation_datetime","parameter_id","deployment_id"],"title":"TransducerObservationResponse"},"TransducerObservationWithBlockResponse":{"properties":{"observation":{"$ref":"#/components/schemas/TransducerObservationResponse"},"block":{"$ref":"#/components/schemas/TransducerObservationBlockResponse"}},"type":"object","required":["observation","block"],"title":"TransducerObservationWithBlockResponse"},"UpdateAddress":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"address_line_1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"address_type":{"anyOf":[{"$ref":"#/components/schemas/address_type"},{"type":"null"}]}},"type":"object","title":"UpdateAddress","description":"Schema for updating address information."},"UpdateAsset":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","title":"UpdateAsset"},"UpdateContact":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"role":{"anyOf":[{"$ref":"#/components/schemas/role"},{"type":"null"}]},"contact_type":{"anyOf":[{"$ref":"#/components/schemas/contact_type"},{"type":"null"}]},"thing_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},"type":"object","title":"UpdateContact","description":"Schema for updating contact information."},"UpdateEmail":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"email_type":{"anyOf":[{"$ref":"#/components/schemas/email_type"},{"type":"null"}]}},"type":"object","title":"UpdateEmail","description":"Schema for updating email information."},"UpdateGroundwaterLevelObservation":{"properties":{"parameter_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parameter Id"},"observation_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Observation Datetime"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"sample_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","title":"UpdateGroundwaterLevelObservation"},"UpdateGroup":{"properties":{"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","title":"UpdateGroup","description":"Pydantic model for updating a group.\nThis model can be extended to include additional fields as needed."},"UpdateLexiconCategory":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"UpdateLexiconCategory"},"UpdateLexiconTerm":{"properties":{"term":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Term"},"definition":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Definition"}},"type":"object","title":"UpdateLexiconTerm"},"UpdateLexiconTriple":{"properties":{"subject":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject"},"predicate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Predicate"},"object_":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Object"}},"type":"object","title":"UpdateLexiconTriple"},"UpdateLocation":{"properties":{"point":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Point"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"elevation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation"},"elevation_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation Accuracy"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"coordinate_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Coordinate Accuracy"},"coordinate_method":{"anyOf":[{"$ref":"#/components/schemas/coordinate_method"},{"type":"null"}]}},"type":"object","title":"UpdateLocation","description":"Schema for updating a location."},"UpdatePhone":{"properties":{"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"phone_type":{"anyOf":[{"$ref":"#/components/schemas/phone_type"},{"type":"null"}]}},"type":"object","title":"UpdatePhone","description":"Schema for updating phone information."},"UpdateSample":{"properties":{"sample_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sample Date"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"field_activity_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Field Activity Id"},"field_event_participant_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Field Event Participant Id"},"sample_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Name"},"sample_matrix":{"anyOf":[{"$ref":"#/components/schemas/sample_matrix"},{"type":"null"}]},"sample_method":{"anyOf":[{"$ref":"#/components/schemas/sample_method"},{"type":"null"}]},"qc_type":{"anyOf":[{"$ref":"#/components/schemas/qc_type"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdateSample"},"UpdateSensor":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"sensor_type":{"anyOf":[{"$ref":"#/components/schemas/sensor_type"},{"type":"null"}]},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdateSensor"},"UpdateSpring":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"}},"type":"object","title":"UpdateSpring"},"UpdateThingIdLink":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"alternate_organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alternate Organization"},"alternate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alternate Id"},"relation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation"}},"type":"object","title":"UpdateThingIdLink"},"UpdateWaterChemistryObservation":{"properties":{"parameter_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parameter Id"},"observation_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Observation Datetime"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"sample_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","title":"UpdateWaterChemistryObservation"},"UpdateWell":{"properties":{"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"well_purposes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Well Purposes"},"well_construction_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Notes"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_materials":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Well Casing Materials"}},"type":"object","title":"UpdateWell"},"UpdateWellScreen":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"screen_depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Bottom"},"screen_depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Top"},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"},"screen_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Type"}},"type":"object","title":"UpdateWellScreen"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WaterChemistryObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit"],"title":"WaterChemistryObservationResponse"},"WellResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"anyOf":[{"$ref":"#/components/schemas/LocationResponse"},{"type":"null"}]},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"well_purposes":{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array","title":"Well Purposes","default":[]},"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"well_depth_unit":{"type":"string","title":"Well Depth Unit","default":"ft"},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"hole_depth_unit":{"type":"string","title":"Hole Depth Unit","default":"ft"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_diameter_unit":{"type":"string","title":"Well Casing Diameter Unit","default":"in"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"well_casing_depth_unit":{"type":"string","title":"Well Casing Depth Unit","default":"ft"},"well_casing_materials":{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array","title":"Well Casing Materials","default":[]},"well_construction_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Notes"}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date"],"title":"WellResponse","description":"Response schema for well details."},"WellScreenResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"thing":{"$ref":"#/components/schemas/WellResponse"},"screen_depth_bottom":{"type":"number","title":"Screen Depth Bottom"},"screen_depth_bottom_unit":{"type":"string","title":"Screen Depth Bottom Unit","default":"ft"},"screen_depth_top":{"type":"number","title":"Screen Depth Top"},"screen_depth_top_unit":{"type":"string","title":"Screen Depth Top Unit","default":"ft"},"screen_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Type"},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"}},"type":"object","required":["id","created_at","release_status","thing_id","thing","screen_depth_bottom","screen_depth_top"],"title":"WellScreenResponse","description":"Response schema for well screen details."},"activity_type":{"type":"string","enum":["groundwater level","water chemistry"],"title":"activity_type"},"address_type":{"type":"string","enum":["Primary","Work","Personal","Mailing","Physical"],"title":"address_type"},"casing_material":{"type":"string","enum":["PVC","Steel","Concrete"],"title":"casing_material"},"contact_type":{"type":"string","enum":["Primary","Secondary","Field Event Participant"],"title":"contact_type"},"coordinate_method":{"type":"string","enum":["Unknown","Differentially corrected GPS","Survey-grade global positioning system (SGPS)","GPS, uncorrected","Interpolated from map","Interpolated from DEM","Reported","Transit, theodolite, or other survey method"],"title":"coordinate_method"},"elevation_method":{"type":"string","enum":["Altimeter","Differentially corrected GPS","Survey-grade GPS","Global positioning system (GPS)","LiDAR DEM","Level or other survey method","Interpolated from topographic map","Interpolated from digital elevation model (DEM)","Reported","Survey-grade Global Navigation Satellite Sys, Lvl1","USGS National Elevation Dataset (NED)","Unknown"],"title":"elevation_method"},"email_type":{"type":"string","enum":["Primary","Work","Personal"],"title":"email_type"},"parameter_name":{"type":"string","enum":["groundwater level","temperature","pH","Alkalinity, Total","Alkalinity as CaCO3","Alkalinity as OH-","Calcium","Calcium, total, unfiltered","Chloride","Carbonate","Conductivity, laboratory","Bicarbonate","Hardness (CaCO3)","Ion Balance","Potassium","Potassium, total, unfiltered","Magnesium","Magnesium, total, unfiltered","Sodium","Sodium, total, unfiltered","Sodium and Potassium combined","Sulfate","Total Anions","Total Cations","Total Dissolved Solids","Tritium","Age of Water using dissolved gases","Silver","Silver, total, unfiltered","Aluminum","Aluminum, total, unfiltered","Arsenic","Arsenic, total, unfiltered","Boron","Boron, total, unfiltered","Barium","Barium, total, unfiltered","Beryllium","Beryllium, total, unfiltered","Bromide","13C:12C ratio","14C content, pmc","Uncorrected C14 age","Cadmium","Cadmium, total, unfiltered","Chlorofluorocarbon-11 avg age","Chlorofluorocarbon-113 avg age","Chlorofluorocarbon-113/12 avg RATIO age","Chlorofluorocarbon-12 avg age","Cobalt","Cobalt, total, unfiltered","Chromium","Chromium, total, unfiltered","Copper","Copper, total, unfiltered","delta O18 sulfate","Sulfate 34 isotope ratio","Fluoride","Iron","Iron, total, unfiltered","Deuterium:Hydrogen ratio","Mercury","Mercury, total, unfiltered","Lithium","Lithium, total, unfiltered","Manganese","Manganese, total, unfiltered","Molybdenum","Molybdenum, total, unfiltered","Nickel","Nickel, total, unfiltered","Nitrite (as NO2)","Nitrite (as N)","Nitrate (as NO3)","Nitrate (as N)","18O:16O ratio","Lead","Lead, total, unfiltered","Phosphate","Antimony","Antimony, total, unfiltered","Selenium","Selenium, total, unfiltered","Sulfur hexafluoride","Silicon","Silicon, total, unfiltered","Silica","Tin","Tin, total, unfiltered","Strontium","Strontium, total, unfiltered","Strontium 87:86 ratio","Thorium","Thorium, total, unfiltered","Titanium","Titanium, total, unfiltered","Thallium","Thallium, total, unfiltered","Uranium (total, by ICP-MS)","Uranium, total, unfiltered","Vanadium","Vanadium, total, unfiltered","Zinc","Zinc, total, unfiltered","Corrected C14 in years","Arsenite (arsenic species)","Arsenate (arsenic species)","Cyanide","Estimated recharge temperature","Hydrogen sulfide","Ammonia","Ammonium","Total nitrogen","Total Kjeldahl nitrogen","Dissolved organic carbon","Total organic carbon","delta C13 of dissolved inorganic carbon"],"title":"parameter_name"},"parameter_type":{"type":"string","enum":["Field Parameter","Metal","Radionuclide","Major Element","Minor Element","Physical property"],"title":"parameter_type"},"phone_type":{"type":"string","enum":["Primary","Work","Home","Mobile"],"title":"phone_type"},"publication_type":{"type":"string","enum":["Map","Report","Dataset","Model","Software","Paper","Thesis","Book","Conference","Webpage"],"title":"publication_type"},"qc_type":{"type":"string","enum":["Normal","Duplicate","Split","Field Blank","Trip Blank","Equipment Blank"],"title":"qc_type"},"release_status":{"type":"string","enum":["draft","provisional","final","published","archived","public","private"],"title":"release_status"},"review_status":{"type":"string","enum":["approved","not reviewed"],"title":"review_status"},"role":{"type":"string","enum":["Unknown","Owner","Manager","Operator","Driller","Geologist","Hydrologist","Hydrogeologist","Engineer","Organization","Specialist","Technician","Research Assistant","Research Scientist","Graduate Student","Biologist","Lab Manager","Publications Manager","Software Developer"],"title":"role"},"sample_matrix":{"type":"string","enum":["water","groundwater","soil"],"title":"sample_matrix"},"sample_method":{"type":"string","enum":["Unknown","Airline measurement","Analog or graphic recorder","Calibrated airline measurement","Differential GPS; especially applicable to surface expression of ground water","Estimated","Transducer","Pressure-gage measurement","Calibrated pressure-gage measurement","Interpreted from geophysical logs","Manometer","Non-recording gage","Observed (required for F, N, and W water level status)","Sonic water level meter (acoustic pulse)","Reported, method not known","Steel-tape measurement","Electric tape measurement (E-probe)","Unknown (for legacy data only; not for new data entry)","Calibrated electric tape; accuracy of equipment has been checked","Calibrated electric cable","Uncalibrated electric cable","Continuous acoustic sounder","Measurement not attempted","null placeholder","bailer","faucet at well head","faucet or outlet at house","grab sample","pump","thief sampler"],"title":"sample_method"},"screen_type":{"type":"string","enum":["PVC","Steel","Concrete"],"title":"screen_type"},"sensor_type":{"type":"string","enum":["Pressure Transducer","Data Logger","Barometer","Acoustic Sounder","Precip Collector","Camera","Soil Moisture Sensor","Tipping Bucket"],"title":"sensor_type"},"spring_type":{"type":"string","enum":["Artesian","Ephemeral","Perennial","Thermal","Mineral"],"title":"spring_type"},"unit":{"type":"string","enum":["dimensionless","ft","ftbgs","F","mg/L","mW/m²","W/m²","W/m·K","m²/s","deg C","deg second","deg minute","second","minute","hour"],"title":"unit"},"well_purpose":{"type":"string","enum":["Unknown","Open, unequipped well","Commercial","Domestic","Power generation","Irrigation","Livestock","Mining","Industrial","Observation","Public supply","Shared domestic","Institutional","Unused","Exploration","Monitoring","Production","Injection"],"title":"well_purpose"}},"securitySchemes":{"OAuth2AuthorizationCodeBearer":{"type":"oauth2","flows":{"authorizationCode":{"scopes":{"openid":"openid","offline_access":"offline_access"},"authorizationUrl":"https://authentik.newmexicowaterdata.org/application/o/authorize/","tokenUrl":"https://authentik.newmexicowaterdata.org/application/o/token/"}}}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Ocotillo API (Full)","description":"Full API schema (authorized users)","version":"0.0.1"},"paths":{"/asset/upload":{"post":{"tags":["asset"],"summary":"Upload Asset","operationId":"upload_asset_asset_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_asset_asset_upload_post"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Upload Asset Asset Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2AuthorizationCodeBearer":[]}]}},"/asset":{"post":{"tags":["asset"],"summary":"Add Asset","operationId":"add_asset_asset_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAsset"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["asset"],"summary":"List Assets","description":"List all assets or assets associated with a specific thing.","operationId":"list_assets_asset_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AssetResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/{asset_id}":{"get":{"tags":["asset"],"summary":"Get Asset","description":"Retrieve an asset by its ID.","operationId":"get_asset_asset__asset_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["asset"],"summary":"Update Asset","description":"Update an existing asset.","operationId":"update_asset_asset__asset_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAsset"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["asset"],"summary":"Delete Asset","operationId":"delete_asset_asset__asset_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/{asset_id}/remove":{"delete":{"tags":["asset"],"summary":"Remove Asset","operationId":"remove_asset_asset__asset_id__remove_delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"integer","title":"Asset Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/author/{author_id}/publications":{"get":{"tags":["author"],"summary":"Get Author Publications","description":"Retrieve all publications for a specific author.","operationId":"get_author_publications_author__author_id__publications_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"author_id","in":"path","required":true,"schema":{"type":"integer","title":"Author Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicationResponse"},"title":"Response Get Author Publications Author Author Id Publications Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact":{"post":{"tags":["contact"],"summary":"Create a new contact","operationId":"create_contact_contact_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContact"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get contacts","description":"Retrieve all contacts from the database.\n:param session:\n:return:","operationId":"get_contacts_contact_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ContactResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/address":{"post":{"tags":["contact"],"summary":"Add an address to a contact","description":"Add a new address to an existing contact in the database.\n:param contact_id: ID of the contact to add the address to\n:param address_data: Data for the new address\n:param session: Database session\n:return: Response containing the added address","operationId":"create_address_contact_address_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAddress"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all addresses","description":"Retrieve all addresses from the database.\n:param session:\n:return:","operationId":"get_addresses_contact_address_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AddressResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/email":{"post":{"tags":["contact"],"summary":"Add an email to a contact","operationId":"create_email_contact_email_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmail"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all emails","description":"Retrieve all emails from the database.\n:param session:\n:return:","operationId":"get_emails_contact_email_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_EmailResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/phone":{"post":{"tags":["contact"],"summary":"Add a phone number to a contact","operationId":"create_phone_contact_phone_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePhone"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get all phones","description":"Retrieve all phone numbers from the database.\n:param session:\n:return:","operationId":"get_phones_contact_phone_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_PhoneResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/email/{email_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Email","description":"Update an existing contact's email in the database.","operationId":"update_contact_email_contact_email__email_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmail"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get email by ID","description":"Retrieve an email by ID from the database.","operationId":"get_email_by_id_contact_email__email_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact email","description":"Delete a contact email by ID from the database.","operationId":"delete_contact_email_contact_email__email_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"email_id","in":"path","required":true,"schema":{"type":"integer","title":"Email Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/phone/{phone_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Phone","description":"Update an existing contact's phone number in the database.\n:param contact_id: ID of the contact to update\n:param phone_type: Type of the phone to update\n:param phone_number: New phone number\n:param session: Database session\n:return: Updated contact response","operationId":"update_contact_phone_contact_phone__phone_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePhone"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get phone by ID","description":"Retrieve a phone by ID from the database.","operationId":"get_phone_by_id_contact_phone__phone_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact phone","description":"Delete a contact phone by ID from the database.","operationId":"delete_contact_phone_contact_phone__phone_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"phone_id","in":"path","required":true,"schema":{"type":"integer","title":"Phone Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/address/{address_id}":{"patch":{"tags":["contact"],"summary":"Update Contact Address","description":"Update an existing contact's address in the database.\n\n:param address_id:\n:param address_data:\n:param session:\n:return:","operationId":"update_contact_address_contact_address__address_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAddress"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get address by ID","description":"Retrieve an address by ID from the database.","operationId":"get_address_by_id_contact_address__address_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact address","description":"Delete a contact address by ID from the database.","operationId":"delete_contact_address_contact_address__address_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"address_id","in":"path","required":true,"schema":{"type":"integer","title":"Address Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}":{"patch":{"tags":["contact"],"summary":"Update contact","description":"Update an existing contact in the database.\n:param contact_id: ID of the contact to update\n:param contact_data: Data to update the contact with\n:param session: Database session\n:return: Updated contact response","operationId":"update_contact_contact__contact_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContact"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["contact"],"summary":"Get contact by ID","description":"Retrieve a contact by ID from the database.","operationId":"get_contact_by_id_contact__contact_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["contact"],"summary":"Delete contact","description":"Delete a contact by ID from the database.","operationId":"delete_contact_contact__contact_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/email":{"get":{"tags":["contact"],"summary":"Get contact emails","description":"Retrieve all emails associated with a contact.","operationId":"get_contact_emails_contact__contact_id__email_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_EmailResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/phone":{"get":{"tags":["contact"],"summary":"Get contact phones","description":"Retrieve all phone numbers associated with a contact.","operationId":"get_contact_phones_contact__contact_id__phone_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_PhoneResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/contact/{contact_id}/address":{"get":{"tags":["contact"],"summary":"Get contact addresses","description":"Retrieve all addresses associated with a contact.","operationId":"get_contact_addresses_contact__contact_id__address_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"integer","title":"Contact Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_AddressResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geospatial":{"get":{"tags":["geospatial"],"summary":"Get Geospatial","description":"Endpoint to retrieve a GeoJSON FeatureCollection or a shapefile.\nIf the request is for a shapefile, it will return a zip file containing the shapefile.\nOtherwise, it returns a GeoJSON FeatureCollection.","operationId":"get_geospatial_geospatial_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_type","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"title":"thing_type"}},{"name":"group","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"integer"}],"title":"group"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","pattern":"^(geojson|shapefile)$","title":"format","description":"Format of the response. 'geojson' for GeoJSON FeatureCollection, 'shapefile' for a shapefile.","default":"geojson"},"description":"Format of the response. 'geojson' for GeoJSON FeatureCollection, 'shapefile' for a shapefile."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geospatial/project-area/{group_id}":{"get":{"tags":["geospatial"],"summary":"Get project area for group","operationId":"get_project_area_geospatial_project_area__group_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureCollectionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/group":{"post":{"tags":["group"],"summary":"Create a new group","description":"Create a new group in the database.","operationId":"create_group_group_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroup"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["group"],"summary":"Get groups","description":"Retrieve all groups from the database.","operationId":"get_groups_group_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/group/{group_id}":{"get":{"tags":["group"],"summary":"Get group by ID","description":"Retrieve a group by ID from the database.","operationId":"get_group_by_id_group__group_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["group"],"summary":"Update a group by ID","description":"Update a group by ID in the database.","operationId":"update_group_group__group_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroup"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["group"],"summary":"Delete a group by ID","operationId":"delete_group_group__group_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"integer","title":"Group Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/category":{"post":{"tags":["lexicon"],"summary":"Add Category","description":"Endpoint to add a category to the lexicon.","operationId":"add_category_lexicon_category_post","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconCategory"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Categories","description":"Endpoint to retrieve lexicon categories.","operationId":"get_lexicon_categories_lexicon_category_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"name","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"asc","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconCategoryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/term":{"post":{"tags":["lexicon"],"summary":"Add term","description":"Endpoint to add a term to the lexicon.","operationId":"add_term_lexicon_term_post","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconTerm"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get lexicon terms","description":"Endpoint to retrieve lexicon terms.","operationId":"get_lexicon_terms_lexicon_term_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"term","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Term"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconTermResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/triple":{"post":{"tags":["lexicon"],"summary":"Add triple","operationId":"add_triple_lexicon_triple_post","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLexiconTriple"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get lexicon triples","description":"Endpoint to retrieve lexicon triples.","operationId":"get_lexicon_triples_lexicon_triple_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"subject","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"asc","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LexiconTripleResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/term/{term_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Term","operationId":"update_lexicon_term_lexicon_term__term_id__patch","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconTerm"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Term","operationId":"get_lexicon_term_lexicon_term__term_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTermResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon term by ID","operationId":"delete_lexicon_term_lexicon_term__term_id__delete","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"term_id","in":"path","required":true,"schema":{"type":"integer","title":"Term Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/category/{category_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Category","operationId":"update_lexicon_category_lexicon_category__category_id__patch","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconCategory"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Category","operationId":"get_lexicon_category_lexicon_category__category_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconCategoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon category by ID","operationId":"delete_lexicon_category_lexicon_category__category_id__delete","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"category_id","in":"path","required":true,"schema":{"type":"integer","title":"Category Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lexicon/triple/{triple_id}":{"patch":{"tags":["lexicon"],"summary":"Update Lexicon Triple","operationId":"update_lexicon_triple_lexicon_triple__triple_id__patch","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLexiconTriple"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["lexicon"],"summary":"Get Lexicon Triple","operationId":"get_lexicon_triple_lexicon_triple__triple_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LexiconTripleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["lexicon"],"summary":"Delete a lexicon triple by ID","operationId":"delete_lexicon_triple_lexicon_triple__triple_id__delete","deprecated":true,"security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"triple_id","in":"path","required":true,"schema":{"type":"integer","title":"Triple Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/location":{"post":{"tags":["location"],"summary":"Create a new sample location","description":"Create a new sample location in the database.","operationId":"create_location_location_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLocation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["location"],"summary":"Get all locations","description":"Retrieve all wells from the database.","operationId":"get_location_location_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"nearby_point","in":"query","required":false,"schema":{"type":"string","title":"Nearby Point"}},{"name":"nearby_distance_km","in":"query","required":false,"schema":{"type":"number","default":1,"title":"Nearby Distance Km"}},{"name":"within","in":"query","required":false,"schema":{"type":"string","title":"Within"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_LocationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/location/{location_id}":{"patch":{"tags":["location"],"summary":"Update a location","description":"Update a sample location in the database.","operationId":"update_location_location__location_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["location"],"summary":"Get location by ID","description":"Retrieve a sample location by ID from the database.","operationId":"get_location_by_id_location__location_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["location"],"summary":"Delete location by ID","description":"Delete a sample location by ID from the database.","operationId":"delete_location_location__location_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"location_id","in":"path","required":true,"schema":{"type":"integer","title":"Location Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/groundwater-level":{"post":{"tags":["observation"],"summary":"Add Groundwater Level Observation","description":"Add a new groundwater observation to the database.","operationId":"add_groundwater_level_observation_observation_groundwater_level_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroundwaterLevelObservation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get groundwater level observations","description":"Retrieve all groundwater level observations from the database.","operationId":"get_groundwater_level_observations_observation_groundwater_level_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_GroundwaterLevelObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/water-chemistry":{"post":{"tags":["observation"],"summary":"Add Water Chemistry Observation","description":"Add a new water chemistry observation to the database.\nThis endpoint is currently a placeholder and does not implement any functionality.","operationId":"add_water_chemistry_observation_observation_water_chemistry_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWaterChemistryObservation"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get water chemistry observations","description":"Retrieve all water chemistry observations from the database.","operationId":"get_water_chemistry_observations_observation_water_chemistry_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WaterChemistryObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/groundwater-level/bulk-upload":{"post":{"tags":["observation"],"summary":"Bulk Upload Groundwater Levels","operationId":"bulk_upload_groundwater_levels_observation_groundwater_level_bulk_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_upload_groundwater_levels_observation_groundwater_level_bulk_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterLevelBulkUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2AuthorizationCodeBearer":[]}]}},"/observation/groundwater-level/{observation_id}":{"patch":{"tags":["observation"],"summary":"Update Groundwater Level Observation","description":"Update an existing groundwater level observation in the database.","operationId":"update_groundwater_level_observation_observation_groundwater_level__observation_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroundwaterLevelObservation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get groundwater level observation by ID","operationId":"get_groundwater_level_observation_by_id_observation_groundwater_level__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/water-chemistry/{observation_id}":{"patch":{"tags":["observation"],"summary":"Update Water Chemistry Observation","description":"Update an existing water chemistry observation in the database.","operationId":"update_water_chemistry_observation_observation_water_chemistry__observation_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWaterChemistryObservation"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["observation"],"summary":"Get water chemistry observation by ID","operationId":"get_water_chemistry_observation_by_id_observation_water_chemistry__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/transducer-groundwater-level":{"get":{"tags":["observation"],"summary":"Get transducer groundwater level observations","operationId":"get_transducer_groundwater_level_observations_observation_transducer_groundwater_level_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_TransducerObservationWithBlockResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation":{"get":{"tags":["observation"],"summary":"Get all observations","operationId":"get_all_observations_observation_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sensor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"}},{"name":"sample_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"}},{"name":"start_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start Time"}},{"name":"end_time","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"End Time"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ObservationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/observation/{observation_id}":{"get":{"tags":["observation"],"summary":"Get an observation by its ID","operationId":"get_observation_by_id_observation__observation_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObservationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["observation"],"summary":"Delete an observation","operationId":"delete_observation_observation__observation_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"observation_id","in":"path","required":true,"schema":{"type":"integer","title":"Observation Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/publication/add":{"post":{"tags":["publication"],"summary":"Post Publication","description":"Add a new publication.","operationId":"post_publication_publication_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePublication"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2AuthorizationCodeBearer":[]}]}},"/sample":{"post":{"tags":["sample"],"summary":"Add Sample","description":"Endpoint to add a sample.","operationId":"add_sample_sample_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSample"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SampleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sample"],"summary":"Get Samples","description":"Endpoint to retrieve samples.","operationId":"get_samples_sample_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SampleResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sample/{sample_id}":{"patch":{"tags":["sample"],"summary":"Update Sample","description":"Endpoint to update a sample.","operationId":"update_sample_sample__sample_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSample"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SampleResponse"},{"$ref":"#/components/schemas/ResourceNotFoundResponse"}],"title":"Response Update Sample Sample Sample Id Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sample"],"summary":"Get Sample by ID","description":"Endpoint to retrieve a sample by its ID.","operationId":"get_sample_by_id_sample__sample_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SampleResponse"},{"$ref":"#/components/schemas/ResourceNotFoundResponse"}],"title":"Response Get Sample By Id Sample Sample Id Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sample"],"summary":"Delete Sample by ID","operationId":"delete_sample_by_id_sample__sample_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sample_id","in":"path","required":true,"schema":{"type":"integer","title":"Sample Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sensor":{"post":{"tags":["sensor"],"summary":"Add Sensor","description":"Add a sensor to the system.","operationId":"add_sensor_sensor_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSensor"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sensor"],"summary":"Get Sensors","description":"Retrieve all sensors from the system.\nThis endpoint is a placeholder and should be implemented with actual logic.","operationId":"get_sensors_sensor_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"parameter_id","in":"query","required":false,"schema":{"type":"integer","title":"Parameter Id"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SensorResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sensor/{sensor_id}":{"patch":{"tags":["sensor"],"summary":"Update Sensor","description":"Update a sensor in the system.","operationId":"update_sensor_sensor__sensor_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSensor"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sensor"],"summary":"Delete Sensor","description":"Delete a sensor in the system","operationId":"delete_sensor_sensor__sensor_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sensor"],"summary":"Get Sensor","description":"Retrieve a sensor by its ID.","operationId":"get_sensor_sensor__sensor_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sensor_id","in":"path","required":true,"schema":{"type":"integer","title":"Sensor Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search":{"get":{"tags":["search"],"summary":"Search Api","description":"Search endpoint for the collaborative network.","operationId":"search_api_search_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","title":"Q"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"title":"Limit"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_dict_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well":{"get":{"tags":["thing"],"summary":"Get all water wells","description":"Retrieve all wells from the database.","operationId":"get_water_wells_thing_water_well_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},{"name":"include_contacts","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Contacts"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a water well","description":"Create a new water well in the database.","operationId":"create_well_thing_water_well_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWell"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}":{"get":{"tags":["thing"],"summary":"Get water well by ID","description":"Retrieve a water well by ID from the database.","operationId":"get_well_by_id_thing_water_well__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update well by parent thing ID","description":"Update an existing well by ID.","operationId":"update_water_well_thing_water_well__thing_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWell"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}/details":{"get":{"tags":["thing"],"summary":"Get water well details payload","description":"Retrieve the consolidated payload needed to render the well details page.\nHydrograph series and map layer loading are intentionally handled separately.","operationId":"get_well_details_thing_water_well__thing_id__details_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"field_event_limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Field Event Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellDetailsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}/export":{"get":{"tags":["thing"],"summary":"Get water well export payload","description":"Retrieve the minimal payload needed for field sheet export generation.","operationId":"get_well_export_thing_water_well__thing_id__export_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellExportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/water-well/{thing_id}/well-screen":{"get":{"tags":["thing"],"summary":"Get well screens by water well ID","description":"Retrieve all well screens for a specific water well by its ID.","operationId":"get_well_screens_by_well_id_thing_water_well__thing_id__well_screen_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellScreenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen":{"get":{"tags":["thing"],"summary":"Get well screens","description":"Retrieve all well screens from the database.","operationId":"get_well_screens_thing_well_screen_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"query","required":false,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_WellScreenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new well screen","description":"Create a new well screen in the database.","operationId":"create_wellscreen_thing_well_screen_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWellScreen"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen/{wellscreen_id}":{"get":{"tags":["thing"],"summary":"Get well screen by ID","description":"Retrieve a well screen by ID from the database.","operationId":"get_well_screen_by_id_thing_well_screen__wellscreen_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"wellscreen_id","in":"path","required":true,"schema":{"type":"integer","title":"Wellscreen Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/spring":{"get":{"tags":["thing"],"summary":"Get all springs","description":"Retrieve all springs from the database.","operationId":"get_springs_thing_spring_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","title":"Query"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_SpringResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new spring","description":"Create a new well in the database.","operationId":"create_spring_thing_spring_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpring"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/spring/{thing_id}":{"get":{"tags":["thing"],"summary":"Get spring by ID","description":"Retrieve a spring by ID from the database.","operationId":"get_spring_by_id_thing_spring__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update spring by parent thing ID","description":"Update an existing spring by ID.","operationId":"update_spring_thing_spring__thing_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpring"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpringResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/id-link":{"get":{"tags":["thing"],"summary":"Get all thing links","description":"Retrieve all thing links, optionally filtered and sorted.","operationId":"get_thing_id_links_thing_id_link_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","title":"Order"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingIdLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["thing"],"summary":"Create a new thing link","description":"Create a new link between a thing and an alternate ID.","operationId":"create_thing_id_link_thing_id_link_post","security":[{"OAuth2AuthorizationCodeBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThingIdLink"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/id-link/{link_id}":{"get":{"tags":["thing"],"summary":"Get thing links by link ID","description":"Retrieve all links for a specific thing by its ID.","operationId":"get_thing_id_links_thing_id_link__link_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["thing"],"summary":"Update thing link by ID","operationId":"update_thing_id_link_thing_id_link__link_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateThingIdLink"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingIdLinkResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete thing link by ID","description":"Delete a thing link by ID.","operationId":"delete_thing_id_link_thing_id_link__link_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing":{"get":{"tags":["thing"],"summary":"Get all things","description":"Retrieve all things or filter by type.","operationId":"get_things_thing_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"within","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Within"}},{"name":"query","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"include_contacts","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Contacts"}},{"name":"filter","in":"query","required":false,"schema":{"type":"string","title":"Filter"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}":{"get":{"tags":["thing"],"summary":"Get thing by ID","description":"Retrieve a thing by ID from the database.","operationId":"get_thing_by_id_thing__thing_id__get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete thing by ID","description":"Delete a thing by ID.","operationId":"delete_thing_thing__thing_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}/id-link":{"get":{"tags":["thing"],"summary":"Get thing links by thing ID","description":"Retrieve all links for a specific thing by its ID.","operationId":"get_thing_id_links_thing__thing_id__id_link_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_ThingIdLinkResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/{thing_id}/deployment":{"get":{"tags":["thing"],"summary":"Get deployments by thing ID","description":"Retrieve all deployments for a specific thing by its ID.","operationId":"get_thing_deployments_thing__thing_id__deployment_get","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"thing_id","in":"path","required":true,"schema":{"type":"integer","title":"Thing Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":25,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Page_DeploymentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thing/well-screen/{well_screen_id}":{"patch":{"tags":["thing"],"summary":"Update Well Screen by ID","operationId":"update_well_screen_thing_well_screen__well_screen_id__patch","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"well_screen_id","in":"path","required":true,"schema":{"type":"integer","title":"Well Screen Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWellScreen"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WellScreenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["thing"],"summary":"Delete well screen by ID","description":"Delete a well screen by ID.","operationId":"delete_well_screen_thing_well_screen__well_screen_id__delete","security":[{"OAuth2AuthorizationCodeBearer":[]}],"parameters":[{"name":"well_screen_id","in":"path","required":true,"schema":{"type":"integer","title":"Well Screen Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ngwmn/waterlevels/{pointid}":{"get":{"tags":["NGWMN"],"summary":"Get waterlevels for a given pointid in the NGWMN format","operationId":"read_ngwmn_waterlevels_ngwmn_waterlevels__pointid__get","parameters":[{"name":"pointid","in":"path","required":true,"schema":{"type":"string","title":"Pointid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ngwmn/wellconstruction/{pointid}":{"get":{"tags":["NGWMN"],"summary":"Get wellconstruction for a given pointid in the NGWMN format","operationId":"read_ngwmn_wellconstruction_ngwmn_wellconstruction__pointid__get","parameters":[{"name":"pointid","in":"path","required":true,"schema":{"type":"string","title":"Pointid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ngwmn/lithology/{pointid}":{"get":{"tags":["NGWMN"],"summary":"Get lithology for a given pointid in the NGWMN format","operationId":"read_ngwmn_lithology_ngwmn_lithology__pointid__get","parameters":[{"name":"pointid","in":"path","required":true,"schema":{"type":"string","title":"Pointid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AddressResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"address_line_1":{"type":"string","title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"type":"string","title":"Country"},"address_type":{"$ref":"#/components/schemas/address_type"}},"type":"object","required":["id","created_at","release_status","contact_id","address_line_1","country","address_type"],"title":"AddressResponse","description":"Response schema for address details."},"AssetResponse":{"properties":{"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"storage_path":{"type":"string","title":"Storage Path"},"mime_type":{"type":"string","title":"Mime Type"},"size":{"type":"integer","title":"Size"},"uri":{"type":"string","title":"Uri"},"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"storage_service":{"type":"string","title":"Storage Service"},"signed_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed Url"}},"type":"object","required":["name","storage_path","mime_type","size","uri","id","created_at","release_status","storage_service"],"title":"AssetResponse"},"AuthorResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"affiliation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Affiliation"}},"type":"object","required":["id","name"],"title":"AuthorResponse","description":"Schema for the response of an author."},"Body_bulk_upload_groundwater_levels_observation_groundwater_level_bulk_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_bulk_upload_groundwater_levels_observation_groundwater_level_bulk_upload_post"},"Body_upload_asset_asset_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_asset_asset_upload_post"},"ContactResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"role":{"$ref":"#/components/schemas/role"},"contact_type":{"$ref":"#/components/schemas/contact_type"},"incomplete_nma_phones":{"items":{"type":"string"},"type":"array","title":"Incomplete Nma Phones","default":[]},"emails":{"items":{"$ref":"#/components/schemas/EmailResponse"},"type":"array","title":"Emails","default":[]},"phones":{"items":{"$ref":"#/components/schemas/PhoneResponse"},"type":"array","title":"Phones","default":[]},"addresses":{"items":{"$ref":"#/components/schemas/AddressResponse"},"type":"array","title":"Addresses","default":[]},"things":{"items":{"$ref":"#/components/schemas/ThingResponseForContact"},"type":"array","title":"Things","default":[]},"communication_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Communication Notes","default":[]},"general_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"General Notes","default":[]}},"type":"object","required":["id","created_at","release_status","name","organization","role","contact_type"],"title":"ContactResponse","description":"Response schema for contact details."},"CreateAddress":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"address_line_1":{"type":"string","title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State","default":"NM"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"type":"string","title":"Country","default":"United States"},"address_type":{"$ref":"#/components/schemas/address_type","default":"Primary"}},"type":"object","required":["address_line_1"],"title":"CreateAddress","description":"Schema for creating an address."},"CreateAsset":{"properties":{"name":{"type":"string","title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"storage_path":{"type":"string","title":"Storage Path"},"mime_type":{"type":"string","title":"Mime Type"},"size":{"type":"integer","title":"Size"},"uri":{"type":"string","title":"Uri"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},"type":"object","required":["name","storage_path","mime_type","size","uri"],"title":"CreateAsset"},"CreateContact":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"type":"integer","title":"Thing Id"},"role":{"$ref":"#/components/schemas/role"},"contact_type":{"$ref":"#/components/schemas/contact_type"},"nma_pk_owners":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Pk Owners"},"emails":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateEmail"},"type":"array"},{"type":"null"}],"title":"Emails"},"phones":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreatePhone"},"type":"array"},{"type":"null"}],"title":"Phones"},"addresses":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateAddress"},"type":"array"},{"type":"null"}],"title":"Addresses"},"notes":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateNote"},"type":"array"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["thing_id","role","contact_type"],"title":"CreateContact","description":"Schema for creating a contact."},"CreateEmail":{"properties":{"email":{"type":"string","title":"Email"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"email_type":{"$ref":"#/components/schemas/email_type","default":"Primary"}},"type":"object","required":["email"],"title":"CreateEmail","description":"Schema for creating an email."},"CreateGroundwaterLevelObservation":{"properties":{"parameter_id":{"type":"integer","title":"Parameter Id"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"type":"integer","title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]},"measuring_point_height":{"type":"number","title":"Measuring Point Height"},"groundwater_level_reason":{"type":"string","title":"Groundwater Level Reason"}},"type":"object","required":["parameter_id","observation_datetime","sample_id","sensor_id","value","unit","measuring_point_height","groundwater_level_reason"],"title":"CreateGroundwaterLevelObservation"},"CreateGroup":{"properties":{"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"CreateGroup","description":"Schema for creating a group."},"CreateLexiconCategory":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"CreateLexiconCategory","description":"Pydantic model for creating a lexicon category.\nThis model can be extended to include additional fields as needed."},"CreateLexiconTerm":{"properties":{"term":{"type":"string","title":"Term"},"definition":{"type":"string","title":"Definition"},"categories":{"items":{"type":"string"},"type":"array","title":"Categories"}},"type":"object","required":["term","definition","categories"],"title":"CreateLexiconTerm","description":"Pydantic model for creating a lexicon term.\nThis model can be extended to include additional fields as needed."},"CreateLexiconTriple":{"properties":{"subject":{"$ref":"#/components/schemas/CreateLexiconTerm"},"predicate":{"type":"string","title":"Predicate"},"object_":{"$ref":"#/components/schemas/CreateLexiconTerm"}},"type":"object","required":["subject","predicate","object_"],"title":"CreateLexiconTriple","description":"Pydantic model for creating a triple.\nThis model can be extended to include additional fields as needed."},"CreateLocation":{"properties":{"point":{"type":"string","title":"Point"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"notes":{"items":{"$ref":"#/components/schemas/CreateNote"},"type":"array","title":"Notes","default":[]},"elevation":{"type":"number","title":"Elevation"}},"type":"object","required":["point","elevation"],"title":"CreateLocation","description":"Schema for creating a sample location."},"CreateMonitoringFrequency":{"properties":{"monitoring_frequency":{"$ref":"#/components/schemas/monitoring_frequency"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date"}},"type":"object","required":["monitoring_frequency","start_date"],"title":"CreateMonitoringFrequency"},"CreateNote":{"properties":{"note_type":{"$ref":"#/components/schemas/note_type"},"content":{"type":"string","title":"Content"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"}},"type":"object","required":["note_type","content"],"title":"CreateNote","description":"Schema for creating a new Note. The parent object's ID and type will be\ntaken from the URL path, not the request body."},"CreatePhone":{"properties":{"phone_number":{"type":"string","title":"Phone Number"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"phone_type":{"$ref":"#/components/schemas/phone_type","default":"Primary"}},"type":"object","required":["phone_number"],"title":"CreatePhone","description":"Schema for creating a phone number."},"CreatePublication":{"properties":{"title":{"type":"string","title":"Title"},"authors":{"items":{"type":"string"},"type":"array","title":"Authors"},"year":{"type":"integer","title":"Year"},"doi":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Doi"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"publication_type":{"$ref":"#/components/schemas/publication_type"}},"type":"object","required":["title","authors","year","publication_type"],"title":"CreatePublication","description":"Schema for creating a new publication."},"CreateSample":{"properties":{"sample_date":{"type":"string","format":"date-time","title":"Sample Date"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"field_activity_id":{"type":"integer","title":"Field Activity Id"},"field_event_participant_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Field Event Participant Id"},"sample_name":{"type":"string","title":"Sample Name"},"sample_matrix":{"$ref":"#/components/schemas/sample_matrix"},"sample_method":{"$ref":"#/components/schemas/sample_method"},"qc_type":{"$ref":"#/components/schemas/qc_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["sample_date","field_activity_id","sample_name","sample_matrix","sample_method","qc_type"],"title":"CreateSample"},"CreateSensor":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"name":{"type":"string","title":"Name"},"sensor_type":{"$ref":"#/components/schemas/sensor_type"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["name","sensor_type"],"title":"CreateSensor","description":"Schema for creating a new sensor."},"CreateSpring":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"location_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Location Id"},"group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group Id"},"name":{"type":"string","title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"notes":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateNote"},"type":"array"},{"type":"null"}],"title":"Notes"},"alternate_ids":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateThingIdLink"},"type":"array"},{"type":"null"}],"title":"Alternate Ids"},"monitoring_frequencies":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateMonitoringFrequency"},"type":"array"},{"type":"null"}],"title":"Monitoring Frequencies"},"spring_type":{"anyOf":[{"$ref":"#/components/schemas/spring_type"},{"type":"null"}]}},"type":"object","required":["name"],"title":"CreateSpring","description":"Schema for creating a spring."},"CreateThingIdLink":{"properties":{"thing_id":{"type":"integer","title":"Thing Id"},"relation":{"type":"string","title":"Relation"},"alternate_id":{"type":"string","title":"Alternate Id"},"alternate_organization":{"type":"string","title":"Alternate Organization"}},"type":"object","required":["thing_id","relation","alternate_id","alternate_organization"],"title":"CreateThingIdLink","description":"Schema for creating a link between a thing and its ID."},"CreateWaterChemistryObservation":{"properties":{"parameter_id":{"type":"integer","title":"Parameter Id"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"type":"integer","title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","required":["parameter_id","observation_datetime","sample_id","sensor_id","value","unit"],"title":"CreateWaterChemistryObservation"},"CreateWell":{"properties":{"well_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Depth","description":"Well depth in feet"},"hole_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Hole Depth","description":"Hole depth in feet"},"well_casing_depth":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Casing Depth","description":"Well casing depth in feet"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height","description":"Measuring point height in feet"},"well_pump_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Pump Depth"},"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"location_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Location Id"},"group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group Id"},"name":{"type":"string","title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"notes":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateNote"},"type":"array"},{"type":"null"}],"title":"Notes"},"alternate_ids":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateThingIdLink"},"type":"array"},{"type":"null"}],"title":"Alternate Ids"},"monitoring_frequencies":{"anyOf":[{"items":{"$ref":"#/components/schemas/CreateMonitoringFrequency"},"type":"array"},{"type":"null"}],"title":"Monitoring Frequencies"},"well_purposes":{"anyOf":[{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array"},{"type":"null"}],"title":"Well Purposes"},"well_depth_source":{"anyOf":[{"$ref":"#/components/schemas/origin_type"},{"type":"null"}]},"well_casing_diameter":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Well Casing Diameter","description":"Well casing diameter in inches"},"well_casing_materials":{"anyOf":[{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array"},{"type":"null"}],"title":"Well Casing Materials"},"measuring_point_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measuring Point Description"},"well_completion_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Well Completion Date"},"well_completion_date_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Completion Date Source"},"well_driller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Driller Name"},"well_construction_method":{"anyOf":[{"$ref":"#/components/schemas/well_construction_method"},{"type":"null"}]},"well_construction_method_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Method Source"},"well_pump_type":{"anyOf":[{"$ref":"#/components/schemas/well_pump_type"},{"type":"null"}]},"is_suitable_for_datalogger":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Suitable For Datalogger"},"is_open":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Open"},"well_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Status"},"monitoring_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Monitoring Status"},"formation_completion_code":{"anyOf":[{"$ref":"#/components/schemas/formation_code"},{"type":"null"}]},"nma_formation_zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Formation Zone"}},"type":"object","required":["name"],"title":"CreateWell","description":"Schema for creating a well."},"CreateWellScreen":{"properties":{"release_status":{"$ref":"#/components/schemas/release_status","default":"draft"},"thing_id":{"type":"integer","title":"Thing Id"},"aquifer_system_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Aquifer System Id"},"geologic_formation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Geologic Formation Id"},"screen_depth_bottom":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Screen Depth Bottom","description":"Screen depth bottom in feet"},"screen_depth_top":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Screen Depth Top","description":"Screen depth top in feet"},"screen_type":{"anyOf":[{"$ref":"#/components/schemas/screen_type"},{"type":"null"}]},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"}},"type":"object","required":["thing_id"],"title":"CreateWellScreen","description":"Schema for creating a well screen."},"DeploymentResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"sensor":{"$ref":"#/components/schemas/SensorResponse"},"installation_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Installation Date"},"removal_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Removal Date"},"recording_interval":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Recording Interval"},"recording_interval_units":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Interval Units"},"hanging_cable_length":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hanging Cable Length"},"hanging_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hanging Point Height"},"hanging_point_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hanging Point Description"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","thing_id","sensor","installation_date","removal_date","recording_interval","recording_interval_units","hanging_cable_length","hanging_point_height","hanging_point_description","notes"],"title":"DeploymentResponse"},"EmailResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"email":{"type":"string","title":"Email"},"email_type":{"$ref":"#/components/schemas/email_type"}},"type":"object","required":["id","created_at","release_status","contact_id","email","email_type"],"title":"EmailResponse","description":"Response schema for email details."},"Feature":{"properties":{"type":{"type":"string","title":"Type","default":"Feature"},"geometry":{"$ref":"#/components/schemas/schemas__thing__GeoJSONGeometry"},"properties":{"additionalProperties":true,"type":"object","title":"Properties","default":{}}},"type":"object","required":["geometry"],"title":"Feature","description":"Feature schema for GeoJSON response."},"FeatureCollectionResponse":{"properties":{"type":{"type":"string","title":"Type","default":"FeatureCollection"},"features":{"items":{"$ref":"#/components/schemas/Feature"},"type":"array","title":"Features","default":[]}},"type":"object","title":"FeatureCollectionResponse","description":"Response schema for GeoJSON FeatureCollection."},"FieldActivityResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"field_event_id":{"type":"integer","title":"Field Event Id"},"activity_type":{"$ref":"#/components/schemas/activity_type"}},"type":"object","required":["id","created_at","release_status","field_event_id","activity_type"],"title":"FieldActivityResponse"},"FieldEventParticipantResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"field_event_id":{"type":"integer","title":"Field Event Id"},"contact_id":{"type":"integer","title":"Contact Id"},"participant_role":{"type":"string","title":"Participant Role"},"participant":{"$ref":"#/components/schemas/ContactResponse"}},"type":"object","required":["id","created_at","release_status","field_event_id","contact_id","participant_role","participant"],"title":"FieldEventParticipantResponse"},"FieldEventResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"event_date":{"type":"string","format":"date-time","title":"Event Date"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","thing_id","event_date","notes"],"title":"FieldEventResponse"},"GeoJSONProperties":{"properties":{"elevation":{"type":"number","title":"Elevation"},"elevation_unit":{"type":"string","title":"Elevation Unit","default":"ft"},"vertical_datum":{"type":"string","title":"Vertical Datum","default":"NAVD88"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"county":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"County"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"quad_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quad Name"},"utm_coordinates":{"$ref":"#/components/schemas/GeoJSONUTMCoordinates"},"notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Notes","default":[]},"nma_location_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Location Notes"},"nma_data_reliability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Data Reliability"},"nma_date_created":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Nma Date Created"},"nma_site_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Nma Site Date"}},"type":"object","required":["elevation","elevation_method"],"title":"GeoJSONProperties"},"GeoJSONUTMCoordinates":{"properties":{"easting":{"type":"number","title":"Easting"},"northing":{"type":"number","title":"Northing"},"utm_zone":{"type":"string","title":"Utm Zone","default":"13N"},"horizontal_datum":{"type":"string","title":"Horizontal Datum","default":"NAD83"}},"type":"object","required":["easting","northing"],"title":"GeoJSONUTMCoordinates"},"GroundwaterLevelObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"},"nma_data_quality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Data Quality"},"depth_to_water_bgs":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth To Water Bgs"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit","depth_to_water_bgs","measuring_point_height","groundwater_level_reason"],"title":"GroundwaterLevelObservationResponse"},"GroupResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"group_type":{"anyOf":[{"$ref":"#/components/schemas/group_type"},{"type":"null"}]},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"}},"type":"object","required":["id","created_at","release_status","name","description","project_area","group_type","parent_group_id"],"title":"GroupResponse","description":"Pydantic model for the response of a group.\nThis model can be extended to include additional fields as needed."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LexiconCategoryResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["id","created_at","name"],"title":"LexiconCategoryResponse","description":"Pydantic model for the response of a lexicon category.\nThis model can be extended to include additional fields as needed."},"LexiconTermResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"term":{"type":"string","title":"Term"},"definition":{"type":"string","title":"Definition"},"categories":{"items":{"$ref":"#/components/schemas/LexiconCategoryResponse"},"type":"array","title":"Categories","default":[]}},"type":"object","required":["id","created_at","term","definition"],"title":"LexiconTermResponse","description":"Pydantic model for the response of a lexicon term.\nThis model can be extended to include additional fields as needed."},"LexiconTripleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"subject":{"type":"string","title":"Subject"},"predicate":{"type":"string","title":"Predicate"},"object_":{"type":"string","title":"Object"}},"type":"object","required":["id","created_at","subject","predicate","object_"],"title":"LexiconTripleResponse"},"LocationGeoJSONResponse":{"properties":{"type":{"type":"string","title":"Type","default":"Feature"},"release_status":{"$ref":"#/components/schemas/release_status"},"geometry":{"$ref":"#/components/schemas/schemas__location__GeoJSONGeometry"},"properties":{"$ref":"#/components/schemas/GeoJSONProperties"}},"type":"object","required":["release_status","geometry","properties"],"title":"LocationGeoJSONResponse"},"LocationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Notes","default":[]},"point":{"type":"string","title":"Point"},"elevation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation"},"horizontal_datum":{"type":"string","title":"Horizontal Datum","default":"WGS84"},"vertical_datum":{"type":"string","title":"Vertical Datum","default":"NAVD88"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"county":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"County"},"quad_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quad Name"},"nma_location_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Location Notes"},"nma_data_reliability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Data Reliability"},"nma_date_created":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Nma Date Created"},"nma_site_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Nma Site Date"}},"type":"object","required":["id","created_at","release_status","point","elevation","elevation_method","state","county","quad_name"],"title":"LocationResponse","description":"Response schema for sample location details."},"MonitoringFrequencyResponse":{"properties":{"monitoring_frequency":{"$ref":"#/components/schemas/monitoring_frequency"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date"}},"type":"object","required":["monitoring_frequency","start_date","end_date"],"title":"MonitoringFrequencyResponse"},"NoteResponse":{"properties":{"note_type":{"$ref":"#/components/schemas/note_type"},"content":{"type":"string","title":"Content"},"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"target_id":{"type":"integer","title":"Target Id"},"target_table":{"type":"string","title":"Target Table"}},"type":"object","required":["note_type","content","id","created_at","release_status","target_id","target_table"],"title":"NoteResponse","description":"Response schema for Note details."},"ObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"},"nma_data_quality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Data Quality"},"depth_to_water_bgs":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth To Water Bgs"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit","depth_to_water_bgs","measuring_point_height","groundwater_level_reason"],"title":"ObservationResponse","description":"Response model for observations.\nCombines groundwater level and geothermal observation responses."},"Page_AddressResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AddressResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[AddressResponse]"},"Page_AssetResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AssetResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[AssetResponse]"},"Page_ContactResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ContactResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ContactResponse]"},"Page_DeploymentResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DeploymentResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[DeploymentResponse]"},"Page_EmailResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/EmailResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[EmailResponse]"},"Page_GroundwaterLevelObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GroundwaterLevelObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[GroundwaterLevelObservationResponse]"},"Page_GroupResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[GroupResponse]"},"Page_LexiconCategoryResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconCategoryResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconCategoryResponse]"},"Page_LexiconTermResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconTermResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconTermResponse]"},"Page_LexiconTripleResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LexiconTripleResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LexiconTripleResponse]"},"Page_LocationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/LocationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[LocationResponse]"},"Page_ObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ObservationResponse]"},"Page_PhoneResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PhoneResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[PhoneResponse]"},"Page_SampleResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SampleResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SampleResponse]"},"Page_SensorResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SensorResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SensorResponse]"},"Page_SpringResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SpringResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[SpringResponse]"},"Page_ThingIdLinkResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ThingIdLinkResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ThingIdLinkResponse]"},"Page_ThingResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ThingResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[ThingResponse]"},"Page_TransducerObservationWithBlockResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TransducerObservationWithBlockResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[TransducerObservationWithBlockResponse]"},"Page_WaterChemistryObservationResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WaterChemistryObservationResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WaterChemistryObservationResponse]"},"Page_WellResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WellResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WellResponse]"},"Page_WellScreenResponse_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/WellScreenResponse"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[WellScreenResponse]"},"Page_dict_":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"page":{"type":"integer","minimum":1.0,"title":"Page"},"size":{"type":"integer","minimum":1.0,"title":"Size"},"pages":{"type":"integer","minimum":0.0,"title":"Pages"}},"type":"object","required":["items","total","page","size","pages"],"title":"Page[dict]"},"ParameterResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"parameter_name":{"$ref":"#/components/schemas/parameter_name"},"matrix":{"type":"string","title":"Matrix"},"parameter_type":{"anyOf":[{"$ref":"#/components/schemas/parameter_type"},{"type":"null"}]},"cas_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cas Number"},"default_unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","required":["id","created_at","release_status","parameter_name","matrix","parameter_type","cas_number","default_unit"],"title":"ParameterResponse","description":"Pydantic model for the response of a parameter.\nThis model can be extended to include additional fields as needed."},"PermissionHistoryResponse":{"properties":{"permission_type":{"$ref":"#/components/schemas/permission_type"},"permission_allowed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Permission Allowed"},"start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date"},"end_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date"}},"type":"object","required":["permission_type","permission_allowed","start_date","end_date"],"title":"PermissionHistoryResponse","description":"Even though permission_allowed and start_date are not-nullable in the\ndatabase, they are nullable here to accommodate cases where no permission\nrecord exists for a given permission type."},"PhoneResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact_id":{"type":"integer","title":"Contact Id"},"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number"},"phone_type":{"type":"string","title":"Phone Type"}},"type":"object","required":["id","created_at","release_status","contact_id","phone_type"],"title":"PhoneResponse","description":"Response schema for phone details."},"PublicationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"title":{"type":"string","title":"Title"},"authors":{"items":{"$ref":"#/components/schemas/AuthorResponse"},"type":"array","title":"Authors"},"year":{"type":"integer","title":"Year"},"doi":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Doi"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"publication_type":{"$ref":"#/components/schemas/publication_type"}},"type":"object","required":["id","title","authors","year","publication_type"],"title":"PublicationResponse","description":"Schema for the response of a publication."},"ResourceNotFoundResponse":{"properties":{"detail":{"type":"string","title":"Detail"}},"type":"object","required":["detail"],"title":"ResourceNotFoundResponse"},"SampleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing":{"$ref":"#/components/schemas/ThingResponse"},"field_event":{"$ref":"#/components/schemas/FieldEventResponse"},"field_activity":{"$ref":"#/components/schemas/FieldActivityResponse"},"contact":{"anyOf":[{"$ref":"#/components/schemas/ContactResponse"},{"type":"null"}]},"sample_date":{"type":"string","title":"Sample Date"},"sample_name":{"type":"string","title":"Sample Name"},"sample_matrix":{"$ref":"#/components/schemas/sample_matrix"},"sample_method":{"$ref":"#/components/schemas/sample_method"},"qc_type":{"$ref":"#/components/schemas/qc_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"}},"type":"object","required":["id","created_at","release_status","thing","field_event","field_activity","contact","sample_date","sample_name","sample_matrix","sample_method","qc_type","notes","depth_top","depth_bottom"],"title":"SampleResponse","description":"Developer's note\n\nThe frontend uses multiple fields for a thing, field_even, and field_activity,\nwhich is why full ThingResponse, FieldEventResponse, and FieldActivityResponse\nare returned. If the response becomes too large and slow, we can use\n.model_dump() and exlude fields to reduce the size."},"SensorResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"sensor_type":{"$ref":"#/components/schemas/sensor_type"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["id","created_at","release_status","name","sensor_type","model","serial_no","pcn_number","owner_agency","sensor_status","notes"],"title":"SensorResponse"},"SpringResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"$ref":"#/components/schemas/LocationGeoJSONResponse"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"groups":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Groups","default":[]},"monitoring_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Monitoring Status"},"alternate_ids":{"items":{"$ref":"#/components/schemas/ThingIdLinkResponse"},"type":"array","title":"Alternate Ids","default":[]},"monitoring_frequencies":{"items":{"$ref":"#/components/schemas/MonitoringFrequencyResponse"},"type":"array","title":"Monitoring Frequencies","default":[]},"general_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"General Notes","default":[]},"sampling_procedure_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Sampling Procedure Notes","default":[]},"site_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Site Notes","default":[]},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date","monitoring_status"],"title":"SpringResponse","description":"Response schema for spring details."},"ThingIdLinkResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"relation":{"type":"string","title":"Relation"},"alternate_id":{"type":"string","title":"Alternate Id"},"alternate_organization":{"$ref":"#/components/schemas/organization"}},"type":"object","required":["id","created_at","release_status","thing_id","relation","alternate_id","alternate_organization"],"title":"ThingIdLinkResponse"},"ThingResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"$ref":"#/components/schemas/LocationGeoJSONResponse"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"groups":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Groups","default":[]},"monitoring_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Monitoring Status"},"alternate_ids":{"items":{"$ref":"#/components/schemas/ThingIdLinkResponse"},"type":"array","title":"Alternate Ids","default":[]},"monitoring_frequencies":{"items":{"$ref":"#/components/schemas/MonitoringFrequencyResponse"},"type":"array","title":"Monitoring Frequencies","default":[]},"general_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"General Notes","default":[]},"sampling_procedure_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Sampling Procedure Notes","default":[]},"site_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Site Notes","default":[]},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"},"well_purposes":{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array","title":"Well Purposes","default":[]},"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"well_depth_unit":{"type":"string","title":"Well Depth Unit","default":"ft"},"well_depth_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Depth Source"},"historic_depth_to_water":{"items":{"type":"string"},"type":"array","title":"Historic Depth To Water","default":[]},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"hole_depth_unit":{"type":"string","title":"Hole Depth Unit","default":"ft"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_diameter_unit":{"type":"string","title":"Well Casing Diameter Unit","default":"in"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"well_casing_depth_unit":{"type":"string","title":"Well Casing Depth Unit","default":"ft"},"well_casing_materials":{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array","title":"Well Casing Materials","default":[]},"well_completion_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Well Completion Date"},"well_completion_date_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Completion Date Source"},"well_driller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Driller Name"},"well_construction_method":{"anyOf":[{"$ref":"#/components/schemas/well_construction_method"},{"type":"null"}]},"well_construction_method_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Method Source"},"well_pump_type":{"anyOf":[{"$ref":"#/components/schemas/well_pump_type"},{"type":"null"}]},"well_pump_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Pump Depth"},"well_pump_depth_unit":{"type":"string","title":"Well Pump Depth Unit","default":"ft"},"well_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Status"},"open_status":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Open Status"},"datalogger_suitability_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datalogger Suitability Status"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"measuring_point_height_unit":{"type":"string","title":"Measuring Point Height Unit","default":"ft"},"measuring_point_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measuring Point Description"},"aquifers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Aquifers","default":[]},"water_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Water Notes","default":[]},"construction_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Construction Notes","default":[]},"contacts":{"items":{"$ref":"#/components/schemas/WellContactSummaryResponse"},"type":"array","title":"Contacts","default":[]},"permissions":{"items":{"$ref":"#/components/schemas/PermissionHistoryResponse"},"type":"array","title":"Permissions"},"formation_completion_code":{"anyOf":[{"$ref":"#/components/schemas/formation_code"},{"type":"null"}]},"nma_formation_zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Formation Zone"},"well_location_note":{"items":{"type":"string"},"type":"array","title":"Well Location Note","default":[]}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date","monitoring_status","well_depth_source","well_completion_date","well_completion_date_source","well_driller_name","well_construction_method","well_construction_method_source","well_pump_type","well_pump_depth","well_status","open_status","datalogger_suitability_status","measuring_point_height","measuring_point_description","permissions","formation_completion_code","nma_formation_zone"],"title":"ThingResponse"},"ThingResponseForContact":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","created_at","release_status","name"],"title":"ThingResponseForContact","description":"Response schema for thing details related to a contact. All that is needed\nare the id and name"},"TransducerObservationBlockResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"review_status":{"$ref":"#/components/schemas/review_status"},"start_datetime":{"type":"string","format":"date-time","title":"Start Datetime"},"end_datetime":{"type":"string","format":"date-time","title":"End Datetime"},"parameter_id":{"type":"integer","title":"Parameter Id"}},"type":"object","required":["id","created_at","release_status","review_status","start_datetime","end_datetime","parameter_id"],"title":"TransducerObservationBlockResponse"},"TransducerObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"value":{"type":"number","title":"Value"},"observation_datetime":{"type":"string","format":"date-time","title":"Observation Datetime"},"parameter_id":{"type":"integer","title":"Parameter Id"},"deployment_id":{"type":"integer","title":"Deployment Id"}},"type":"object","required":["id","created_at","release_status","value","observation_datetime","parameter_id","deployment_id"],"title":"TransducerObservationResponse"},"TransducerObservationWithBlockResponse":{"properties":{"observation":{"$ref":"#/components/schemas/TransducerObservationResponse"},"block":{"$ref":"#/components/schemas/TransducerObservationBlockResponse"}},"type":"object","required":["observation","block"],"title":"TransducerObservationWithBlockResponse"},"UpdateAddress":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"address_line_1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 1"},"address_line_2":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address Line 2"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"address_type":{"anyOf":[{"$ref":"#/components/schemas/address_type"},{"type":"null"}]}},"type":"object","title":"UpdateAddress","description":"Schema for updating address information."},"UpdateAsset":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","title":"UpdateAsset"},"UpdateContact":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"role":{"anyOf":[{"$ref":"#/components/schemas/role"},{"type":"null"}]},"contact_type":{"anyOf":[{"$ref":"#/components/schemas/contact_type"},{"type":"null"}]},"thing_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Thing Id"}},"type":"object","title":"UpdateContact","description":"Schema for updating contact information."},"UpdateEmail":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"email_type":{"anyOf":[{"$ref":"#/components/schemas/email_type"},{"type":"null"}]}},"type":"object","title":"UpdateEmail","description":"Schema for updating email information."},"UpdateGroundwaterLevelObservation":{"properties":{"parameter_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parameter Id"},"observation_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Observation Datetime"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"sample_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"groundwater_level_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Groundwater Level Reason"}},"type":"object","title":"UpdateGroundwaterLevelObservation"},"UpdateGroup":{"properties":{"project_area":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Area"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"parent_group_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Group Id"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","title":"UpdateGroup","description":"Pydantic model for updating a group.\nThis model can be extended to include additional fields as needed."},"UpdateLexiconCategory":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"UpdateLexiconCategory"},"UpdateLexiconTerm":{"properties":{"term":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Term"},"definition":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Definition"}},"type":"object","title":"UpdateLexiconTerm"},"UpdateLexiconTriple":{"properties":{"subject":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject"},"predicate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Predicate"},"object_":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Object"}},"type":"object","title":"UpdateLexiconTriple"},"UpdateLocation":{"properties":{"point":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Point"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"notes":{"items":{"$ref":"#/components/schemas/UpdateNote"},"type":"array","title":"Notes","default":[]},"elevation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation"},"elevation_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Elevation Accuracy"},"elevation_method":{"anyOf":[{"$ref":"#/components/schemas/elevation_method"},{"type":"null"}]},"coordinate_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Coordinate Accuracy"},"coordinate_method":{"anyOf":[{"$ref":"#/components/schemas/coordinate_method"},{"type":"null"}]}},"type":"object","title":"UpdateLocation","description":"Schema for updating a location. Notes are managed via the polymorphic Notes table."},"UpdateNote":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"note_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note Type"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"}},"type":"object","title":"UpdateNote","description":"Schema for updating an existing Note. All fields are optional"},"UpdatePhone":{"properties":{"phone_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone Number"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"contact_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contact Id"},"phone_type":{"anyOf":[{"$ref":"#/components/schemas/phone_type"},{"type":"null"}]}},"type":"object","title":"UpdatePhone","description":"Schema for updating phone information."},"UpdateSample":{"properties":{"sample_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sample Date"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"field_activity_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Field Activity Id"},"field_event_participant_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Field Event Participant Id"},"sample_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Name"},"sample_matrix":{"anyOf":[{"$ref":"#/components/schemas/sample_matrix"},{"type":"null"}]},"sample_method":{"anyOf":[{"$ref":"#/components/schemas/sample_method"},{"type":"null"}]},"qc_type":{"anyOf":[{"$ref":"#/components/schemas/qc_type"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdateSample"},"UpdateSensor":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"sensor_type":{"anyOf":[{"$ref":"#/components/schemas/sensor_type"},{"type":"null"}]},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"serial_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Serial No"},"pcn_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pcn Number"},"owner_agency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Agency"},"sensor_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Status"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"UpdateSensor"},"UpdateSpring":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"spring_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spring Type"}},"type":"object","title":"UpdateSpring"},"UpdateThingIdLink":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"alternate_organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alternate Organization"},"alternate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alternate Id"},"relation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation"}},"type":"object","title":"UpdateThingIdLink"},"UpdateWaterChemistryObservation":{"properties":{"parameter_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parameter Id"},"observation_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Observation Datetime"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"sample_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"anyOf":[{"$ref":"#/components/schemas/unit"},{"type":"null"}]}},"type":"object","title":"UpdateWaterChemistryObservation"},"UpdateWell":{"properties":{"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"well_pump_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Pump Depth"},"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"well_purposes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Well Purposes"},"well_construction_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Notes"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_materials":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Well Casing Materials"},"nma_formation_zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Formation Zone"}},"type":"object","title":"UpdateWell"},"UpdateWellScreen":{"properties":{"release_status":{"anyOf":[{"$ref":"#/components/schemas/release_status"},{"type":"null"}]},"aquifer_system_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Aquifer System Id"},"geologic_formation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Geologic Formation Id"},"screen_depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Bottom"},"screen_depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Top"},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"},"screen_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Type"}},"type":"object","title":"UpdateWellScreen"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WaterChemistryObservationResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"sample_id":{"type":"integer","title":"Sample Id"},"sensor_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sensor Id"},"observation_datetime":{"type":"string","title":"Observation Datetime"},"parameter":{"$ref":"#/components/schemas/ParameterResponse"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"unit":{"$ref":"#/components/schemas/unit"},"nma_data_quality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Data Quality"}},"type":"object","required":["id","created_at","release_status","sample_id","sensor_id","observation_datetime","parameter","value","unit"],"title":"WaterChemistryObservationResponse"},"WaterLevelBulkUploadResponse":{"properties":{"summary":{"$ref":"#/components/schemas/WaterLevelBulkUploadSummary"},"water_levels":{"items":{"$ref":"#/components/schemas/WaterLevelBulkUploadRow"},"type":"array","title":"Water Levels"},"validation_errors":{"items":{"type":"string"},"type":"array","title":"Validation Errors"}},"type":"object","required":["summary","water_levels","validation_errors"],"title":"WaterLevelBulkUploadResponse"},"WaterLevelBulkUploadRow":{"properties":{"well_name_point_id":{"type":"string","title":"Well Name Point Id"},"field_event_id":{"type":"integer","title":"Field Event Id"},"field_activity_id":{"type":"integer","title":"Field Activity Id"},"sample_id":{"type":"integer","title":"Sample Id"},"observation_id":{"type":"integer","title":"Observation Id"},"measurement_date_time":{"type":"string","title":"Measurement Date Time"},"level_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Level Status"},"data_quality":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Data Quality"}},"type":"object","required":["well_name_point_id","field_event_id","field_activity_id","sample_id","observation_id","measurement_date_time","level_status","data_quality"],"title":"WaterLevelBulkUploadRow"},"WaterLevelBulkUploadSummary":{"properties":{"total_rows_processed":{"type":"integer","title":"Total Rows Processed"},"total_rows_imported":{"type":"integer","title":"Total Rows Imported"},"validation_errors_or_warnings":{"type":"integer","title":"Validation Errors Or Warnings"}},"type":"object","required":["total_rows_processed","total_rows_imported","validation_errors_or_warnings"],"title":"WaterLevelBulkUploadSummary"},"WellContactSummaryResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"organization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Organization"},"role":{"$ref":"#/components/schemas/role"},"contact_type":{"$ref":"#/components/schemas/contact_type"}},"type":"object","required":["id","created_at","release_status","role","contact_type"],"title":"WellContactSummaryResponse"},"WellDetailsFieldActivityResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"field_event_id":{"type":"integer","title":"Field Event Id"},"activity_type":{"$ref":"#/components/schemas/activity_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"samples":{"items":{"$ref":"#/components/schemas/WellDetailsFieldEventSampleResponse"},"type":"array","title":"Samples"}},"type":"object","required":["id","created_at","release_status","field_event_id","activity_type"],"title":"WellDetailsFieldActivityResponse"},"WellDetailsFieldEventResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"event_date":{"type":"string","title":"Event Date"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"field_event_participants":{"items":{"$ref":"#/components/schemas/FieldEventParticipantResponse"},"type":"array","title":"Field Event Participants"},"field_activities":{"items":{"$ref":"#/components/schemas/WellDetailsFieldActivityResponse"},"type":"array","title":"Field Activities"}},"type":"object","required":["id","created_at","release_status","thing_id","event_date"],"title":"WellDetailsFieldEventResponse"},"WellDetailsFieldEventSampleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"contact":{"anyOf":[{"$ref":"#/components/schemas/ContactResponse"},{"type":"null"}]},"sample_date":{"type":"string","title":"Sample Date"},"sample_name":{"type":"string","title":"Sample Name"},"sample_matrix":{"$ref":"#/components/schemas/sample_matrix"},"sample_method":{"$ref":"#/components/schemas/sample_method"},"qc_type":{"$ref":"#/components/schemas/qc_type"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"},"depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Top"},"depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Depth Bottom"},"observations":{"items":{"$ref":"#/components/schemas/ObservationResponse"},"type":"array","title":"Observations"}},"type":"object","required":["id","created_at","release_status","sample_date","sample_name","sample_matrix","sample_method","qc_type"],"title":"WellDetailsFieldEventSampleResponse"},"WellDetailsResponse":{"properties":{"well":{"$ref":"#/components/schemas/WellResponse"},"contacts":{"items":{"$ref":"#/components/schemas/ContactResponse"},"type":"array","title":"Contacts"},"sensors":{"items":{"$ref":"#/components/schemas/SensorResponse"},"type":"array","title":"Sensors"},"deployments":{"items":{"$ref":"#/components/schemas/DeploymentResponse"},"type":"array","title":"Deployments"},"well_screens":{"items":{"$ref":"#/components/schemas/WellScreenBaseResponse"},"type":"array","title":"Well Screens"},"field_events":{"items":{"$ref":"#/components/schemas/WellDetailsFieldEventResponse"},"type":"array","title":"Field Events"},"first_field_event":{"anyOf":[{"$ref":"#/components/schemas/WellDetailsFieldEventResponse"},{"type":"null"}]}},"type":"object","required":["well"],"title":"WellDetailsResponse"},"WellExportResponse":{"properties":{"well":{"$ref":"#/components/schemas/WellResponse"},"contacts":{"items":{"$ref":"#/components/schemas/ContactResponse"},"type":"array","title":"Contacts"},"sensors":{"items":{"$ref":"#/components/schemas/SensorResponse"},"type":"array","title":"Sensors"},"deployments":{"items":{"$ref":"#/components/schemas/DeploymentResponse"},"type":"array","title":"Deployments"}},"type":"object","required":["well"],"title":"WellExportResponse"},"WellResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"name":{"type":"string","title":"Name"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name"},"thing_type":{"type":"string","title":"Thing Type"},"current_location":{"$ref":"#/components/schemas/LocationGeoJSONResponse"},"first_visit_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"First Visit Date"},"groups":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Groups","default":[]},"monitoring_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Monitoring Status"},"alternate_ids":{"items":{"$ref":"#/components/schemas/ThingIdLinkResponse"},"type":"array","title":"Alternate Ids","default":[]},"monitoring_frequencies":{"items":{"$ref":"#/components/schemas/MonitoringFrequencyResponse"},"type":"array","title":"Monitoring Frequencies","default":[]},"general_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"General Notes","default":[]},"sampling_procedure_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Sampling Procedure Notes","default":[]},"site_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Site Notes","default":[]},"well_purposes":{"items":{"$ref":"#/components/schemas/well_purpose"},"type":"array","title":"Well Purposes","default":[]},"well_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Depth"},"well_depth_unit":{"type":"string","title":"Well Depth Unit","default":"ft"},"well_depth_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Depth Source"},"historic_depth_to_water":{"items":{"type":"string"},"type":"array","title":"Historic Depth To Water","default":[]},"hole_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hole Depth"},"hole_depth_unit":{"type":"string","title":"Hole Depth Unit","default":"ft"},"well_casing_diameter":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Diameter"},"well_casing_diameter_unit":{"type":"string","title":"Well Casing Diameter Unit","default":"in"},"well_casing_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Casing Depth"},"well_casing_depth_unit":{"type":"string","title":"Well Casing Depth Unit","default":"ft"},"well_casing_materials":{"items":{"$ref":"#/components/schemas/casing_material"},"type":"array","title":"Well Casing Materials","default":[]},"well_completion_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Well Completion Date"},"well_completion_date_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Completion Date Source"},"well_driller_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Driller Name"},"well_construction_method":{"anyOf":[{"$ref":"#/components/schemas/well_construction_method"},{"type":"null"}]},"well_construction_method_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Construction Method Source"},"well_pump_type":{"anyOf":[{"$ref":"#/components/schemas/well_pump_type"},{"type":"null"}]},"well_pump_depth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Well Pump Depth"},"well_pump_depth_unit":{"type":"string","title":"Well Pump Depth Unit","default":"ft"},"well_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Well Status"},"open_status":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Open Status"},"datalogger_suitability_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datalogger Suitability Status"},"measuring_point_height":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Measuring Point Height"},"measuring_point_height_unit":{"type":"string","title":"Measuring Point Height Unit","default":"ft"},"measuring_point_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measuring Point Description"},"aquifers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Aquifers","default":[]},"water_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Water Notes","default":[]},"construction_notes":{"items":{"$ref":"#/components/schemas/NoteResponse"},"type":"array","title":"Construction Notes","default":[]},"contacts":{"items":{"$ref":"#/components/schemas/WellContactSummaryResponse"},"type":"array","title":"Contacts","default":[]},"permissions":{"items":{"$ref":"#/components/schemas/PermissionHistoryResponse"},"type":"array","title":"Permissions"},"formation_completion_code":{"anyOf":[{"$ref":"#/components/schemas/formation_code"},{"type":"null"}]},"nma_formation_zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nma Formation Zone"},"well_location_note":{"items":{"type":"string"},"type":"array","title":"Well Location Note","default":[]}},"type":"object","required":["id","created_at","release_status","name","thing_type","current_location","first_visit_date","monitoring_status","well_depth_source","well_completion_date","well_completion_date_source","well_driller_name","well_construction_method","well_construction_method_source","well_pump_type","well_pump_depth","well_status","open_status","datalogger_suitability_status","measuring_point_height","measuring_point_description","permissions","formation_completion_code","nma_formation_zone"],"title":"WellResponse","description":"Response schema for well details."},"WellScreenBaseResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"aquifer_system_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Aquifer System Id"},"aquifer_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aquifer System"},"aquifer_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aquifer Type"},"geologic_formation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Geologic Formation Id"},"geologic_formation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geologic Formation"},"screen_depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Bottom"},"screen_depth_bottom_unit":{"type":"string","title":"Screen Depth Bottom Unit","default":"ft"},"screen_depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Top"},"screen_depth_top_unit":{"type":"string","title":"Screen Depth Top Unit","default":"ft"},"screen_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Type"},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"}},"type":"object","required":["id","created_at","release_status","thing_id"],"title":"WellScreenBaseResponse"},"WellScreenResponse":{"properties":{"id":{"type":"integer","title":"Id"},"created_at":{"type":"string","title":"Created At"},"release_status":{"$ref":"#/components/schemas/release_status"},"thing_id":{"type":"integer","title":"Thing Id"},"aquifer_system_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Aquifer System Id"},"aquifer_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aquifer System"},"aquifer_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aquifer Type"},"geologic_formation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Geologic Formation Id"},"geologic_formation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Geologic Formation"},"screen_depth_bottom":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Bottom"},"screen_depth_bottom_unit":{"type":"string","title":"Screen Depth Bottom Unit","default":"ft"},"screen_depth_top":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Screen Depth Top"},"screen_depth_top_unit":{"type":"string","title":"Screen Depth Top Unit","default":"ft"},"screen_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Type"},"screen_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen Description"},"thing":{"$ref":"#/components/schemas/WellResponse"}},"type":"object","required":["id","created_at","release_status","thing_id","thing"],"title":"WellScreenResponse","description":"Response schema for well screen details."},"activity_type":{"type":"string","enum":["well inventory","groundwater level","water chemistry"],"title":"activity_type"},"address_type":{"type":"string","enum":["Primary","Work","Personal","Mailing","Physical"],"title":"address_type"},"casing_material":{"type":"string","enum":["PVC","Steel","Concrete"],"title":"casing_material"},"contact_type":{"type":"string","enum":["Primary","Secondary","Field Event Participant"],"title":"contact_type"},"coordinate_method":{"type":"string","enum":["Unknown","Differentially corrected GPS","Survey-grade global positioning system (SGPS)","GPS, uncorrected","Interpolated from map","Interpolated from DEM","Reported","Transit, theodolite, or other survey method"],"title":"coordinate_method"},"elevation_method":{"type":"string","enum":["Altimeter","Differentially corrected GPS","Survey-grade GPS","Global positioning system (GPS)","LiDAR DEM","Level or other survey method","Interpolated from topographic map","Interpolated from digital elevation model (DEM)","Reported","Survey-grade Global Navigation Satellite Sys, Lvl1","USGS National Elevation Dataset (NED)","Unknown"],"title":"elevation_method"},"email_type":{"type":"string","enum":["Primary","Work","Personal"],"title":"email_type"},"formation_code":{"type":"string","enum":["000EXRV","000IRSV","050QUAL","100QBAS","110ALVM","110AVMB","110BLSN","110NTGU","110PTODC","111MCCR","112ANCH","112CURB","112LAMA","112LAMAb","112LGUN","112QTBF","112QTBFlac","112QTBFpd","112QTBFppm","112SNTF","112SNTFA","112SNTFOB","112SNTFP","112TRTO","120DTIL","120ELRT","120IRSV","120SBLC","120SRVB","120SRVBf","120TSBV_Lower","120TSBV_Upper","121CHMT","121CHMTv","121CHMTvs","121OGLL","121PUYEF","121TSUQ","121TSUQa","121TSUQacu","121TSUQacuf","121TSUQaml","121TSUQb","121TSUQbfl","121TSUQbfm","121TSUQbp","121TSUQce","121TSUQe","121TSUQs","121TSUQsa","121TSUQsc","121TSUQsf","122CHOC","122CRTO","122OJOC","122PICR","122PPTS","122SNTFP","123DTILSPRS","123DTMGandbas","123DTMGign","123DTMGrhydac","123ESPN","123GLST","123PICS","123PICSc","123PICSl","123SPRSDTMGlava","123SPRSlower","123SPRSmid_uppe","124BACA","124CBMN","124LLVS","124PSCN","124RGIN","124SNJS","124TPCS","125NCMN","125NCMNS","125RTON","130CALDFLOOR","180TKSCC_Upper","180TKTR","210CRCS","210GLUPC_Lower","210HOSTD","210MCDK","210MNCS","210MNCSL","210MNCSU","211CLFHV","211CRLL","211CRVC","211DKOT","211DLCO","211DLTN","211FRHS","211FRLD","211FRMG","211GBSNC","211GLLG","211GLLP","211GRRG","211GRRS","211HOST","211KRLD","211LWIS","211MENF","211MENFU","211MVRD","211OJAM","211PCCF","211PIRR","211PNLK","211SMKH","211TLLS","212KTRP","217PRGR","220ENRD","220JURC","220NAVJ","221BLFF","221CSPG","221ERADU","221MRSN","221MRSN/BBSN","221MRSN/JCKP","221MRSN/RCAP","221MRSN/WWCN","221SLWS","221SMVL","221TDLT","221WSRC","221ZUNIS","231AGZC","231AGZCU","231CHNL","231CORR","231DCKM","231PFDF","231PFDFL","231PFDFM","231PFDFU","231RCKP","231SNRS","231SNSL","231SRMP","231WNGT","260SNAN","260SNAN_lower","261SNGL","300YESO","300YESO_lower","300YESO_upper","310ABO","310DCLL","310GLOR","310MBLC","310TRRS","310YESO","310YESOG","312CSTL","312RSLR","313ARTS","313BLCN","313BRUC","313CKBF","313CLBD","313CPTN","313GDLP","313GOSP","313SADG","313SADR","313TNSL","313YATS","315LABR","315YESOABO","318ABO","318BSPG","318JOYT","318YESO","319BRSM","320HLDR","320PENN","320SNDI","321SGDC","322BEMN","325GBLR","325MDER","325MDERL","325MDERU","325SAND","326MGDL","340EPRS","350PZBA","350PZBB","400EMBD","400PCMB","400PREC","400PRECintr","400PRST","400TUSS","410PRCG","410PRCGf","410PRCQ","410PRCQf","121GILA","312DYLK","120WMVL","313GRBG","318ABOL","318ABOU","112SNTFU","310FRNR","312OCHO","313AZOT","313QUEN","319HUCO","313SVRV","313CABD","320GRMS","211CLRDH","120BRLM","122RUBO","313SADRL","313SADRU","313BRNL","318CPDR","121BDHC","313SADY","221SRFLL","221BLUF","221COSP","317ABYS","221BRSB","310SYDR","400SDVL","221SRFL","310SGRC","231TCVS","211DCRS","211ALSN","211LVNN","211MORD","210PRMD","124ANMS","211NBRR","111ALVM","122SNTFL","111CPLN","120CRSN","111CRMS","111CRMSA","111SPOL","110TURT","221RCPR","320BLNG","112ANCHsr","121TSUQae","230TRSC","122TSUQdx","123PICSu","123PICSm","123PICSmc","120VBVC","120VCSS","124DMDT","325ALMT","400SAND","318VCPK","318BSVP","100ALVM","310PRMN","110AVPS","313CRCX","112SLBL","112SBCRC","313CRDM","112SBDM","120BLSN","112SBCR","112HCBL","120IVIG","112RLBL","112EFBL","112GRBL","123SAND","210MRNH","320ALMT","313DLRM","300PLZC","122SPRS","110AVTV","313DMBS","120ERSV"],"title":"formation_code"},"group_type":{"type":"string","enum":["Monitoring Plan","Geographic Area","Historical"],"title":"group_type"},"monitoring_frequency":{"type":"string","enum":["Monthly","Bimonthly","Bimonthly reported","Quarterly","Biannual","Annual","Decadal","Event-based"],"title":"monitoring_frequency"},"note_type":{"type":"string","enum":["Access","Directions","Communication","Construction","Maintenance","Historical","General","Water","Water Quality","Sampling Procedure","Coordinate","OwnerComment","Site Notes (legacy)"],"title":"note_type"},"organization":{"type":"string","enum":["Unknown","City of Aztec","Daybreak Investments","Vallecitos HOA","SFC, Santa Fe Animal Shelter","El Guicu Ditch Association","Santa Fe Municipal Airport","Uluru Development","AllSup's Convenience Stores","Santa Fe Downs Resort","City of Truth or Consequences, WWTP","Riverbend Hotsprings","Armendaris Ranch","El Paso Water","BLM, Socorro Field Office","USFWS","Sile MDWCA","Pena Blanca Water & Sanitation District","Town of Questa","Town of Cerro","Farr Cattle Company","Carrizozo Orchard","USFS, Kiowa Grasslands","Cloud Country West Subdivision","Chama West WUA","El Rito Regional Water and Waste Water Association","West Rim MDWUA","Village of Willard","Quemado Municipal Water & SWA","Coyote Creek MDWUA","Lamy MDWCA","La Joya CWDA","NM Firefighters Training Academy","Cebolleta Land Grant","Madrid Water Co-op","Sun Valley Water and Sanitation","Bluewater Lake MDWCA","Bluewater Acres Domestic WUA","Lybrook MDWCA","New Mexico Museum of Natural History","Hillsboro MDWCA","Tyrone MDWCA","Santa Clara Water System","Casas Adobes MDWCA","Lake Roberts WUA","El Creston MDWCA","Reserve Municipality Water Works","Town of Estancia","Pie Town MDWCA","Roosevelt SWCD","Otis MDWCA","White Cliffs MDWUA","Vista Linda Water Co-op","Anasazi Trails Water Co-op","Canon MDWCA","Placitas Trails Water Co-op","BLM, Roswell Office","Forked Lightning Ranch","Cottonwood RWA","Pinon Ridge WUA","McSherry Farms","Agua Sana WUA","Chamita MDWCA","W Spear-bar Ranch","Village of Capitan","Brazos MDWCA","Alto Alps HOA","Chiricahua Desert Museum","Bike Ranch","Hachita MDWCA","Carrizozo Municipal Water","Dunhill Ranch","Santa Fe Conservation Trust","NMSU","USGS","TWDB","NMED","NMOSE","NMBGMR","Bernalillo County","BLM","BLM Taos Office","SFC","SFC, Fire Facilities","SFC, Utilities Dept.","SFC, Valle Vista Water Utility, Inc.","City of Santa Fe","City of Santa Fe WWTP","City of Santa Fe, Municipal Recreation Complex","City of Santa Fe, Sangre de Cristo Water Co.","NMISC","PVACD","Bayard","SNL","USFS","NMT","NPS","NMRWA","NMDOT","Taos SWCD","Otero SWCD","Northeastern SWCD","CDWR","Pendaries Village","A&T Pump & Well Service, LLC","A. G. Wassenaar, Inc","AMEC","Balleau Groundwater, Inc","CDM Smith","CH2M Hill","Corbin Consulting, Inc","Chevron","Daniel B. Stephens & Associates, Inc","EnecoTech","Faith Engineering, Inc","Foster Well Service, Inc","Glorieta Geoscience, Inc","Golder Associates, Inc","Hathorn's Well Service, Inc","Hydroscience Associates, Inc","IC Tech, Inc","John Shomaker & Associates, Inc","Kuckleman Pump Service","Los Golondrinas","Minton Engineers","MJDarrconsult, Inc","Puerta del Canon Ranch","Rodgers & Company, Inc","San Pedro Creek Estates HOA","Statewide Drilling, Inc","Tec Drilling Limited","Tetra Tech, Inc","Thompson Drilling, Inc","Witcher & Associates","Zeigler Geologic Consulting, LLC","Sandia Well Service, Inc","San Marcos Association","URS","Vista del Oro","Abeyta Engineering, Inc","Adobe Ranch","Agua Fria Community Water Association","Apache Gap Ranch","Aspendale Mountain Retreat","Augustin Plains Ranch LLC","B & B Cattle Co","Berridge Distributing Company","Bishop's Lodge","Bonanza Creek Ranch","Bug Scuffle Water Association","Wehinahpay Mountain Camp","Campbell Ranch","Capitol Ford Santa Fe","Cemex, Inc","Cerro Community Center","Santa Fe Jewish Center","Chupadero MDWCA","Cielo Lumbre HOA","Circle Cross Ranch","City of Alamogordo","City of Portales, Public Works Dept.","City of Socorro","Commonwealth Conservancy","Costilla MDWCA","Country Club Garden Mobile Home Park","Crossroads Cattle Co., Ltd","Double H Ranch","E.A. Meadows East","El Camino Realty, Inc","Eldorado Area Water & Sanitation District","Bourbon Grill at El Gancho","El Prado HOA","El Rancho de las Golondrinas","El Rito Canyon MDWCA","Encantado Enterprises","Estrella Concepts LLC","Sixteen Springs Fire Department","Fire Water Lodge","Ford County Land & Cattle Company, Inc","Friendly Construction, Inc","Hacienda Del Cerezo","Hefker Vega Ranch","High Nogal Ranch","Holloman Air Force Base","Hyde Park Estates MDWCA","Desert Village RV & Mobile Home Park","K. Schmitt Trust","La Cienega MDWCA","La Vista HOA","Land Ventures LLC","Las Lagunitas","Las Lagunitas HOA","Living World Ministries","Los Atrevidos, Inc","Los Prados HOA","Malaga MDWCA & SWA","Mangas Outfitters","Medina Gravel Pit","Mendenhall Trading Co","Mesa Verde Ranch","NMDGF","NMSU College of Agriculture","Naiche Development","NRAO","NMSA","Nogal MDWCA","O Bar O Ranch","OMI Wastewater Treatment Plant","Old Road Ranch Pardners Ltd","PNM Service Center","Peace Tabernacle Church","Pecos Trail Inn","Pelican Spa","Pistachio Tree Ranch","Rancho Encantado","Rancho San Lucas","Rancho San Marcos","Rancho Viejo Partnership","Ranney Ranch","Rio En Medio MDWCA","San Acacia MDWCA","San Juan Residences","Sangre de Cristo Estates","Santa Fe Community College","Sangre de Cristo Center","Santa Fe Horse Park","Santa Fe Opera","Santa Fe Waldorf School","Shidoni Foundry and Gallery","Sierra Grande Lodge","Sierra Vista Retirement Community","Slash Triangle Ranch","Stagecoach Motel","State of New Mexico","Stephenson Ranch","Sun Broadcasting Network","Tano Rd LLC","UNM-Taos","Tee Pee Ranch/Tee Pee Subdivision","Tent Rock, Inc","Tesuque MDWCA","The Great Cloud Zen Center","Three Rivers Ranch","Timberon Water and Sanitation District","Town of Magdalena","Town of Taos","Town of Taos, National Guard Armory","Trinity Ranch","Tularosa Basin National Desalination Research Facility","Turquoise Trail Charter School","US Bureau of Indian Affairs, Santa Fe Indian School","USFS, Carson NF, Taos Office","USFS, Cibola NF, Magdalena Ranger District","USFS, Santa Fe NF, Espanola Ranger District","Ute Mountain Farms","VA Hospital","Velte","Vereda Serena Property","Village of Corona","Village of Floyd","Village of Melrose","Village of Vaughn","Vista Land Company","Vista Redonda MDWCA","Vista de Oro de Placitas Water Users Coop","Walker Ranch","Wild & Woolley Trailer Ranch","Winter Brothers","Yates Petroleum Corporation","Zamora Accounting Services","Agua Sana MWCD","Canada Los Alamos MDWCA","Canjilon Mutual Domestic Water System","Cebolla Mutual Domestic","Chihuahuan Desert Rangeland Research Center (CDRRC)","East Rio Arriba SWCD","El Prado Municipal Water","Hachita Mutual Domestic","Jornada Experimental Range (JER)","La Canada Way HOA","Los Ojos Mutual Domestic","The Nature Conservancy (TNC)","Smith Ranch LLC","Zia Pueblo","Our Lady of Guadalupe (OLG)","PLSS"],"title":"organization"},"origin_type":{"type":"string","enum":["Reported by another agency","From driller's log or well report","Private geologist, consultant or univ associate","Interpreted fr geophys logs by source agency","Memory of owner, operator, driller","Measured by source agency","Reported by owner of well","Reported by person other than driller owner agency","Measured by NMBGMR staff","Other","Data Portal"],"title":"origin_type"},"parameter_name":{"type":"string","enum":["groundwater level","temperature","pH","Alkalinity, Total","Alkalinity as CaCO3","Alkalinity as OH-","Calcium","Calcium, total, unfiltered","Chloride","Carbonate","Conductivity, laboratory","Bicarbonate","Hardness (CaCO3)","Ion Balance","Potassium","Potassium, total, unfiltered","Magnesium","Magnesium, total, unfiltered","Sodium","Sodium, total, unfiltered","Sodium and Potassium combined","Sulfate","Total Anions","Total Cations","Total Dissolved Solids","Tritium","Age of Water using dissolved gases","Silver","Silver, total, unfiltered","Aluminum","Aluminum, total, unfiltered","Arsenic","Arsenic, total, unfiltered","Boron","Boron, total, unfiltered","Barium","Barium, total, unfiltered","Beryllium","Beryllium, total, unfiltered","Bromide","13C:12C ratio","14C content, pmc","Uncorrected C14 age","Cadmium","Cadmium, total, unfiltered","Chlorofluorocarbon-11 avg age","Chlorofluorocarbon-113 avg age","Chlorofluorocarbon-113/12 avg RATIO age","Chlorofluorocarbon-12 avg age","Cobalt","Cobalt, total, unfiltered","Chromium","Chromium, total, unfiltered","Copper","Copper, total, unfiltered","delta O18 sulfate","Sulfate 34 isotope ratio","Fluoride","Iron","Iron, total, unfiltered","Deuterium:Hydrogen ratio","Mercury","Mercury, total, unfiltered","Lithium","Lithium, total, unfiltered","Manganese","Manganese, total, unfiltered","Molybdenum","Molybdenum, total, unfiltered","Nickel","Nickel, total, unfiltered","Nitrite (as NO2)","Nitrite (as N)","Nitrate (as NO3)","Nitrate (as N)","18O:16O ratio","Lead","Lead, total, unfiltered","Phosphate","Antimony","Antimony, total, unfiltered","Selenium","Selenium, total, unfiltered","Sulfur hexafluoride","Silicon","Silicon, total, unfiltered","Silica","Tin","Tin, total, unfiltered","Strontium","Strontium, total, unfiltered","Strontium 87:86 ratio","Thorium","Thorium, total, unfiltered","Titanium","Titanium, total, unfiltered","Thallium","Thallium, total, unfiltered","Uranium (total, by ICP-MS)","Uranium, total, unfiltered","Vanadium","Vanadium, total, unfiltered","Zinc","Zinc, total, unfiltered","Corrected C14 in years","Arsenite (arsenic species)","Arsenate (arsenic species)","Cyanide","Estimated recharge temperature","Hydrogen sulfide","Ammonia","Ammonium","Total nitrogen","Total Kjeldahl nitrogen","Dissolved organic carbon","Total organic carbon","delta C13 of dissolved inorganic carbon"],"title":"parameter_name"},"parameter_type":{"type":"string","enum":["Field Parameter","Metal","Radionuclide","Major Element","Minor Element","Physical property"],"title":"parameter_type"},"permission_type":{"type":"string","enum":["Water Level Sample","Water Chemistry Sample","Datalogger Installation"],"title":"permission_type"},"phone_type":{"type":"string","enum":["Primary","Work","Home","Mobile"],"title":"phone_type"},"publication_type":{"type":"string","enum":["Map","Report","Dataset","Model","Software","Paper","Thesis","Book","Conference","Webpage"],"title":"publication_type"},"qc_type":{"type":"string","enum":["Normal","Duplicate","Split","Field Blank","Trip Blank","Equipment Blank"],"title":"qc_type"},"release_status":{"type":"string","enum":["draft","provisional","final","published","archived","public","private"],"title":"release_status"},"review_status":{"type":"string","enum":["approved","not reviewed"],"title":"review_status"},"role":{"type":"string","enum":["Unknown","Principal Investigator","Owner","Manager","Operator","Driller","Geologist","Hydrologist","Hydrogeologist","Engineer","Organization","Specialist","Technician","Research Assistant","Research Scientist","Graduate Student","Biologist","Lab Manager","Publications Manager","Software Developer"],"title":"role"},"sample_matrix":{"type":"string","enum":["water","groundwater","soil"],"title":"sample_matrix"},"sample_method":{"type":"string","enum":["Unknown","Airline measurement","Analog or graphic recorder","Calibrated airline measurement","Differential GPS; especially applicable to surface expression of ground water","Estimated","Transducer","Pressure-gage measurement","Calibrated pressure-gage measurement","Interpreted from geophysical logs","Manometer","Non-recording gage","Observed (required for F, N, and W water level status)","Sonic water level meter (acoustic pulse)","Reported, method not known","Steel-tape measurement","Electric tape measurement (E-probe)","Unknown (for legacy data only; not for new data entry)","Calibrated electric tape; accuracy of equipment has been checked","Calibrated electric cable","Uncalibrated electric cable","Continuous acoustic sounder","Measurement not attempted","null placeholder","bailer","faucet at well head","faucet or outlet at house","grab sample","pump","thief sampler"],"title":"sample_method"},"schemas__location__GeoJSONGeometry":{"properties":{"type":{"type":"string","title":"Type","default":"Point"},"coordinates":{"items":{},"type":"array","maxItems":3,"minItems":3,"title":"Coordinates","description":"Coordinates in [longitude, latitude, elevation] format"}},"type":"object","required":["coordinates"],"title":"GeoJSONGeometry"},"schemas__thing__GeoJSONGeometry":{"properties":{"type":{"type":"string","title":"Type"},"coordinates":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},{"items":{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},"type":"array"},{"items":{"items":{"items":{"items":{"type":"number"},"type":"array"},"type":"array"},"type":"array"},"type":"array"}],"title":"Coordinates"}},"type":"object","required":["type","coordinates"],"title":"GeoJSONGeometry","description":"Geometry schema for GeoJSON response."},"screen_type":{"type":"string","enum":["PVC","Steel","Concrete"],"title":"screen_type"},"sensor_type":{"type":"string","enum":["DiverLink","Diver Cable","Pressure Transducer","Data Logger","Barometer","Acoustic Sounder","Precip Collector","Camera","Soil Moisture Sensor","Tipping Bucket","Weather Station","Weir","Snow Lysimeter","Lysimeter"],"title":"sensor_type"},"spring_type":{"type":"string","enum":["Artesian","Ephemeral","Perennial","Thermal","Mineral"],"title":"spring_type"},"unit":{"type":"string","enum":["dimensionless","ft","ftbgs","F","mg/L","mW/m²","W/m²","W/m·K","m²/s","deg C","deg second","deg minute","second","minute","hour","m"],"title":"unit"},"well_construction_method":{"type":"string","enum":["Unknown","Air-Rotary","Bored or augered","Cable-tool","Hydraulic rotary (mud or water)","Air percussion","Reverse rotary","Driven","Other (explain in notes)"],"title":"well_construction_method"},"well_pump_type":{"type":"string","enum":["Submersible","Jet","Line Shaft","Hand","Windmill"],"title":"well_pump_type"},"well_purpose":{"type":"string","enum":["Unknown","Open, unequipped well","Commercial","Domestic","Power generation","Irrigation","Livestock","Mining","Industrial","Observation","Public supply","Shared domestic","Institutional","Unused","Exploration","Monitoring","Production","Injection"],"title":"well_purpose"}},"securitySchemes":{"OAuth2AuthorizationCodeBearer":{"type":"oauth2","flows":{"authorizationCode":{"scopes":{"openid":"openid","offline_access":"offline_access"},"authorizationUrl":"https://authentik.newmexicowaterdata.org/application/o/authorize/","tokenUrl":"https://authentik.newmexicowaterdata.org/application/o/token/"}}}}}} \ No newline at end of file diff --git a/openapi-ts.config.ts b/openapi-ts.config.ts index df1777c6..83f3ae42 100644 --- a/openapi-ts.config.ts +++ b/openapi-ts.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from '@hey-api/openapi-ts' export default defineConfig({ - input: 'https://ocotillo-api-staging.newmexicowaterdata.org/openapi-auth.json', + input: './openapi-auth.json', output: {path: './src/generated', clean: true}, plugins: [ { diff --git a/src/generated/types.gen.ts b/src/generated/types.gen.ts index fc2813fd..b0ef527f 100644 --- a/src/generated/types.gen.ts +++ b/src/generated/types.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts export type ClientOptions = { - baseUrl: 'https://ocotillo-api-staging.newmexicowaterdata.org' | (string & {}); + baseUrl: `${string}://${string}` | (string & {}); }; /** From 10a7a0fc34190780cbc5c21b8590786734fecedc Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Mon, 27 Apr 2026 14:41:57 -0400 Subject: [PATCH 49/52] Fix hydrograph showing previous well after client-side navigation Drive thing_id from React Query queryKey inside the hydrograph queryFn, forward AbortSignal through ocotillo getList and axios, show loading while the query is pending, and remount the chart when the well id changes. Add .cursor to gitignore for local Cursor metadata. --- .gitignore | 1 + src/components/card/Hydrograph.tsx | 1 + src/pages/ocotillo/thing/well-show.tsx | 27 ++++++++++++++++++------- src/providers/ocotillo-data-provider.ts | 6 ++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 56837453..8768adc0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. .idea +.cursor .env # dependencies diff --git a/src/components/card/Hydrograph.tsx b/src/components/card/Hydrograph.tsx index 25f10281..27e9b7c8 100644 --- a/src/components/card/Hydrograph.tsx +++ b/src/components/card/Hydrograph.tsx @@ -56,6 +56,7 @@ export const HydrographCard = ({ ) : ( diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 1e33c9b4..50be1c27 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -179,11 +179,24 @@ export const WellShow = () => { )?.alternate_id || 'N/A' const hydrographQuery = useQuery({ - queryKey: ['well-hydrograph', id], + queryKey: ['well-hydrograph', id ?? ''], enabled: Boolean(id), staleTime: 5 * 60 * 1000, gcTime: 10 * 60 * 1000, - queryFn: async () => { + queryFn: async ({ queryKey, signal }) => { + const thingId = queryKey[1] + if (thingId === '' || thingId == null) { + return { + manualRows: [] as IObservation[], + transducerRows: [] as TransducerObservationWithBlockResponse[], + } + } + + const listMeta = (params: Record) => ({ + params, + ...(signal ? { signal } : {}), + }) + const fetchAllPages = async ( resource: string, params: Record, @@ -192,7 +205,7 @@ export const WellShow = () => { const firstPage = await ocotilloDataProvider.getList({ resource, pagination: { currentPage: 1, pageSize }, - meta: { params }, + meta: listMeta(params), }) const totalPages = Math.max(1, Math.ceil(firstPage.total / pageSize)) @@ -206,7 +219,7 @@ export const WellShow = () => { ocotilloDataProvider.getList({ resource, pagination: { currentPage: index + 2, pageSize }, - meta: { params }, + meta: listMeta(params), }) ) ) @@ -219,12 +232,12 @@ export const WellShow = () => { const [manualRows, transducerRows] = await Promise.all([ fetchAllPages('observation/groundwater-level', { - thing_id: id, + thing_id: thingId as string | number, }), fetchAllPages( 'observation/transducer-groundwater-level', { - thing_id: id, + thing_id: thingId as string | number, }, 5000 ), @@ -352,7 +365,7 @@ export const WellShow = () => { well={well} rows={[...manualHydrographRows, ...transducerHydrographRows]} dataSource={hydrographDatasource} - isLoading={hydrographQuery.isLoading} + isLoading={hydrographQuery.isPending} /> 299) throw response From 3fa8df7c47fde0e54f3679c10ff7559f3daac832 Mon Sep 17 00:00:00 2001 From: Jeremy Zilar Date: Mon, 27 Apr 2026 15:01:04 -0400 Subject: [PATCH 50/52] Well list: use name_contains for toolbar search and clarify labels WellList passes name_contains (not query) so the staging API can filter by substring on Thing.name. ListPage accepts optional searchAriaLabel for screens that customize server-side search. Well list placeholder and aria text describe searching by well name instead of search all records. --- src/components/ListPage.tsx | 8 ++++++-- src/pages/ocotillo/thing/list.tsx | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/ListPage.tsx b/src/components/ListPage.tsx index 0bf906de..912db162 100644 --- a/src/components/ListPage.tsx +++ b/src/components/ListPage.tsx @@ -132,6 +132,8 @@ type ListPageProps = { searchValue?: string onSearchChange?: (value: string) => void searchPlaceholder?: string + /** Overrides default aria-label on the search input when server search is customized */ + searchAriaLabel?: string } export const ListPage: React.FC = ({ @@ -150,6 +152,7 @@ export const ListPage: React.FC = ({ searchValue, onSearchChange, searchPlaceholder, + searchAriaLabel, }) => { if (!exportProps) { exportProps = { pageSize: 1000 } @@ -303,9 +306,10 @@ export const ListPage: React.FC = ({ sx={{ fontSize: 14, flex: 1 }} inputProps={{ 'aria-label': - searchMode === 'server' + searchAriaLabel ?? + (searchMode === 'server' ? 'Search all records' - : 'Filter rows on this page', + : 'Filter rows on this page'), }} /> diff --git a/src/pages/ocotillo/thing/list.tsx b/src/pages/ocotillo/thing/list.tsx index d846452e..093ab667 100644 --- a/src/pages/ocotillo/thing/list.tsx +++ b/src/pages/ocotillo/thing/list.tsx @@ -80,7 +80,7 @@ export const WellList: React.FC = () => { meta: { params: { include_contacts: true, - ...(search ? { query: search } : {}), + ...(search ? { name_contains: search } : {}), }, }, pagination: { pageSize: 50 }, @@ -317,6 +317,8 @@ export const WellList: React.FC = () => { searchMode="server" searchValue={searchInput} onSearchChange={setSearchInput} + searchPlaceholder="Search by well name" + searchAriaLabel="Search wells by well name" /> ) } From c3f4487e25a7b0555ebaeaaa953bf63792cfd11f Mon Sep 17 00:00:00 2001 From: jross Date: Mon, 27 Apr 2026 14:33:05 -0600 Subject: [PATCH 51/52] feat(map): filter features by selection polygons and update dependencies in effects --- src/pages/ocotillo/map/list.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pages/ocotillo/map/list.tsx b/src/pages/ocotillo/map/list.tsx index 02460eea..0e530cd5 100644 --- a/src/pages/ocotillo/map/list.tsx +++ b/src/pages/ocotillo/map/list.tsx @@ -355,12 +355,18 @@ export const MapView: React.FC = () => { layers: renderedLayerIds, }) + // Filter by selection polygons if they exist + const filteredFeatures = filterLayerFeaturesBySelection( + renderedFeatures, + selectionFeatures + ) + const grouped = new Map< string, { label: string; features: any[]; seenIds: Set } >() - for (const feature of renderedFeatures) { + for (const feature of filteredFeatures) { const renderedLayerId = String(feature?.layer?.id || '') if (!renderedLayerId.startsWith('location-')) continue @@ -412,7 +418,7 @@ export const MapView: React.FC = () => { window.cancelAnimationFrame(idleFrame) map?.off?.('idle', handleMapIdle) } - }, [THING_LAYERS, viewportBbox, visibleLayerLabels, visibleLayers]) + }, [THING_LAYERS, viewportBbox, visibleLayerLabels, visibleLayers, selectionFeatures]) const selectedMajorChemistryPoints = useMemo( () => @@ -719,7 +725,7 @@ export const MapView: React.FC = () => { useEffect(() => { setVisibleFeaturesPage(1) - }, [viewportBbox, visibleLayers]) + }, [viewportBbox, visibleLayers, selectionFeatures]) useEffect(() => { if (!isMajorChemistryVisible) { From 85aec546e8169d99fc804a45cd639f09dda9f3e7 Mon Sep 17 00:00:00 2001 From: jross Date: Mon, 27 Apr 2026 14:45:18 -0600 Subject: [PATCH 52/52] fix(map): update selection features to use selectionPolygons for improved list updates --- src/pages/ocotillo/map/list.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ocotillo/map/list.tsx b/src/pages/ocotillo/map/list.tsx index 0e530cd5..7a58f288 100644 --- a/src/pages/ocotillo/map/list.tsx +++ b/src/pages/ocotillo/map/list.tsx @@ -418,7 +418,7 @@ export const MapView: React.FC = () => { window.cancelAnimationFrame(idleFrame) map?.off?.('idle', handleMapIdle) } - }, [THING_LAYERS, viewportBbox, visibleLayerLabels, visibleLayers, selectionFeatures]) + }, [THING_LAYERS, viewportBbox, visibleLayerLabels, visibleLayers, selectionPolygons]) const selectedMajorChemistryPoints = useMemo( () => @@ -725,7 +725,7 @@ export const MapView: React.FC = () => { useEffect(() => { setVisibleFeaturesPage(1) - }, [viewportBbox, visibleLayers, selectionFeatures]) + }, [viewportBbox, visibleLayers, selectionPolygons]) useEffect(() => { if (!isMajorChemistryVisible) {