Three bugs from smoke-testing SlicerOpenLIFU#640.
Bug 1: New target not persisted on Save
Root cause: mutating a nested field of the SlicerOpenLIFUPlanningSession parameter pack (planning_session.session.planning_session.targets = ...) does not automatically re-serialize the outer pack. The SlicerOpenLIFUPlanningSessionWrapper gets deserialized-on-read but never re-serialized-on-mutation.
The legacy OpenLIFUDataLogic.update_underlying_openlifu_session handles this by explicitly reassigning the outer field back to the parameter node after mutation:
parameter_node.loaded_session = session # remember to write the updated session into the parameter node
My new OpenLIFUTargetSelectionLogic does not do the equivalent, so target additions / moves / renames vanish from the openlifu Session by the time save_loaded_session reads it, even though target_nodes (which uses a different serializer path) persists correctly.
Fix:
-
After every mutation, capture the wrapper, mutate the openlifu object, write the wrapper back to the pack, and then reassign the pack to the app state:
wrapper = planning_session.session
wrapper.planning_session.targets = new_target_points
planning_session.session = wrapper
get_app_state().loaded_planning_session = planning_session
-
Extract this into a _persist_planning_session_changes(planning_session) helper so every mutation goes through it and the pattern is documented in one place.
Bug 2: Placement + edit flow leaves fiducial draggable
Newly-placed target fiducials come out of slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode") unlocked (Slicer default), so they stay draggable in 3D even after Add Target completes. And the Edit button on the page currently only toggles cell editability -- it doesn't lock / unlock fiducials at all.
Desired workflow (per user):
- Click Add Target → PLACE mode.
- Click in slice view (or type R / A / S values in the row cells) → target placed, page enters Edit mode focused on the new target.
- User drags the fiducial in slice / 3D views OR edits R / A / S cells to fine-tune.
- Click Done to commit (exits edit mode, all fiducials re-locked).
Editing an existing target: same, minus the placement step. User selects the row and clicks Edit.
Fix:
- When entering edit mode: unlock the currently-selected fiducial (or if none selected, all stay locked). Lock all other targets.
- On selection change while in edit mode: unlock the newly-selected, re-lock the previously-selected.
- When exiting edit mode: lock all target fiducials.
- After
add_target_from_scene: rebuild the table, select the new row, toggle the Edit button ON. Edit button becomes "Done".
- Table
editTriggers follows the mode: NoEditTriggers when off, DoubleClicked | EditKeyPressed | AnyKeyPressed when on.
Optional (deferred): tint the focused fiducial's selected color to yellow while it's the edit-focus, restore its palette color on unfocus. Legacy Pre-Planning did this via a SlicerOpenLIFU.OriginalSelectedColor node attribute. Nice UX cue but not required.
Bug 3: Timeline footer not visible for the new workflow
PAGE_DEFS in host/page_registry.py currently has every page with on_timeline=False, so the timeline strip is hidden everywhere. As the workflow-timeline pages come online (Target Selection first, Virtual Fit / Solution Generator next), they should register on the timeline so the user can see progression and click circles to jump between reachable steps.
Fix:
- Set
OpenLIFUTargetSelection to on_timeline=True. Home / Data Manager / Session Overviews stay off-timeline (they're hubs / entry points, not linear workflow steps).
- Verify the footer's timeline strip renders correctly with one item. The Next button hides itself (one-item timelines have no next step) -- this is expected and correct until Virtual Fit lands.
- When Virtual Fit is added, it will also register on the timeline and the Next button becomes useful.
Acceptance
- Load a Planning Session → Overview → click Edit Targets… → Target Selection opens. Footer shows the timeline strip with a single "Target Selection" step highlighted.
- Click Add Target → click in a slice view → target is placed and locked in 3D (not draggable). Table row appears. Edit button is now labelled Done (edit mode entered). The new row's fiducial is now UNLOCKED and can be dragged.
- Drag the fiducial in the 2D or 3D view → R / A / S cells in the row update to match.
- Edit an R / A / S cell → fiducial moves to match.
- Click Done → edit mode exits, fiducial re-locks (can no longer be dragged). Button label returns to Edit.
- Select an existing target row, click Edit → same behaviour: that row's fiducial unlocks, others stay locked. Click Done → re-locks.
- Save via toolbar → target appears on disk in
subjects/{subject_id}/planning_sessions/{ps_id}/{ps_id}.planning.json inside the openlifu Session's targets list.
- Data Manager and Planning Session Overview show the updated target count after save.
Relates to SlicerOpenLIFU#640, SlicerOpenLIFU#636, SlicerOpenLIFU#631.
Three bugs from smoke-testing SlicerOpenLIFU#640.
Bug 1: New target not persisted on Save
Root cause: mutating a nested field of the
SlicerOpenLIFUPlanningSessionparameter pack (planning_session.session.planning_session.targets = ...) does not automatically re-serialize the outer pack. TheSlicerOpenLIFUPlanningSessionWrappergets deserialized-on-read but never re-serialized-on-mutation.The legacy
OpenLIFUDataLogic.update_underlying_openlifu_sessionhandles this by explicitly reassigning the outer field back to the parameter node after mutation:My new
OpenLIFUTargetSelectionLogicdoes not do the equivalent, so target additions / moves / renames vanish from the openlifu Session by the timesave_loaded_sessionreads it, even thoughtarget_nodes(which uses a different serializer path) persists correctly.Fix:
After every mutation, capture the wrapper, mutate the openlifu object, write the wrapper back to the pack, and then reassign the pack to the app state:
Extract this into a
_persist_planning_session_changes(planning_session)helper so every mutation goes through it and the pattern is documented in one place.Bug 2: Placement + edit flow leaves fiducial draggable
Newly-placed target fiducials come out of
slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode")unlocked (Slicer default), so they stay draggable in 3D even after Add Target completes. And the Edit button on the page currently only toggles cell editability -- it doesn't lock / unlock fiducials at all.Desired workflow (per user):
Editing an existing target: same, minus the placement step. User selects the row and clicks Edit.
Fix:
add_target_from_scene: rebuild the table, select the new row, toggle the Edit button ON. Edit button becomes "Done".editTriggersfollows the mode:NoEditTriggerswhen off,DoubleClicked | EditKeyPressed | AnyKeyPressedwhen on.Optional (deferred): tint the focused fiducial's selected color to yellow while it's the edit-focus, restore its palette color on unfocus. Legacy Pre-Planning did this via a
SlicerOpenLIFU.OriginalSelectedColornode attribute. Nice UX cue but not required.Bug 3: Timeline footer not visible for the new workflow
PAGE_DEFSinhost/page_registry.pycurrently has every page withon_timeline=False, so the timeline strip is hidden everywhere. As the workflow-timeline pages come online (Target Selection first, Virtual Fit / Solution Generator next), they should register on the timeline so the user can see progression and click circles to jump between reachable steps.Fix:
OpenLIFUTargetSelectiontoon_timeline=True. Home / Data Manager / Session Overviews stay off-timeline (they're hubs / entry points, not linear workflow steps).Acceptance
subjects/{subject_id}/planning_sessions/{ps_id}/{ps_id}.planning.jsoninside the openlifu Session'stargetslist.Relates to SlicerOpenLIFU#640, SlicerOpenLIFU#636, SlicerOpenLIFU#631.