feat: show spreadsheet params in sample list

Add Oscillation, Exposure, Total range and Transmission columns to the
dewar sample table, read from SampleShortInfo.aaredb_params (already
filled by spreadsheetupdater from AareDB, so no server change).
Transmission is shown as percent like the user spreadsheet.

The new columns are nullable, so the header sort key now puts None last
instead of raising on None < float.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 16:54:43 +02:00
committed by duan_j
co-authored by Claude Fable 5.1
parent 85ac38e7ea
commit a2c5ed3d5c
2 changed files with 49 additions and 2 deletions
+24 -2
View File
@@ -43,7 +43,19 @@ def get_entry(sample: SampleShortInfo, column: int):
return sample.screening_count
elif column == 10:
return sample.rotation_count
# Data-collection params straight from the AareDB spreadsheet (filled by
# spreadsheetupdater). Nullable: samples without params show blank.
elif column == 11:
return sample.aaredb_params.oscillation if sample.aaredb_params else None
elif column == 12:
return sample.aaredb_params.exposure if sample.aaredb_params else None
elif column == 13:
return sample.aaredb_params.totalangle if sample.aaredb_params else None
elif column == 14:
# Model holds a 0-1 fraction; users think in spreadsheet percent.
t = sample.aaredb_params.transmission if sample.aaredb_params else None
return None if t is None else round(t * 100, 1)
elif column == 15:
return sample.comment
return ""
@@ -74,6 +86,10 @@ class UserSampleSpreadsheet(QAbstractTableModel):
# collected, so Screening sits left of Rotation.
"Screening count",
"Rotation count",
"Oscillation (°)",
"Exposure (s)",
"Total range (°)",
"Transmission (%)",
"Comment",
]
self.current_sample = current_sample
@@ -261,10 +277,16 @@ class UserSampleSpreadsheet(QAbstractTableModel):
), # Reverse for descending order
)
else:
# Sort the samples based on the specified column and order
# Sort the samples based on the specified column and order.
# Nullable columns (params, comment): None sorts last, never
# compared against a real value (None < float raises).
def _key(row):
v = get_entry(row, self._sort_col)
return (v is None, "" if v is None else v)
self._sorted_samples = sorted(
filtered,
key=lambda row: get_entry(row, self._sort_col),
key=_key,
reverse=(
self._sort_order == Qt.SortOrder.DescendingOrder
), # Reverse for descending order
+25
View File
@@ -263,3 +263,28 @@ def test_mime_data_round_trips_for_chip_drops(status_model):
samples = SampleShortInfoList.model_validate_json(payload.text())
assert len(samples.s) == 2
assert samples.s[0].db_id == model.get_id(0).db_id
def test_spreadsheet_param_columns(status_model):
from aarecommon.models.models import DataCollectionParameters
model = status_model
hdr = model.header
osc, exp, tot, trans = (
hdr.index("Oscillation (°)"),
hdr.index("Exposure (s)"),
hdr.index("Total range (°)"),
hdr.index("Transmission (%)"),
)
model.get_id(_row_of(model, 1)).aaredb_params = DataCollectionParameters(
oscillation=0.1, exposure=0.01, totalangle=360, transmission=0.125
)
row = _row_of(model, 1)
d = lambda c: model.data(model.index(row, c), Qt.ItemDataRole.DisplayRole)
assert (d(osc), d(exp), d(tot), d(trans)) == (0.1, 0.01, 360, 12.5)
# No params -> blank, and sorting a mostly-None column must not raise;
# the real value sorts first.
assert model.data(model.index(_row_of(model, 2), osc), Qt.ItemDataRole.DisplayRole) is None
model.sort(osc, Qt.SortOrder.AscendingOrder)
assert model.get_id(0).db_id == 1
assert model.headerData(hdr.index("Comment"), Qt.Orientation.Horizontal, 0) == "Comment"