From eaeeb7349504d83cd3251daba4c557854c46cd00 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 20 Oct 2026 12:29:03 +0200 Subject: Packages: orphaned filter chip SBo marks an orphaned package MAINTAINER="orphaned - no maintainer" (1936 in the tree today); the inventory already carries the maintainer, so the chip filters in the GUI alone. The shown/selected count moves next to the search field so the chip row fits the default window width. Co-Authored-By: Claude Opus 5.5 --- sb_builder/hints_tab.py | 8 +++++--- sb_builder/packages.py | 32 ++++++++++++++++++++++---------- sb_builder/ui.py | 2 +- 3 files changed, 28 insertions(+), 14 deletions(-) (limited to 'sb_builder') diff --git a/sb_builder/hints_tab.py b/sb_builder/hints_tab.py index 071e304..fbf8a70 100644 --- a/sb_builder/hints_tab.py +++ b/sb_builder/hints_tab.py @@ -61,8 +61,6 @@ class HintsTab(QWidget): self.chips[name].toggled.connect(self.refilter) chips.addWidget(self.chips[name]) chips.addStretch() - self.status = QLabel() - chips.addWidget(self.status) self.table = QTableWidget(0, len(COLUMNS)) self.table.setHorizontalHeaderLabels(COLUMNS) @@ -97,8 +95,12 @@ class HintsTab(QWidget): for key, on in (("Ctrl+A", True), ("Ctrl+Shift+A", False))] self.loaded = False + self.status = QLabel() + search = QHBoxLayout() + search.addWidget(self.query) + search.addWidget(self.status) layout = QVBoxLayout(self) - layout.addWidget(self.query) + layout.addLayout(search) layout.addLayout(chips) layout.addWidget(self.table, 1) self.refilter() diff --git a/sb_builder/packages.py b/sb_builder/packages.py index a4d1f1b..ab6f3ce 100644 --- a/sb_builder/packages.py +++ b/sb_builder/packages.py @@ -64,12 +64,19 @@ def parse_query(text): return terms -def matches(row, terms, overlays=(), statuses=()): +def orphaned(row): + # SBo marks them MAINTAINER="orphaned - no maintainer", EMAIL="NOEMAIL" + return (row["maintainer"] or "").startswith("orphaned") + + +def matches(row, terms, overlays=(), statuses=(), orphans=False): """All terms match, and the row is in a toggled chip of each non-empty group.""" if overlays and overlay(row) not in overlays: return False if statuses and row["status"] not in statuses: return False + if orphans and not orphaned(row): + return False for field, term in terms: if field is None: hay = f"{row['name']} {row['summary'] or ''}" @@ -148,15 +155,16 @@ class Model(QAbstractTableModel): class Filter(QSortFilterProxyModel): def __init__(self): super().__init__() - self.terms, self.overlays, self.statuses = [], set(), set() + self.terms, self.overlays, self.statuses, self.orphans = [], set(), set(), False - def update(self, text, overlays, statuses): + def update(self, text, overlays, statuses, orphans=False): self.terms, self.overlays, self.statuses = parse_query(text), overlays, statuses + self.orphans = orphans self.invalidateFilter() def filterAcceptsRow(self, source_row, _parent): row = self.sourceModel().rows[source_row] - return matches(row, self.terms, self.overlays, self.statuses) + return matches(row, self.terms, self.overlays, self.statuses, self.orphans) def detail_html(row): @@ -214,16 +222,15 @@ class PackagesTab(QWidget): self.query.textChanged.connect(self.refilter) self.chips = {} chips = QHBoxLayout() - for label, group in (("overlay", ("personal", "pentesting", "upstream")), ("status", STATUSES)): + for label, group in (("overlay", ("personal", "pentesting", "upstream")), ("status", STATUSES), + ("maint", ("orphaned",))): # the query prefix's name chips.addWidget(group_label(label)) for name in group: self.chips[name] = chip(name, STATUS_COLOR.get(name) if group is STATUSES else None) self.chips[name].toggled.connect(self.refilter) chips.addWidget(self.chips[name]) - chips.addSpacing(16) + chips.addSpacing(12) chips.addStretch() - self.count = QLabel() - chips.addWidget(self.count) self.table = QTableView(sortingEnabled=True) self.table.setModel(self.proxy) @@ -279,8 +286,12 @@ class PackagesTab(QWidget): for key, slot in (("Ctrl+A", self.select_visible), ("Ctrl+Shift+A", self.clear))] self.loaded = False + self.count = QLabel() + search = QHBoxLayout() + search.addWidget(self.query) + search.addWidget(self.count) layout = QVBoxLayout(self) - layout.addWidget(self.query) + layout.addLayout(search) layout.addLayout(chips) layout.addWidget(split, 1) self.model.dataChanged.connect(lambda *_: self.update_count()) @@ -300,7 +311,8 @@ class PackagesTab(QWidget): def refilter(self): on = {n for n, b in self.chips.items() if b.isChecked()} - self.proxy.update(self.query.text(), on - set(STATUSES), on & set(STATUSES)) + self.proxy.update(self.query.text(), on - set(STATUSES) - {"orphaned"}, on & set(STATUSES), + "orphaned" in on) self.update_count() def update_count(self): diff --git a/sb_builder/ui.py b/sb_builder/ui.py index 82ddc6d..3f02515 100644 --- a/sb_builder/ui.py +++ b/sb_builder/ui.py @@ -50,7 +50,7 @@ SP = QStyle.StandardPixmap # ── filter bars: search field, group labels, chips ────────────────────────── CHIP_STYLE = ("QPushButton { background: palette(button); border: 1px solid palette(mid);" - " border-radius: 11px; padding: 3px 12px; }" + " border-radius: 11px; padding: 3px 10px; }" "QPushButton:hover { border-color: palette(highlight); }" "QPushButton:checked { background: palette(highlight);" " color: palette(highlighted-text); border-color: palette(highlight); }") -- cgit v1.2.3