Files

73 lines
2.6 KiB
Python

"""Minimal PyQt6 host for dashboard.html (desktop mode). Pattern from Tebra main_window.py.
The bot runs as a child process and this window shows its progress. The bot wiring
(command, step markers, friendly rules) lives in bot_runner.py, next to this file.
Run it with: python dashboard/bridge.py
"""
import json, sys, threading
from pathlib import Path
from PyQt6.QtCore import QObject, pyqtSlot, pyqtSignal, QUrl, QSettings
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebChannel import QWebChannel
import bot_runner
HTML_PATH = Path(__file__).with_name("dashboard.html")
def settings():
return QSettings("{{ORG}}", "{{APP_NAME}}")
class Bridge(QObject):
_emit = pyqtSignal(str) # thread-safe hop to the GUI thread
def __init__(self, view):
super().__init__()
self.view, self._one_run = view, threading.Lock()
self._emit.connect(lambda js: self.view.page().runJavaScript(f"window.__pyMsg({js})"))
# Restore the saved dark-mode choice on every page load, sample-data mode included.
view.loadFinished.connect(lambda _ok: self.send_to_js("apply_dark", {"on": settings().value("dark", False, bool)}))
def send_to_js(self, event, data):
self._emit.emit(json.dumps(json.dumps({"event": event, "data": data})))
@pyqtSlot()
def load_dashboard(self):
self.send_to_js("dashboard_data", {"batches": []}) # TODO: read from DB on a worker thread
@pyqtSlot()
def load_latest_report(self):
self.send_to_js("report_data", {"rows": []}) # TODO: read the latest report rows
@pyqtSlot()
def download_report(self):
pass # TODO: export the report rows to .xlsx
@pyqtSlot(bool)
def set_dark(self, on):
settings().setValue("dark", on)
@pyqtSlot()
def start_automation(self):
if self._one_run.acquire(blocking=False): # a second click can't start a second bot
threading.Thread(target=self._run, daemon=True).start()
def _run(self):
try:
bot_runner.run(self.send_to_js)
finally:
self._one_run.release()
if __name__ == "__main__":
app = QApplication(sys.argv)
win, view = QMainWindow(), QWebEngineView()
bridge, channel = Bridge(view), QWebChannel()
channel.registerObject("pyBridge", bridge)
view.page().setWebChannel(channel)
view.setUrl(QUrl.fromLocalFile(str(HTML_PATH)))
win.setCentralWidget(view); win.resize(1280, 820); win.setWindowTitle("{{APP_NAME}}"); win.show()
sys.exit(app.exec())