Distributed confirmation dialog: all GUIs open on WAIT_USER, server closes all

- Browser: OK button sends Confirm without closing dialog; Escape blocked;
  dialog closes when state leaves WAIT_USER (server-driven).
- PyQt: non-blocking QDialog replaces blocking QMessageBox; OK sends Confirm
  without closing; dialog closed by server state change or on disconnect.
- ws_client.py: remove deprecated loop= params from websockets.connect() and
  asyncio.ensure_future() (same fix already applied to ws_server.py) so the
  PyQt client can actually connect with websockets >= 10.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tqxrk8uj4M3w3d3eXm3xK8
This commit is contained in:
2026-06-25 22:21:41 +02:00
co-authored by Claude Sonnet 4.6
parent dabec1fd31
commit 0215bac13e
4 changed files with 32 additions and 12 deletions
+21 -5
View File
@@ -421,6 +421,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_empty = True
self.sud_state = None
self.sud_user_message = None
self._confirm_box = None
# Mirrors the server's TempController.enabled - gates the
# temp/heatrate setpoint controls (see on_tempctrl_changed()).
self.tc_enabled = False
@@ -732,6 +733,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.sud_empty = True
self.sud_state = None
self.sud_user_message = None
self._close_confirm_dialog()
self.tc_enabled = False
self.checkbox_tc_enable.blockSignals(True)
self.checkbox_tc_enable.setChecked(False)
@@ -875,11 +877,23 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
self.msg_sud.send({'Stop': True})
def show_user_message(self, message):
# on_sud_changed() already runs on the GUI thread (via recv_signal),
# so this can show the dialog directly. The Sud is already blocked
# in WAIT_USER server-side; closing this dialog is what unblocks it.
QtWidgets.QMessageBox.information(self, "Sud", message)
self.msg_sud.send({'Confirm': True})
if self._confirm_box is not None:
return
dlg = QtWidgets.QDialog(self)
dlg.setWindowTitle("Sud")
dlg.setWindowModality(QtCore.Qt.NonModal)
layout = QtWidgets.QVBoxLayout(dlg)
layout.addWidget(QtWidgets.QLabel(message))
btn = QtWidgets.QPushButton("OK")
btn.clicked.connect(lambda: self.msg_sud.send({'Confirm': True}))
layout.addWidget(btn)
self._confirm_box = dlg
dlg.show()
def _close_confirm_dialog(self):
if self._confirm_box is not None:
self._confirm_box.close()
self._confirm_box = None
def on_action_sud_new(self):
# Sends an empty schedule via the same Load path Load Sud uses, with
@@ -1088,6 +1102,8 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
if self.sud_state == SUD_WAIT_USER_STATE and prev_state != SUD_WAIT_USER_STATE and self.sud_user_message:
self.show_user_message(self.sud_user_message)
elif prev_state == SUD_WAIT_USER_STATE and self.sud_state != SUD_WAIT_USER_STATE:
self._close_confirm_dialog()
self._update_step_plates()
elif "UserMessage" in key:
self.sud_user_message = msg['UserMessage']