From 1b3b144265b825ffbe27fca63f1593b198f73861 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 12 Aug 2026 15:20:11 +0200 Subject: [PATCH 1/4] refactor: remove dead code --- src/aare/devices/bec_worker.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/aare/devices/bec_worker.py b/src/aare/devices/bec_worker.py index d6a5c1f8..c0ca889e 100644 --- a/src/aare/devices/bec_worker.py +++ b/src/aare/devices/bec_worker.py @@ -270,12 +270,6 @@ class BECClientWorker: return True return self.planner.is_state(state) - def current_state(self): - if self.simulated: - logger.debug("Simulating check_beamline_state") - return BeamlineState.MAINTENANCE - return self.planner.current_state() - def list_position_devices(self): """List the position devices available for the BEC worker""" if self.simulated or self.position_devices is None: -- 2.54.0 From 362880ec820953e95c14bfd3a1c3fa3351030643 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 12 Aug 2026 15:29:41 +0200 Subject: [PATCH 2/4] fix: rename free beamline to clear busy --- src/aare/daq/server.py | 6 ++++-- .../gui/panels/beamline_recovery_panel.py | 21 ++++++++++--------- src/aare/gui/threads/daq_worker.py | 6 +++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/aare/daq/server.py b/src/aare/daq/server.py index e0f5f3e7..6d847d30 100644 --- a/src/aare/daq/server.py +++ b/src/aare/daq/server.py @@ -1483,8 +1483,10 @@ async def take_over_beamline( return "OK" -@app.post("/state/free_beamline") -async def free_beamline(payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme)) -> str: +@app.post("/state/force_clear_busy") +async def force_clear_busy( + payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme) +) -> str: """ Clear the beamline busy flag. Staff only. diff --git a/src/aare/gui/panels/beamline_recovery_panel.py b/src/aare/gui/panels/beamline_recovery_panel.py index aa5c5a85..09baee07 100644 --- a/src/aare/gui/panels/beamline_recovery_panel.py +++ b/src/aare/gui/panels/beamline_recovery_panel.py @@ -106,8 +106,8 @@ class RecoveryPanel(QWidget): self._take_over_btn.clicked.connect(self._take_over_beamline) layout.addWidget(self._take_over_btn) - self._free_beamline_btn = QPushButton("Free beamline", self) - self._free_beamline_btn.setStyleSheet( + self._force_clear_busy_btn = QPushButton("Clear busy flag", self) + self._force_clear_busy_btn.setStyleSheet( card_style( PENDING_CARD_BG, PENDING_CARD_BORDER, @@ -116,8 +116,8 @@ class RecoveryPanel(QWidget): extra="padding: 10px; font-weight: 600;", ) ) - self._free_beamline_btn.clicked.connect(self._free_beamline) - layout.addWidget(self._free_beamline_btn) + self._force_clear_busy_btn.clicked.connect(self._force_clear_busy) + layout.addWidget(self._force_clear_busy_btn) self._recover_beamline_btn = QPushButton("Recover beamline", self) self._recover_beamline_btn.setStyleSheet( @@ -201,8 +201,8 @@ class RecoveryPanel(QWidget): else "Disabled because no mounted sample is visible in current status." ) - self._free_beamline_btn.setEnabled(beamline_busy) - self._free_beamline_btn.setToolTip( + self._force_clear_busy_btn.setEnabled(beamline_busy) + self._force_clear_busy_btn.setToolTip( "" if beamline_busy else "Disabled because beamline does not currently appear busy." ) @@ -238,16 +238,17 @@ class RecoveryPanel(QWidget): self._daq.take_over_beamline(code) @Slot() - def _free_beamline(self) -> None: + def _force_clear_busy(self) -> None: if not self._confirm( - "Free beamline", "This will clear the beamline busy flag.\n\nDo you want to continue?" + "Clear busy flag", + "This will clear the beamline busy flag.\nAfter this, the server may still report that it is 'moving' if it is not in a defined state. You may then force the server into maintenance mode to recover.\nDo you want to continue?", ): return - code = self._prompt_recovery_code("Free beamline") + code = self._prompt_recovery_code("Clear busy flag") if not code: return self._last_action.setText("Last action: Clearing beamline busy flag...") - self._daq.free_beamline(code) + self._daq.force_clear_busy(code) @Slot() def _recover_beamline(self) -> None: diff --git a/src/aare/gui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py index bd8ef669..98e6e5e9 100644 --- a/src/aare/gui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -872,12 +872,12 @@ class DAQWorker(QObject): self.generic_post("state/xtal_snapshot") @Slot(str) - def free_beamline(self, confirmation_code: str): + def force_clear_busy(self, confirmation_code: str): if self._base_url is None: - logger.info("POST /state/free_beamline") + logger.info("POST /state/force_clear_busy") return - request = QNetworkRequest(QUrl(f"{self._base_url}/state/free_beamline")) + request = QNetworkRequest(QUrl(f"{self._base_url}/state/force_clear_busy")) request.setRawHeader(b"Authorization", f"Bearer {self._token}".encode()) request.setRawHeader(b"Content-Type", b"application/json") body = json.dumps({"confirmation_code": confirmation_code}) -- 2.54.0 From 63ea060fb9dc4df994cc266b7084e4ba7c4c48db Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 12 Aug 2026 15:36:01 +0200 Subject: [PATCH 3/4] fix: rename recover beamline to force maintenance --- src/aare/daq/server.py | 6 +++--- src/aare/gui/panels/beamline_recovery_panel.py | 18 +++++++++--------- src/aare/gui/threads/daq_worker.py | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/aare/daq/server.py b/src/aare/daq/server.py index 6d847d30..6a473545 100644 --- a/src/aare/daq/server.py +++ b/src/aare/daq/server.py @@ -1508,8 +1508,8 @@ async def force_clear_busy( return "OK" -@app.post("/recovery/recover_beamline") -async def recover_beamline( +@app.post("/recovery/force_maintenance_state") +async def force_maintenance_state( payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme) ) -> dict: """ @@ -1535,7 +1535,7 @@ async def recover_beamline( cfg.state = BeamlineStateEnum.Maintenance logger.warning( - "Beamline recovery action executed.", + "Beamline recovery action executed - forced maintenance state.", extra={ "session": getattr(data, "session", None), "previous_state": getattr(prev_state, "name", str(prev_state)), diff --git a/src/aare/gui/panels/beamline_recovery_panel.py b/src/aare/gui/panels/beamline_recovery_panel.py index 09baee07..7e4a5822 100644 --- a/src/aare/gui/panels/beamline_recovery_panel.py +++ b/src/aare/gui/panels/beamline_recovery_panel.py @@ -119,8 +119,8 @@ class RecoveryPanel(QWidget): self._force_clear_busy_btn.clicked.connect(self._force_clear_busy) layout.addWidget(self._force_clear_busy_btn) - self._recover_beamline_btn = QPushButton("Recover beamline", self) - self._recover_beamline_btn.setStyleSheet( + self._force_maintenance_state_btn = QPushButton("Force to maintenance state", self) + self._force_maintenance_state_btn.setStyleSheet( card_style( CHIP_BAD_BG, BAD_CARD_BORDER, @@ -130,8 +130,8 @@ class RecoveryPanel(QWidget): extra="padding: 10px; font-weight: 700;", ) ) - self._recover_beamline_btn.clicked.connect(self._recover_beamline) - layout.addWidget(self._recover_beamline_btn) + self._force_maintenance_state_btn.clicked.connect(self._force_maintenance_state) + layout.addWidget(self._force_maintenance_state_btn) self._recovery_unmount_btn = QPushButton("Unmount sample (recovery)", self) self._recovery_unmount_btn.setStyleSheet( @@ -251,10 +251,10 @@ class RecoveryPanel(QWidget): self._daq.force_clear_busy(code) @Slot() - def _recover_beamline(self) -> None: + def _force_maintenance_state(self) -> None: if self._sample_appears_mounted(): if not self._confirm( - "Recover beamline", + "Force maintenance mode", "A sample appears to be mounted.\n\n" "Recovering the beamline may damage the sample or leave hardware in an unsafe state.\n\n" "Only continue if you are sure this is the correct recovery action.", @@ -262,17 +262,17 @@ class RecoveryPanel(QWidget): return else: if not self._confirm( - "Recover beamline", + "Force maintenance mode", "This will take over the beamline, clear the busy flag, and set the state to Maintenance.\n\n" "Do you want to continue?", ): return - code = self._prompt_recovery_code("Recover beamline") + code = self._prompt_recovery_code("Force maintenance mode") if not code: return self._last_action.setText("Last action: Recovering beamline to Maintenance...") - self._daq.recover_beamline(code) + self._daq.force_maintenance_state(code) @Slot() def _recovery_unmount_sample(self) -> None: diff --git a/src/aare/gui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py index 98e6e5e9..2973063a 100644 --- a/src/aare/gui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -902,12 +902,12 @@ class DAQWorker(QObject): ) @Slot(str) - def recover_beamline(self, confirmation_code: str): + def force_maintenance_state(self, confirmation_code: str): if self._base_url is None: - logger.info("POST /recovery/recover_beamline") + logger.info("POST /recovery/force_maintenance_state") return - request = QNetworkRequest(QUrl(f"{self._base_url}/recovery/recover_beamline")) + request = QNetworkRequest(QUrl(f"{self._base_url}/recovery/force_maintenance_state")) request.setRawHeader(b"Authorization", f"Bearer {self._token}".encode()) request.setRawHeader(b"Content-Type", b"application/json") body = json.dumps({"confirmation_code": confirmation_code}) -- 2.54.0 From 8e6897262537e221d42d7b44e418322d2cb15d54 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 12 Aug 2026 15:40:07 +0200 Subject: [PATCH 4/4] fix: show viewing mode for all states --- src/aare/gui/widgets/busy_overlay.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/aare/gui/widgets/busy_overlay.py b/src/aare/gui/widgets/busy_overlay.py index 6013a7b2..e41604f6 100644 --- a/src/aare/gui/widgets/busy_overlay.py +++ b/src/aare/gui/widgets/busy_overlay.py @@ -15,9 +15,6 @@ from aare.gui.styles import ( BUSY_PSI_RED, BUSY_PSI_RED_BORDER, BUSY_PSI_RED_DOT, - BUSY_PURPLE, - BUSY_PURPLE_BORDER, - BUSY_PURPLE_DOT, BUSY_RED_BADGE, BUSY_RED_BORDER, BUSY_RED_DOT, @@ -108,7 +105,11 @@ def build_busy_overlay_style( tell_state: TellStateModel | None, session_state: SessionsStateEnum | None = None, ) -> BusyOverlayStyle | None: - if session_state == SessionsStateEnum.Vacant: + if session_state in { + SessionsStateEnum.OwnedByElse, + SessionsStateEnum.PendingYouToElse, + SessionsStateEnum.Vacant, + }: return BusyOverlayStyle( text="In viewing mode", badge_bg=BUSY_YELLOW, @@ -117,20 +118,8 @@ def build_busy_overlay_style( overlay_border=qcolor(BUSY_YELLOW_BORDER, 235), overlay_text=qcolor(WHITE), accent_dot=BUSY_YELLOW_DOT, - subtext="Click here to grab baton if need to interact with GUI", + subtext="Click here to grab the baton if you need to interact with GUI", ) - - if session_state in {SessionsStateEnum.OwnedByElse, SessionsStateEnum.PendingYouToElse}: - return BusyOverlayStyle( - text="GUEST MODE", - badge_bg=BUSY_PURPLE, - badge_fg=WHITE, - overlay_fill=qcolor(BUSY_PURPLE, 190), - overlay_border=qcolor(BUSY_PURPLE_BORDER, 230), - overlay_text=qcolor(WHITE), - accent_dot=BUSY_PURPLE_DOT, - ) - if not is_busy: return None -- 2.54.0