fix(flomni,bec_widgets): treat incomplete jobs as a reorder floor, like running
Sort mode and tomo_queue_move() let a pending job be dragged/moved
visually ahead of an incomplete one. Harmless to actual run order --
tomo_queue_execute()'s pick-next loop always resumes the first
running/incomplete job it finds regardless of list position -- but
confusing to read, since list order looked like run order and wasn't.
Narrows the GUI's _MOVABLE_STATUSES to ("pending",) and the CLI's
floor check to the highest index among all running/incomplete jobs,
not just the running one. Found while testing the reorder feature
against a real interrupted scan.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3861,13 +3861,16 @@ class Flomni(
|
||||
print(f"Deleted tomo queue job #{index} ({job['label']}).")
|
||||
|
||||
def tomo_queue_move(self, index: int, new_index: int) -> None:
|
||||
"""Move a pending/incomplete tomo queue job to a new position.
|
||||
"""Move a pending tomo queue job to a new position.
|
||||
|
||||
Only ``pending``/``incomplete`` jobs can be reordered -- a
|
||||
``running`` or ``done`` job stays put. A move is also refused if it
|
||||
would place the job at or above the position of the job currently
|
||||
``running`` (that job is a hard floor: nothing may be reordered
|
||||
ahead of the thing already in progress). Takes effect at the next
|
||||
Only ``pending`` jobs can be reordered -- a ``running``,
|
||||
``incomplete``, or ``done`` job stays put. ``incomplete`` is a floor
|
||||
exactly like ``running``: tomo_queue_execute()'s pick-next loop
|
||||
always resumes whichever of the two it finds first, regardless of
|
||||
list order, so a pending job moved "ahead" of one in the list would
|
||||
visually suggest a run order that isn't real. A move is also
|
||||
refused if it would place the job at or above the position of any
|
||||
currently ``running``/``incomplete`` job. Takes effect at the next
|
||||
job boundary if the queue is executing (see tomo_queue_execute()'s
|
||||
pick-next model).
|
||||
|
||||
@@ -3882,16 +3885,19 @@ class Flomni(
|
||||
if not 0 <= new_index < len(jobs):
|
||||
raise ValueError(f"tomo_queue_move: new_index {new_index} out of range.")
|
||||
job = jobs[index]
|
||||
if job.get("status", "pending") not in ("pending", "incomplete"):
|
||||
if job.get("status", "pending") != "pending":
|
||||
raise ValueError(
|
||||
f"tomo_queue_move: job #{index} is '{job.get('status')}' -- only "
|
||||
"pending/incomplete jobs can be reordered."
|
||||
"pending jobs can be reordered."
|
||||
)
|
||||
running_idx = next((i for i, j in enumerate(jobs) if j.get("status") == "running"), None)
|
||||
if running_idx is not None and new_index <= running_idx:
|
||||
floor_indices = [
|
||||
i for i, j in enumerate(jobs) if j.get("status") in ("running", "incomplete")
|
||||
]
|
||||
if floor_indices and new_index <= max(floor_indices):
|
||||
raise ValueError(
|
||||
f"tomo_queue_move: can't move to position {new_index} -- job "
|
||||
f"#{running_idx} is currently running and is a hard floor for reordering."
|
||||
f"#{max(floor_indices)} is running/incomplete and is a hard floor "
|
||||
"for reordering."
|
||||
)
|
||||
self._tomo_queue_proxy.move(index, new_index)
|
||||
print(f"Moved tomo queue job #{index} -> #{new_index} ({job['label']}).")
|
||||
|
||||
@@ -1043,10 +1043,14 @@ class TomoQueueDialog(QDialog):
|
||||
_POLL_MS = 2000
|
||||
|
||||
# Statuses a job must have to be reorderable in sort mode. "running" and
|
||||
# "done" are excluded: running is a hard floor (plan section 6.4), done
|
||||
# is pinned for readability (plan section 6.3) even though moving it
|
||||
# would be harmless.
|
||||
_MOVABLE_STATUSES = ("pending", "incomplete")
|
||||
# "incomplete" are both hard floors: tomo_queue_execute()'s pick-next
|
||||
# loop always resumes whichever of them it finds first, regardless of
|
||||
# list position (see TOMO_QUEUE_TESTING.md's resume-before-fresh
|
||||
# rationale) -- so a pending job dragged "ahead" of one in the list
|
||||
# would visually suggest a run order that isn't real. "done" is pinned
|
||||
# for readability (plan section 6.3) even though moving it would be
|
||||
# harmless.
|
||||
_MOVABLE_STATUSES = ("pending",)
|
||||
|
||||
def __init__(self, client, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -1125,7 +1129,7 @@ class TomoQueueDialog(QDialog):
|
||||
self._btn_sort = QPushButton("Sort queue…")
|
||||
self._btn_sort.setCheckable(True)
|
||||
self._btn_sort.setToolTip(
|
||||
"Reorder pending/incomplete jobs. The running job (if any) and "
|
||||
"Reorder pending jobs. The running/incomplete job (if any) and "
|
||||
"done jobs stay put."
|
||||
)
|
||||
self._btn_move_up = QPushButton("▲ Move up")
|
||||
@@ -1279,10 +1283,10 @@ class TomoQueueDialog(QDialog):
|
||||
|
||||
def _move_selected(self, direction: int) -> None:
|
||||
"""Swap the selected row with the adjacent one. Only ever swaps two
|
||||
movable (pending/incomplete) rows -- a running or done neighbour
|
||||
blocks the swap, which is what keeps the running job as a hard
|
||||
floor (plan section 6.4) and done jobs pinned (section 6.3) without
|
||||
needing separate index-range bookkeeping.
|
||||
movable (pending) rows -- a running, incomplete, or done neighbour
|
||||
blocks the swap, which is what keeps the running/incomplete job as
|
||||
a hard floor (plan section 6.4) and done jobs pinned (section 6.3)
|
||||
without needing separate index-range bookkeeping.
|
||||
"""
|
||||
row = self._selected_single_row()
|
||||
jobs = self._load_queue()
|
||||
|
||||
Reference in New Issue
Block a user