Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
902b4d5
Add feature spec for well data relationships
kbighorse Jan 22, 2026
ca6a820
Add relationship navigation scenario to feature spec
kbighorse Jan 22, 2026
b2ab2c5
Formatting changes
kbighorse Jan 22, 2026
175335c
Merge branch 'staging' into feature/thing-fk-enforcement
kbighorse Jan 26, 2026
e355b30
test: add failing tests for Thing FK enforcement (Issue #363)
kbighorse Jan 26, 2026
7e73805
test: update minimal creation tests to require thing_id
kbighorse Jan 26, 2026
8230cd8
feat: add FK enforcement to NMA legacy models (Issue #363)
kbighorse Jan 26, 2026
6e297d5
migrate: add nma_pk_location and enforce thing_id NOT NULL
kbighorse Jan 26, 2026
d9c151c
Formatting changes
kbighorse Jan 26, 2026
81605ba
fix: add nma_pk_location to thing_version table
kbighorse Jan 26, 2026
9dec608
fix: address PR review comments
kbighorse Jan 26, 2026
ea6926c
Formatting changes
kbighorse Jan 26, 2026
cf5dbd9
fix: correct duplicate NMA_ prefix in BDD step imports
kbighorse Jan 26, 2026
464a6cf
fix(tests): restore test database configuration
kbighorse Jan 28, 2026
8e84e35
fix(tests): add required fields and fix cascade delete tests
kbighorse Jan 28, 2026
f24ad39
refactor(models): migrate NMA tables to Integer PKs with nma_ prefix
kbighorse Jan 28, 2026
a9f002b
refactor(transfers): update column mappings for Integer PK schema
kbighorse Jan 28, 2026
2587dc6
refactor(admin): update views for Integer PK schema
kbighorse Jan 28, 2026
620afd0
test(unit): update NMA legacy model tests for Integer PK schema
kbighorse Jan 28, 2026
9302064
test(integration): update relationship tests for Integer PK schema
kbighorse Jan 28, 2026
6845535
feat(alembic): add Integer PK migration for NMA legacy tables
kbighorse Jan 28, 2026
e19cf02
Formatting changes
kbighorse Jan 28, 2026
897d663
Merge branch 'staging' into feature/thing-fk-enforcement
kbighorse Jan 28, 2026
bba4313
fix: update admin views and tests for Integer PK schema
kbighorse Jan 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 70 additions & 36 deletions admin/views/associated_data.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# ===============================================================================
# Copyright 2026
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===============================================================================
"""
AssociatedDataAdmin view for legacy NMA_AssociatedData.

Updated for Integer PK schema:
- id: Integer PK (autoincrement)
- nma_assoc_id: Legacy UUID PK (AssocID), UNIQUE for audit
- nma_location_id: Legacy LocationId UUID, UNIQUE
- nma_point_id: Legacy PointID string
- nma_object_id: Legacy OBJECTID, UNIQUE
"""

from starlette.requests import Request

from admin.views.base import OcotilloModelView


Expand All @@ -12,68 +40,74 @@ class AssociatedDataAdmin(OcotilloModelView):
label = "NMA Associated Data"
icon = "fa fa-link"

# Pagination
page_size = 50
page_size_options = [25, 50, 100, 200]
# Integer PK
pk_attr = "id"
pk_type = int

def can_create(self, request: Request) -> bool:
return False

def can_edit(self, request: Request) -> bool:
return False

def can_delete(self, request: Request) -> bool:
return False

# ========== List View ==========

list_fields = [
"location_id",
"point_id",
"assoc_id",
"id",
"nma_assoc_id",
"nma_location_id",
"nma_point_id",
"nma_object_id",
"notes",
"formation",
"object_id",
"thing_id",
]

sortable_fields = [
"assoc_id",
"object_id",
"point_id",
"id",
"nma_assoc_id",
"nma_object_id",
"nma_point_id",
]

fields_default_sort = [("point_id", False), ("object_id", False)]
fields_default_sort = [("nma_point_id", False), ("nma_object_id", False)]

searchable_fields = [
"point_id",
"assoc_id",
"nma_point_id",
"nma_assoc_id",
"notes",
"formation",
]

# ========== Detail View ==========
page_size = 50
page_size_options = [25, 50, 100, 200]

# ========== Form View ==========

fields = [
"location_id",
"point_id",
"assoc_id",
"id",
"nma_assoc_id",
"nma_location_id",
"nma_point_id",
"nma_object_id",
"notes",
"formation",
"object_id",
"thing_id",
]

# ========== Legacy Field Labels ==========
field_labels = {
"location_id": "LocationId",
"point_id": "PointID",
"assoc_id": "AssocID",
"id": "ID",
"nma_assoc_id": "NMA AssocID (Legacy)",
"nma_location_id": "NMA LocationId (Legacy)",
"nma_point_id": "NMA PointID (Legacy)",
"nma_object_id": "NMA OBJECTID (Legacy)",
"notes": "Notes",
"formation": "Formation",
"object_id": "OBJECTID",
"thing_id": "ThingID",
"thing_id": "Thing ID",
}

# ========== READ ONLY ==========
enable_publish_actions = (
False # hides publish/unpublish actions inherited from base
)

def can_create(self, request) -> bool:
return False

def can_edit(self, request) -> bool:
return False

def can_delete(self, request) -> bool:
return False
# ============= EOF =============================================
68 changes: 55 additions & 13 deletions admin/views/chemistry_sampleinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
# ===============================================================================
"""
ChemistrySampleInfoAdmin view for legacy Chemistry_SampleInfo.

Updated for Integer PK schema:
- id: Integer PK (autoincrement)
- nma_sample_pt_id: Legacy UUID PK (SamplePtID), UNIQUE for audit
- nma_wclab_id: Legacy WCLab_ID
- nma_sample_point_id: Legacy SamplePointID
- nma_object_id: Legacy OBJECTID, UNIQUE
- nma_location_id: Legacy LocationId UUID
"""

from admin.views.base import OcotilloModelView
Expand All @@ -31,13 +39,18 @@ class ChemistrySampleInfoAdmin(OcotilloModelView):
label = "Chemistry Sample Info"
icon = "fa fa-flask"

# Integer PK
pk_attr = "id"
pk_type = int

# ========== List View ==========

sortable_fields = [
"sample_pt_id",
"object_id",
"sample_point_id",
"wclab_id",
"id",
"nma_sample_pt_id",
"nma_object_id",
"nma_sample_point_id",
"nma_wclab_id",
"collection_date",
"sample_type",
"data_source",
Expand All @@ -48,9 +61,9 @@ class ChemistrySampleInfoAdmin(OcotilloModelView):
fields_default_sort = [("collection_date", True)]

searchable_fields = [
"sample_point_id",
"sample_pt_id",
"wclab_id",
"nma_sample_point_id",
"nma_sample_pt_id",
"nma_wclab_id",
"collected_by",
"analyses_agency",
"sample_notes",
Expand All @@ -70,10 +83,13 @@ class ChemistrySampleInfoAdmin(OcotilloModelView):
# ========== Form View ==========

fields = [
"sample_pt_id",
"sample_point_id",
"object_id",
"wclab_id",
"id",
"nma_sample_pt_id",
"nma_sample_point_id",
"nma_object_id",
"nma_wclab_id",
"nma_location_id",
"thing_id",
"collection_date",
"collection_method",
"collected_by",
Expand All @@ -91,12 +107,38 @@ class ChemistrySampleInfoAdmin(OcotilloModelView):
]

exclude_fields_from_create = [
"object_id",
"id",
"nma_object_id",
]

exclude_fields_from_edit = [
"object_id",
"id",
"nma_object_id",
]

field_labels = {
"id": "ID",
"nma_sample_pt_id": "NMA SamplePtID (Legacy)",
"nma_sample_point_id": "NMA SamplePointID (Legacy)",
"nma_object_id": "NMA OBJECTID (Legacy)",
"nma_wclab_id": "NMA WCLab_ID (Legacy)",
"nma_location_id": "NMA LocationId (Legacy)",
"thing_id": "Thing ID",
"collection_date": "Collection Date",
"collection_method": "Collection Method",
"collected_by": "Collected By",
"analyses_agency": "Analyses Agency",
"sample_type": "Sample Type",
"sample_material_not_h2o": "Sample Material (Not H2O)",
"water_type": "Water Type",
"study_sample": "Study Sample",
"data_source": "Data Source",
"data_quality": "Data Quality",
"public_release": "Public Release",
"added_day_to_date": "Added Day to Date",
"added_month_day_to_date": "Added Month/Day to Date",
"sample_notes": "Sample Notes",
}


# ============= EOF =============================================
70 changes: 46 additions & 24 deletions admin/views/field_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
# ===============================================================================
"""
FieldParametersAdmin view for legacy NMA_FieldParameters.

Updated for Integer PK schema:
- id: Integer PK (autoincrement)
- nma_global_id: Legacy UUID PK (GlobalID), UNIQUE for audit
- chemistry_sample_info_id: Integer FK to NMA_Chemistry_SampleInfo.id
- nma_sample_pt_id: Legacy UUID FK (SamplePtID) for audit
- nma_sample_point_id: Legacy SamplePointID string
- nma_object_id: Legacy OBJECTID
- nma_wclab_id: Legacy WCLab_ID
"""

from starlette.requests import Request
Expand All @@ -33,6 +42,10 @@ class FieldParametersAdmin(OcotilloModelView):
label = "NMA Field Parameters"
icon = "fa fa-tachometer"

# Integer PK
pk_attr = "id"
pk_type = int

def can_create(self, request: Request) -> bool:
return False

Expand All @@ -45,42 +58,47 @@ def can_delete(self, request: Request) -> bool:
# ========== List View ==========

list_fields = [
"global_id",
"sample_pt_id",
"sample_point_id",
"id",
"nma_global_id",
"chemistry_sample_info_id",
"nma_sample_pt_id",
"nma_sample_point_id",
"field_parameter",
"sample_value",
"units",
"notes",
"object_id",
"analyses_agency",
"wc_lab_id",
"nma_wclab_id",
"nma_object_id",
]

sortable_fields = [
"global_id",
"sample_pt_id",
"sample_point_id",
"id",
"nma_global_id",
"chemistry_sample_info_id",
"nma_sample_pt_id",
"nma_sample_point_id",
"field_parameter",
"sample_value",
"units",
"notes",
"analyses_agency",
"wc_lab_id",
"object_id",
"nma_wclab_id",
"nma_object_id",
]

fields_default_sort = [("sample_point_id", True)]
fields_default_sort = [("nma_sample_point_id", True)]

searchable_fields = [
"global_id",
"sample_pt_id",
"sample_point_id",
"nma_global_id",
"nma_sample_pt_id",
"nma_sample_point_id",
"field_parameter",
"units",
"notes",
"analyses_agency",
"wc_lab_id",
"nma_wclab_id",
]

page_size = 50
Expand All @@ -89,29 +107,33 @@ def can_delete(self, request: Request) -> bool:
# ========== Form View ==========

fields = [
"global_id",
"sample_pt_id",
"sample_point_id",
"id",
"nma_global_id",
"chemistry_sample_info_id",
"nma_sample_pt_id",
"nma_sample_point_id",
"field_parameter",
"sample_value",
"units",
"notes",
"object_id",
"nma_object_id",
"analyses_agency",
"wc_lab_id",
"nma_wclab_id",
]

field_labels = {
"global_id": "GlobalID",
"sample_pt_id": "SamplePtID",
"sample_point_id": "SamplePointID",
"id": "ID",
"nma_global_id": "NMA GlobalID (Legacy)",
"chemistry_sample_info_id": "Chemistry Sample Info ID",
"nma_sample_pt_id": "NMA SamplePtID (Legacy)",
"nma_sample_point_id": "NMA SamplePointID (Legacy)",
"field_parameter": "FieldParameter",
"sample_value": "SampleValue",
"units": "Units",
"notes": "Notes",
"object_id": "OBJECTID",
"nma_object_id": "NMA OBJECTID (Legacy)",
"analyses_agency": "AnalysesAgency",
"wc_lab_id": "WCLab_ID",
"nma_wclab_id": "NMA WCLab_ID (Legacy)",
}


Expand Down
Loading
Loading