gui: continung efforts to fix baton system
Build and Publish / build (push) Successful in 15s
Build and Publish / Build and Deploy Docs (push) Successful in 35s

This commit is contained in:
2026-03-31 17:18:40 +02:00
parent 7ceeb8fcc2
commit 90d2ccb233
2 changed files with 50 additions and 27 deletions
+24 -20
View File
@@ -868,7 +868,10 @@ class MainWindow(QMainWindow):
@Slot(BatonStatus)
def _on_baton_status_changed(self, status: BatonStatus):
"""Close the pending dialog immediately if the baton request has been resolved via SSE."""
"""
Update waiting UI based on SSE status.
StatusBar handles baton-granted p-group selection automatically.
"""
if self._waiting_for_baton_response and not status.you_have_pending_request:
self._waiting_for_baton_response = False
self._close_baton_pending_dialog()
@@ -878,28 +881,26 @@ class MainWindow(QMainWindow):
else:
self.alert_banner.show_message("Request declined or cancelled", False, auto_clear_ms=10000)
# Manage incoming request dialog
# Manage incoming request dialog (when someone requests from us)
if not status.incoming_request and self._baton_request_dialog is not None:
logger.info("Incoming baton request no longer active, closing request dialog")
self._close_baton_dialog()
@Slot(dict)
def _on_baton_request_result(self, result: dict):
"""Handle result of our baton request - show waiting banner with countdown."""
"""
Handle result of our baton request.
- Show success/pending/error banners
- Manage pending dialog lifecycle
- StatusBar handles p-group selection automatically via update_baton_status
"""
if result.get("granted"):
self._waiting_for_baton_response = False
self.alert_banner.show_message("Baton acquired!", False, auto_clear_ms=10000)
logger.info("Baton acquired")
# Close the pending dialog immediately before showing p-group prompt
# Close pending dialog; StatusBar will trigger p-group selection via SSE
self._close_baton_pending_dialog()
available_pgroups = [str(p).strip() for p in (self.__decoded_token.pgroups or []) if p is not None and str(p).strip()]
if len(available_pgroups) == 1:
self.status_bar.set_pgroup.emit(available_pgroups[0])
else:
self.status_bar._after_baton_granted_select_pgroup()
elif result.get("pending"):
self._waiting_for_baton_response = True
timeout = result.get("timeout_seconds", 30)
@@ -907,7 +908,8 @@ class MainWindow(QMainWindow):
is_busy = result.get("beamline_busy", False)
if getattr(self, "_baton_pending_dialog", None) is None:
target_user = holder.replace("Request sent to ", "").replace(" (Note: beamline is currently busy, transfer will be queued if accepted)", "")
target_user = holder.replace("Request sent to ", "").replace(
" (Note: beamline is currently busy, transfer will be queued if accepted)", "")
self._baton_pending_dialog = BatonPendingDialog(target_user=target_user, timeout_seconds=timeout,
parent=self)
self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request)
@@ -937,30 +939,34 @@ class MainWindow(QMainWindow):
elif result.get("error"):
self._waiting_for_baton_response = False
self.alert_banner.show_message(result.get("message", "Request failed"), True)
self.alert_banner.show_message(result.get("message", "Request failed"), True,
auto_clear_ms=15000)
logger.warning(f"Baton request failed: {result.get('message')}")
self._close_baton_pending_dialog()
@Slot(dict)
def _on_baton_response_result(self, result: dict):
"""Handle result after we responded to someone else's request."""
"""
Handle response after someone requests from us.
Just update UI banners; StatusBar handles session display.
"""
logger.debug(f"Baton response result: {result}")
if result.get("accepted"):
self._waiting_for_baton_response = False
self.alert_banner.show_message("Control transferred", False, auto_clear_ms=10000)
self._close_baton_dialog()
self.status_bar.update_baton_status(self.status_bar._baton_status) # refresh label state
self.status_bar.update_baton_status(self.status_bar._baton_status)
elif result.get("refused"):
self._waiting_for_baton_response = False
self.alert_banner.show_message("Request declined", False, auto_clear_ms=10000)
self._close_baton_dialog()
self.status_bar.update_baton_status(self.status_bar._baton_status) # refresh label state
self.status_bar.update_baton_status(self.status_bar._baton_status)
else:
logger.debug(f"replied with {result}")
@Slot(dict)
def _on_baton_timeout_checked(self, result: dict):
"""Refresh waiting UI when the backend confirms timeout state."""
"""Refresh waiting UI when backend confirms timeout state."""
logger.debug(f"Baton timeout checked: {result}")
if result.get("pending"):
remaining = int(result.get("remaining_seconds", 0))
@@ -972,10 +978,7 @@ class MainWindow(QMainWindow):
elif result.get("granted"):
self._waiting_for_baton_response = False
self.alert_banner.show_message("Baton acquired!", False, auto_clear_ms=10000)
# Close the pending dialog immediately before showing p-group prompt
self._close_baton_pending_dialog()
# P-group logic will be handled automatically by the status_bar stream update
elif result.get("queued"):
self._waiting_for_baton_response = True
@@ -1001,6 +1004,7 @@ class MainWindow(QMainWindow):
self._close_baton_pending_dialog()
def _close_baton_dialog(self) -> None:
"""Close the incoming-request dialog (when someone requests from us)."""
if getattr(self, "_baton_request_dialog", None) is not None:
try:
self._baton_request_dialog.close()
+26 -7
View File
@@ -52,6 +52,7 @@ class StatusBar(QStatusBar):
self._has_pending_request: bool = False
self._pgroup_dialog_for_baton: PGroupDialog | None = None
self._baton_request_dialog: BatonRequestDialog | None = None
self._pgroup_dialog_shown_for_current_baton: bool = False
self.message_label = QLabel("", self)
self.message_label.setVisible(False)
@@ -231,10 +232,15 @@ class StatusBar(QStatusBar):
self._has_pending_request = status.you_have_pending_request if status else False
self._update_session_display()
# If we just received the baton (and weren't the holder a moment ago)
if now_holder and not was_holder:
self._after_baton_granted_select_pgroup()
# Reset one-shot flag when we lose the baton
if not now_holder:
self._pgroup_dialog_shown_for_current_baton = False
# If we just acquired the baton, prompt for p-group (and only once)
if now_holder and not was_holder:
self._show_pgroup_after_baton_grant()
# Handle incoming request dialogs (when someone requests from us)
incoming = bool(status and status.incoming_request)
if incoming and not prev_incoming:
logger.info(f"Incoming baton request detected: {status.pending_request}")
@@ -245,7 +251,20 @@ class StatusBar(QStatusBar):
self._baton_request_dialog.close()
except Exception as e:
logger.error(f"Error closing baton request dialog: {e}")
self._baton_request_dialog = None
self._baton_request_dialog = None\
def _show_pgroup_after_baton_grant(self) -> None:
"""
Single-source for p-group selection after baton is granted.
Uses a one-shot flag to prevent duplicates from multiple status updates.
"""
if self._pgroup_dialog_shown_for_current_baton:
logger.debug("P-group dialog already shown for this baton grant, skipping")
return
self._pgroup_dialog_shown_for_current_baton = True
self.show_change_dialog()
def _emit_incoming_baton_request(self, status: BatonStatus) -> None:
requester = "Another user"
@@ -471,10 +490,10 @@ class StatusBar(QStatusBar):
def _after_baton_granted_select_pgroup(self) -> None:
"""
After baton grant, open the same p-group selection flow
used everywhere else so staff and non-staff behave consistently.
Deprecated: kept for backward compatibility.
Use _show_pgroup_after_baton_grant() instead.
"""
self.show_change_dialog()
self._show_pgroup_after_baton_grant()
def show_change_dialog(self):
logger.debug(self.__decoded_token.pgroups)