gui: always allow pausing automation; only gate starting/resuming

The play/pause toggle ran its start-time checks (beamline state, busy, baton,
maintenance) before the pause branch, so when running you could be blocked from
pausing if the beamline was in the wrong state or busy.

Handle the pause toggle first and return immediately (unconditional), and run
the start-condition gates only when starting/resuming from paused.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
appleb_m
2026-06-26 09:58:05 +02:00
co-authored by Claude Opus 4.8
parent 53e29bece3
commit 48111e5718
+76 -70
View File
@@ -268,6 +268,20 @@ class SampleQueuePanel(QFrame):
def run(self):
self.__recovery_timer.stop()
# Pausing must ALWAYS be possible, regardless of beamline state, busy
# flag, baton or maintenance. Only starting/resuming is gated on
# conditions, so handle the pause toggle first and return immediately.
if not self.__pause:
self.__set_to_pause = True
self.__pause = True
self.table_model.set_running(False)
self.play_button.setText("▶ Run")
self._emit_samples_in_queue_changed()
self.automation_running_changed.emit(False)
return
# --- Starting/resuming: require the beamline to be in a good state. ---
checks_enabled = self._checks_enabled()
if checks_enabled:
if self.__warning_msg_box:
@@ -282,82 +296,74 @@ class SampleQueuePanel(QFrame):
)
return
if self.__pause:
if self.__busy:
logger.error(f"Cannot run automation while beamline is busy. Busy flag = {self.__busy}")
self.show_error_dialog(
title="Beamline is busy",
msg="Cannot run automation while beamline is busy",
info="Please wait until beamline is idle "
"or contact your local contact for support",
)
return
if self.__busy:
logger.error(f"Cannot run automation while beamline is busy. Busy flag = {self.__busy}")
self.show_error_dialog(
title="Beamline is busy",
msg="Cannot run automation while beamline is busy",
info="Please wait until beamline is idle "
"or contact your local contact for support",
)
return
if self.__baton_holder is SessionsStateEnum.Vacant:
self.show_error_dialog(
title="Session is vacant",
msg="Starting automation while session is vacant is not currently implemented",
info="Please grab the baton before continuing "
"or contact your local contact for support",
)
return
if self.__baton_holder is SessionsStateEnum.Vacant:
self.show_error_dialog(
title="Session is vacant",
msg="Starting automation while session is vacant is not currently implemented",
info="Please grab the baton before continuing "
"or contact your local contact for support",
)
return
elif self.__baton_holder is not SessionsStateEnum.OwnedByYou:
self.show_error_dialog(
title="You do not hold the baton",
msg="You do not hold the baton.",
info="Please request the baton if it is your shift."
"If your baton request is denied and it should be the start of your shift,"
"please contact your local contact for support",
)
return
elif self.__baton_holder is not SessionsStateEnum.OwnedByYou:
self.show_error_dialog(
title="You do not hold the baton",
msg="You do not hold the baton.",
info="Please request the baton if it is your shift."
"If your baton request is denied and it should be the start of your shift,"
"please contact your local contact for support",
)
return
if self.__beamline_state is BeamlineStateEnum.Maintenance:
self.show_error_dialog(
title="Maintenance mode",
msg="Cannot run automation while beamline is in maintenance mode",
info=("Change to safe state such as Sample Exchange before trying to continue. "
"If this issue persists please contact your local contact for support."),
)
return
if self.__beamline_state is BeamlineStateEnum.Maintenance:
self.show_error_dialog(
title="Maintenance mode",
msg="Cannot run automation while beamline is in maintenance mode",
info=("Change to safe state such as Sample Exchange before trying to continue. "
"If this issue persists please contact your local contact for support."),
)
return
if len(self.table_model.samples) > 0:
if checks_enabled:
bad = self._bad_conditions()
if bad:
logger.warning(f"Cannot start automation; beamline not ready: {bad}")
self.show_error_dialog(
title="Beamline not ready",
msg="Cannot start automation:\n- " + "\n- ".join(bad),
info="Fix the above, or untick 'Pause on bad conditions' for testing.",
)
return
if len(self.table_model.samples) > 0:
if checks_enabled:
bad = self._bad_conditions()
if bad:
logger.warning(f"Cannot start automation; beamline not ready: {bad}")
self.show_error_dialog(
title="Beamline not ready",
msg="Cannot start automation:\n- " + "\n- ".join(bad),
info="Fix the above, or untick 'Pause on bad conditions' for testing.",
)
return
self.table_model.set_running(True)
self.__set_to_pause = False
self.__pause = False
self.play_button.setText("⏸ Pause")
current = self.table_model.samples[0]
self._current_db_id = current.db_id
self._emit_samples_in_queue_changed()
self.automation_running_changed.emit(True)
self.auto_scan.emit(current)
self.viewer_track_online.emit()
else:
logger.debug("No samples in queue, skipping")
self.show_error_dialog(
title="No Samples in Queue",
msg="Cannot run automation as there are no samples in the queue.",
info="Please add samples to the queue.",
)
return
else:
self.__set_to_pause = True
self.__pause = True
self.table_model.set_running(False)
self.play_button.setText("▶ Run")
self.table_model.set_running(True)
self.__set_to_pause = False
self.__pause = False
self.play_button.setText("⏸ Pause")
current = self.table_model.samples[0]
self._current_db_id = current.db_id
self._emit_samples_in_queue_changed()
self.automation_running_changed.emit(False)
self.automation_running_changed.emit(True)
self.auto_scan.emit(current)
self.viewer_track_online.emit()
else:
logger.debug("No samples in queue, skipping")
self.show_error_dialog(
title="No Samples in Queue",
msg="Cannot run automation as there are no samples in the queue.",
info="Please add samples to the queue.",
)
return
def clear(self):
self.table_model.clearSamples()