system: refactor

checking for updates:
doesn't lock the interface, it happens in the background
status and moonraker errors are reported in the scrolled window
refresh and restart buttons use the busy spinner
confirmation when restarting a service during print
change the refresh icon to a different one from the restart icons
This commit is contained in:
alfrix 2024-01-02 08:08:12 -03:00
parent 6cf639c083
commit 726231d4c7

View File

@ -3,39 +3,20 @@ import os
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango, GLib
from gi.repository import Gtk, Pango
from ks_includes.screen_panel import ScreenPanel
# Same as ALLOWED_SERVICES in moonraker
# https://github.com/Arksine/moonraker/blob/master/moonraker/components/machine.py
ALLOWED_SERVICES = (
"klipper_mcu",
"webcamd",
"MoonCord",
"klipper",
"KlipperScreen",
"moonraker",
"moonraker-telegram-bot",
"moonraker-obico",
"sonar",
"crowsnest",
"octoeverywhere",
"ratos-configurator",
)
class Panel(ScreenPanel):
def __init__(self, screen, title):
super().__init__(screen, title)
self.refresh = None
self.update_dialog = None
grid = Gtk.Grid(column_homogeneous=True)
self.update_status = None
self.system_info = self._screen.apiclient.send_request("machine/system_info")
update_all = self._gtk.Button('arrow-up', _('Full Update'), 'color1')
update_all.connect("clicked", self.show_update_info, "full")
update_all.set_vexpand(False)
self.refresh = self._gtk.Button('refresh', _('Refresh'), 'color2')
self.update_all = self._gtk.Button('arrow-up', _('Full Update'), 'color1')
self.update_all.connect("clicked", self.show_update_info, "full")
self.update_all.set_vexpand(False)
self.refresh = self._gtk.Button('arrow-down', _('Refresh'), 'color2')
self.refresh.connect("clicked", self.refresh_updates)
self.refresh.set_vexpand(False)
@ -46,77 +27,80 @@ class Panel(ScreenPanel):
shutdown.connect("clicked", self.reboot_poweroff, "poweroff")
shutdown.set_vexpand(False)
scroll = self._gtk.ScrolledWindow()
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self.update_msg = Gtk.Label(label=_("Checking for updates, please wait..."), vexpand=True)
self.moonraker_error_msg = Gtk.Label(label=_("Moonraker update manager is not responding"), vexpand=True)
self.scroll = self._gtk.ScrolledWindow()
self.scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self.scroll.add(self.update_msg)
self.main_grid = Gtk.Grid(column_homogeneous=True)
self.main_grid.attach(self.scroll, 0, 0, 4, 2)
self.main_grid.attach(self.update_all, 0, 2, 1, 1)
self.main_grid.attach(self.refresh, 1, 2, 1, 1)
self.main_grid.attach(reboot, 2, 2, 1, 1)
self.main_grid.attach(shutdown, 3, 2, 1, 1)
self.content.add(self.main_grid)
self._screen._ws.send_method('machine.update.status', callback=self.get_updates)
def create_info_grid(self):
infogrid = Gtk.Grid()
infogrid.get_style_context().add_class("system-program-grid")
update_resp = self._screen.apiclient.send_request("machine/update/status")
for i, prog in enumerate(sorted(list(self.update_status['version_info']))):
self.labels[prog] = Gtk.Label(hexpand=True, halign=Gtk.Align.START, ellipsize=Pango.EllipsizeMode.END)
if not update_resp:
self.update_status = {}
logging.info("No update manager configured")
else:
self.update_status = update_resp['result']
vi = update_resp['result']['version_info']
items = sorted(list(vi))
i = 0
for prog in items:
self.labels[prog] = Gtk.Label(hexpand=True, halign=Gtk.Align.START, ellipsize=Pango.EllipsizeMode.END)
self.labels[f"{prog}_status"] = self._gtk.Button()
self.labels[f"{prog}_status"].set_hexpand(False)
self.labels[f"{prog}_status"].connect("clicked", self.show_update_info, prog)
self.labels[f"{prog}_status"] = self._gtk.Button()
self.labels[f"{prog}_status"].set_hexpand(False)
self.labels[f"{prog}_status"].connect("clicked", self.show_update_info, prog)
if prog in ALLOWED_SERVICES:
try:
if prog in self.system_info['result']['system_info']['available_services']:
self.labels[f"{prog}_restart"] = self._gtk.Button("refresh", scale=.7)
self.labels[f"{prog}_restart"].connect("clicked", self.restart, prog)
infogrid.attach(self.labels[f"{prog}_restart"], 0, i, 1, 1)
except Exception as e:
logging.exception(e)
infogrid.attach(self.labels[f"{prog}_status"], 2, i, 1, 1)
self.update_program_info(prog)
infogrid.attach(self.labels[prog], 1, i, 1, 1)
self.labels[prog].get_style_context().add_class('updater-item')
infogrid.attach(self.labels[prog], 1, i, 1, 1)
self.labels[prog].get_style_context().add_class('updater-item')
i = i + 1
scroll.add(infogrid)
grid.attach(scroll, 0, 0, 4, 2)
grid.attach(update_all, 0, 2, 1, 1)
grid.attach(self.refresh, 1, 2, 1, 1)
grid.attach(reboot, 2, 2, 1, 1)
grid.attach(shutdown, 3, 2, 1, 1)
self.content.add(grid)
def activate(self):
self.get_updates()
infogrid.attach(self.labels[f"{prog}_status"], 2, i, 1, 1)
self.update_program_info(prog)
self.scroll.remove(self.update_msg)
self.scroll.add(infogrid)
def refresh_updates(self, widget=None):
self.refresh.set_sensitive(False)
self._screen.show_popup_message(_("Checking for updates, please wait..."), level=1)
GLib.timeout_add_seconds(1, self.get_updates, "true")
for child in self.scroll.get_children():
self.scroll.remove(child)
self.scroll.add(self.update_msg)
self._gtk.Button_busy(widget, True)
logging.info('Sending machine.update.refresh')
self._screen._ws.send_method('machine.update.refresh', callback=self.get_updates)
def get_updates(self, refresh="false"):
update_resp = self._screen.apiclient.send_request(f"machine/update/status?refresh={refresh}", timeout=60)
if not update_resp:
self.update_status = {}
logging.info("No update manager configured")
def get_updates(self, response, method, params):
self._gtk.Button_busy(self.refresh, False)
logging.info(response)
if not response or 'result' not in response:
self.update_all.set_sensitive(False)
self.scroll.remove(self.update_msg)
if 'error' in response:
self.scroll.add(Gtk.Label(label=f"Moonraker: {response['error']['message']}", vexpand=True))
else:
self.scroll.add(self.moonraker_error_msg)
else:
self.update_status = update_resp['result']
vi = update_resp['result']['version_info']
items = sorted(list(vi))
for prog in items:
self.update_program_info(prog)
self.refresh.set_sensitive(True)
self._screen.close_popup_message()
self.update_status = response['result']
self.update_all.set_sensitive(True)
self.create_info_grid()
self.scroll.show_all()
def restart(self, widget, program):
if program not in ALLOWED_SERVICES:
return
logging.info(f"Restarting service: {program}")
self._screen._ws.send_method("machine.services.restart", {"service": program})
if self._printer.state in ["printing", "paused"]:
self._screen._confirm_send_action(widget, f'{_("Are you sure?")}\n\n'
f'{_("Restart")}: {program}',
"machine.services.restart", {"service": program})
else:
self._screen._send_action(widget, "machine.services.restart", {"service": program})
def show_update_info(self, widget, program):
info = self.update_status['version_info'][program] if program in self.update_status['version_info'] else {}
@ -243,7 +227,7 @@ class Panel(ScreenPanel):
def update_program_info(self, p):
if 'version_info' not in self.update_status or p not in self.update_status['version_info']:
if not self.update_status or p not in self.update_status['version_info']:
logging.info(f"Unknown version: {p}")
return
@ -279,7 +263,6 @@ class Panel(ScreenPanel):
self._needs_update(p, info['version'], info['remote_version'])
def _already_updated(self, p, info):
logging.info(f"{p} {info['version']}")
self.labels[p].set_markup(f"<b>{p}</b>\n{info['version']}")
self.labels[f"{p}_status"].set_label(_("Up To Date"))
self.labels[f"{p}_status"].get_style_context().remove_class('update')
@ -295,17 +278,15 @@ class Panel(ScreenPanel):
label = Gtk.Label(wrap=True, hexpand=True, vexpand=True)
if method == "reboot":
label.set_label(_("Are you sure you wish to reboot the system?"))
title = _("Restart")
else:
label.set_label(_("Are you sure you wish to shutdown the system?"))
title = _("Shutdown")
buttons = [
{"name": _("Host"), "response": Gtk.ResponseType.OK, "style": 'dialog-info'},
{"name": _("Printer"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-warning'},
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
]
if method == "reboot":
title = _("Restart")
else:
title = _("Shutdown")
self._gtk.Dialog(title, buttons, label, self.reboot_poweroff_confirm, method)
def reboot_poweroff_confirm(self, dialog, response_id, method):