diff --git a/qui/updater.glade b/qui/updater.glade index 20ba001c..f1b5c2d2 100644 --- a/qui/updater.glade +++ b/qui/updater.glade @@ -34,6 +34,9 @@ + + list_store + @@ -141,7 +144,7 @@ False - list_store + list_store_filter True True diff --git a/qui/updater/intro_page.py b/qui/updater/intro_page.py index 47cd311d..47812374 100644 --- a/qui/updater/intro_page.py +++ b/qui/updater/intro_page.py @@ -52,10 +52,17 @@ def __init__(self, builder, log, next_button): self.next_button = next_button self.disable_checkboxes = False self.active = True + self.hide_skipped: Optional[bool] = True + self.hide_updated: Optional[bool] = False self.page: Gtk.Box = self.builder.get_object("list_page") self.stack: Gtk.Stack = self.builder.get_object("main_stack") self.vm_list: Gtk.TreeView = self.builder.get_object("vm_list") + self.list_store_raw: Gtk.ListStore = self.builder.get_object( + "list_store") + self.list_store_filter: Gtk.TreeModelFilter = self.builder.get_object( + "list_store_filter") + self.list_store_filter.set_visible_func(self.filter_func) self.list_store: Optional[ListWrapper] = None checkbox_column: Gtk.TreeViewColumn = self.builder.get_object( @@ -82,14 +89,16 @@ def __init__(self, builder, log, next_button): MAYBE=f'' 'MAYBE', OBSOLETE=f'' - 'OBSOLETE' + 'OBSOLETE', + SKIP=f'' + 'SKIP' )) def populate_vm_list(self, qapp, settings): """Adds to list any updatable vms with update info.""" self.log.debug("Populate update list") self.list_store = ListWrapper( - UpdateRowWrapper, self.vm_list.get_model()) + UpdateRowWrapper, self.list_store_raw) for vm in qapp.domains: if vm.klass == 'AdminVM': @@ -103,9 +112,10 @@ def populate_vm_list(self, qapp, settings): if getattr(vm, 'updateable', False) and vm.klass != 'AdminVM': self.list_store.append_vm(vm) - self.refresh_update_list(settings.update_if_stale) + self.refresh_update_list(settings.update_if_stale, \ + settings.hide_skipped, settings.hide_updated) - def refresh_update_list(self, update_if_stale): + def refresh_update_list(self, update_if_stale, hide_skipped, hide_updated): """ Refreshes "Updates Available" column if settings changed. """ @@ -124,6 +134,10 @@ def refresh_update_list(self, update_if_stale): row.updates_available = bool(row.vm.name in to_update) row.selected = bool(row.vm.name in to_update) + self.hide_skipped = hide_skipped + self.hide_updated = hide_updated + self.list_store_filter.refilter() + def get_vms_to_update(self) -> ListWrapper: """Returns list of vms selected to be updated""" return self.list_store.get_selected() @@ -250,6 +264,12 @@ def _handle_cli_dom0(dom0, to_update, cliargs): to_update = to_update.difference({"dom0"}) return to_update + def filter_func(self, model, iter, data): + if self.hide_skipped and 'SKIP' in str(model[iter][4]): + return False + if self.hide_updated and 'NO' in str(model[iter][4]): + return False + return True def is_stale(vm, expiration_period): if expiration_period is None: @@ -278,6 +298,7 @@ class UpdateRowWrapper(RowWrapper): def __init__(self, list_store, vm, to_update: bool): updates_available = bool(vm.features.get('updates-available', False)) + skip = bool(vm.features.get('skip-update', False)) if to_update and not updates_available: updates_available = None selected = updates_available is True @@ -293,7 +314,7 @@ def __init__(self, list_store, vm, to_update: bool): selected, icon, name, - UpdatesAvailable.from_features(updates_available, supported), + UpdatesAvailable.from_features(updates_available, supported, skip), Date(last_updates_check), Date(last_update), 0, @@ -335,12 +356,14 @@ def updates_available(self): def updates_available(self, value): updates_available = bool( self.vm.features.get('updates-available', False)) + skip = bool( + self.vm.features.get('skip-update', False)) supported = check_support(self.vm) if value and not updates_available: updates_available = None self.raw_row[self._UPDATES_AVAILABLE] = \ - UpdatesAvailable.from_features(updates_available, supported) + UpdatesAvailable.from_features(updates_available, supported, skip) @property def last_updates_check(self): @@ -438,10 +461,14 @@ class UpdatesAvailable(Enum): MAYBE = 1 NO = 2 EOL = 3 + SKIP = 4 @staticmethod def from_features(updates_available: Optional[bool], - supported: Optional[str]=None) -> "UpdatesAvailable": + supported: Optional[str]=None, + skip: Optional[bool]=False) -> "UpdatesAvailable": + if skip: + return UpdatesAvailable.SKIP if not supported: return UpdatesAvailable.EOL if updates_available: @@ -460,9 +487,13 @@ def color(self): return label_color_theme("black") if self is UpdatesAvailable.EOL: return label_color_theme('red') + if self is UpdatesAvailable.SKIP: + return label_color_theme('red') def __str__(self): - if self is UpdatesAvailable.YES: + if self is UpdatesAvailable.SKIP: + name = "SKIP" + elif self is UpdatesAvailable.YES: name = "YES" elif self is UpdatesAvailable.MAYBE: name = "MAYBE" diff --git a/qui/updater/updater_settings.py b/qui/updater/updater_settings.py index f80a65f7..d5aa77be 100644 --- a/qui/updater/updater_settings.py +++ b/qui/updater/updater_settings.py @@ -53,6 +53,8 @@ class Settings: MAX_UPDATE_IF_STALE = 99 DEFAULT_RESTART_SERVICEVMS = True DEFAULT_RESTART_OTHER_VMS = False + DEFAULT_HIDE_SKIPPED = True + DEFAULT_HIDE_UPDATED = False def __init__( self, @@ -108,6 +110,12 @@ def __init__( self.restart_other_checkbox.connect( "toggled", self._show_restart_exceptions) + self.hide_skipped_checkbox: Gtk.CheckButton = \ + self.builder.get_object("hide_skipped") + + self.hide_updated_checkbox: Gtk.CheckButton = \ + self.builder.get_object("hide_updated") + self.available_vms = [ vm for vm in self.qapp.domains if vm.klass == 'DispVM' and not vm.auto_cleanup @@ -138,6 +146,8 @@ def __init__( self._init_restart_other_vms: Optional[bool] = None self._init_limit_concurrency: Optional[bool] = None self._init_max_concurrency: Optional[int] = None + self._init_hide_skipped: Optional[bool] = None + self._init_hide_updated: Optional[bool] = None @property def update_if_stale(self) -> int: @@ -176,6 +186,18 @@ def restart_other_vms(self) -> bool: self.vm, "qubes-vm-update-restart-other", Settings.DEFAULT_RESTART_OTHER_VMS) + @property + def hide_skipped(self) -> bool: + return get_boolean_feature( + self.vm, "qubes-vm-update-hide-skipped", + Settings.DEFAULT_HIDE_SKIPPED) + + @property + def hide_updated(self) -> bool: + return get_boolean_feature( + self.vm, "qubes-vm-update-hide-updated", + Settings.DEFAULT_HIDE_UPDATED) + @property def max_concurrency(self) -> Optional[int]: """Return the current (set by this window or manually) option value.""" @@ -210,6 +232,11 @@ def load_settings(self): if self._init_limit_concurrency: self.max_concurrency_button.set_value(self._init_max_concurrency) + self._init_hide_skipped = self.hide_skipped + self._init_hide_updated = self.hide_updated + self.hide_skipped_checkbox.set_active(self._init_hide_skipped) + self.hide_updated_checkbox.set_active(self._init_hide_updated) + def _show_restart_exceptions(self, _emitter=None): if self.restart_other_checkbox.get_active(): self.restart_exceptions_page.show_all() @@ -262,6 +289,20 @@ def save_and_close(self, _emitter): default=Settings.DEFAULT_RESTART_OTHER_VMS ) + self._save_option( + name="hide-skipped", + value=self.hide_skipped_checkbox.get_active(), + init=self._init_hide_skipped, + default=Settings.DEFAULT_HIDE_SKIPPED + ) + + self._save_option( + name="hide-updated", + value=self.hide_updated_checkbox.get_active(), + init=self._init_hide_updated, + default=Settings.DEFAULT_HIDE_UPDATED + ) + limit_concurrency = self.limit_concurrency_checkbox.get_active() if self._init_limit_concurrency or limit_concurrency: if limit_concurrency: @@ -279,7 +320,8 @@ def save_and_close(self, _emitter): apply_feature_change(vm, 'restart-after-update', None) self.exceptions.save() - self.refresh_callback(self.update_if_stale) + self.refresh_callback(self.update_if_stale, self.hide_skipped, \ + self.hide_updated) self.settings_window.close() def _save_option( diff --git a/qui/updater_settings.glade b/qui/updater_settings.glade index 1a181560..9b0dcc63 100644 --- a/qui/updater_settings.glade +++ b/qui/updater_settings.glade @@ -9,7 +9,7 @@ Qubes OS Updater Settings False 458 - 571 + 640 @@ -495,6 +495,70 @@ 10 + + + Filtering Options + True + False + start + start + 18 + True + True + + + + False + True + 11 + + + + + Hide qubes with 'skip-update' feature from selection page. + False + True + False + start + start + 5 + True + True + True + + + + False + True + 12 + + + + + Hide already updated qubes from selection page. + True + True + False + start + start + 5 + True + False + True + + + + False + True + 13 + +