From aaa00d030f1fc686d3cf334df7fff43600abdb97 Mon Sep 17 00:00:00 2001 From: appleb_m Date: Fri, 1 May 2026 18:07:50 +0200 Subject: [PATCH] GUI: automation progress widget bug fix where it sometimes wouldn't update if automation paused or finished. --- src/aare/gui/main_window.py | 2 ++ src/aare/gui/panels/automation_panel.py | 42 ++++++++++++++++++++--- src/aare/gui/panels/sample_queue_panel.py | 6 ++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/aare/gui/main_window.py b/src/aare/gui/main_window.py index 81337b70..9ec5780a 100644 --- a/src/aare/gui/main_window.py +++ b/src/aare/gui/main_window.py @@ -320,12 +320,14 @@ class MainWindow(QMainWindow): self.tabifyDockWidget(self.manual_sample_dock, self.automation_progress_dock) self.tabifyDockWidget(self.automation_progress_dock, self.log_dock) + self.job_list_panel.samples_in_queue_changed.connect( self.automation_progress_panel.set_samples_in_queue ) self.automation_progress_panel.set_samples_in_queue( len(self.job_list_panel.table_model.samples) ) + self.automation_progress_panel.set_running(self.job_list_panel.is_running()) # smargon trace panel self.smargon_trace_panel = SmargonTracePanel() diff --git a/src/aare/gui/panels/automation_panel.py b/src/aare/gui/panels/automation_panel.py index bdea5347..1baa2070 100644 --- a/src/aare/gui/panels/automation_panel.py +++ b/src/aare/gui/panels/automation_panel.py @@ -1,5 +1,6 @@ from __future__ import annotations +import copy import time from datetime import datetime @@ -32,6 +33,7 @@ class AutomationProgressWidget(QWidget): self._labels: dict[WorkflowStateKind, QLabel] = {} self._title_label: QLabel | None = None self._stats_label: QLabel | None = None + self._is_paused = False self._refresh_timer = QTimer(self) self._refresh_timer.setInterval(1000) self._refresh_timer.timeout.connect(self._refresh_live_metrics) @@ -68,6 +70,7 @@ class AutomationProgressWidget(QWidget): def clear(self) -> None: self._gui_samples_in_queue = 0 + self._is_paused = False empty = AutomationProgress( current_step=None, steps=[ @@ -180,6 +183,35 @@ class AutomationProgressWidget(QWidget): return self.set_progress(self._progress) + @Slot(bool) + def set_running(self, running: bool) -> None: + self._is_paused = not running + + if self._progress is None: + return + + progress = copy.deepcopy(self._progress) + + final_step = next( + (step for step in progress.steps if step.step == WorkflowStateKind.FINAL), + None, + ) + + if self._is_paused: + self._refresh_timer.stop() + progress.current_step = "Paused" + if final_step is not None: + final_step.status = StepStatus.PAUSED + final_step.message = "Automation paused" + else: + if final_step is not None and final_step.status == StepStatus.PAUSED: + final_step.status = StepStatus.PENDING + final_step.message = "" + if self._has_live_timing(progress): + self._refresh_timer.start() + + self.set_progress(progress) + @Slot(int) def set_samples_in_queue(self, count: int) -> None: self._gui_samples_in_queue = max(0, int(count)) @@ -190,7 +222,7 @@ class AutomationProgressWidget(QWidget): def set_progress(self, progress: AutomationProgress) -> None: self._progress = progress - if self._has_live_timing(progress): + if self._has_live_timing(progress) and not self._is_paused: if not self._refresh_timer.isActive(): self._refresh_timer.start() else: @@ -200,7 +232,7 @@ class AutomationProgressWidget(QWidget): measured_avg_seconds = progress.avg_time_per_sample if progress.avg_time_per_sample > 0 else None displayed_avg_seconds = measured_avg_seconds or self.DEFAULT_SAMPLE_ESTIMATE_S - current_step = progress.current_step or "Idle" + current_step = "Paused" if self._is_paused else (progress.current_step or "Idle") current_sample = progress.current_sample_name or "None" samples_left = ( self._gui_samples_in_queue @@ -208,7 +240,7 @@ class AutomationProgressWidget(QWidget): else max(0, int(progress.samples_in_queue or 0)) ) - has_active_sample = self._has_active_sample(progress) + has_active_sample = self._has_active_sample(progress) and not self._is_paused current_sample_elapsed = self._current_sample_elapsed_seconds(progress) if progress.finished or not has_active_sample: @@ -254,7 +286,9 @@ class AutomationProgressWidget(QWidget): label.setStyleSheet(self._style_for_status(step_state.status)) if self._title_label is not None: - if progress.finished: + if self._is_paused: + self._title_label.setText("Automation progress — Paused") + elif progress.finished: if progress.success is True: self._title_label.setText("Automation progress — Finished") elif progress.success is False: diff --git a/src/aare/gui/panels/sample_queue_panel.py b/src/aare/gui/panels/sample_queue_panel.py index 79afdbb9..4ae7550d 100644 --- a/src/aare/gui/panels/sample_queue_panel.py +++ b/src/aare/gui/panels/sample_queue_panel.py @@ -22,6 +22,7 @@ class SampleQueuePanel(QFrame): park_and_dry = Signal() viewer_track_online = Signal() samples_in_queue_changed = Signal(int) + automation_running_changed = Signal(bool) def __init__(self, parent=None, samples: SampleShortInfoList | None = None): super().__init__(parent) @@ -96,6 +97,7 @@ class SampleQueuePanel(QFrame): # Add the button layout to the main layout layout.addLayout(button_layout) self._emit_samples_in_queue_changed() + self.automation_running_changed.emit(False) def _samples_left_in_queue(self) -> int: total = len(self.table_model.samples) @@ -213,6 +215,7 @@ class SampleQueuePanel(QFrame): 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: @@ -220,10 +223,12 @@ class SampleQueuePanel(QFrame): self.__pause = True self.play_button.setText("▶ Run") self._emit_samples_in_queue_changed() + self.automation_running_changed.emit(False) def clear(self): self.table_model.clearSamples() self._emit_samples_in_queue_changed() + self.automation_running_changed.emit(False) @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): @@ -238,6 +243,7 @@ class SampleQueuePanel(QFrame): if set_id_to_None: self._current_db_id = None self._emit_samples_in_queue_changed() + self.automation_running_changed.emit(False) @Slot(int, bool) def automated_scan_done(self, db_id: int, success: bool, reply:str):