aboutsummaryrefslogtreecommitdiffstats
path: root/sb_builder
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-21 10:07:37 +0200
committerDanilo M. <danix@danix.xyz>2026-10-21 10:07:42 +0200
commit28b7d44e2d29d14ce2b9b30adecdf1bff3a71bf6 (patch)
tree5f339562dc04f207c59c70151d7379d594e40dd8 /sb_builder
parent6b0f67655b40fef221f9c84cfb6c0bcedf34e3bb (diff)
downloadsb-builder-28b7d44e2d29d14ce2b9b30adecdf1bff3a71bf6.tar.gz
sb-builder-28b7d44e2d29d14ce2b9b30adecdf1bff3a71bf6.zip
Repository: stats as Dashboard tiles
Packages, Size, Unpublished (opens the unpublished filter), Last publish, in place of the one-line summary. CARD_STYLE moves to dashboard.py so both tabs share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'sb_builder')
-rw-r--r--sb_builder/dashboard.py7
-rw-r--r--sb_builder/repository.py34
2 files changed, 27 insertions, 14 deletions
diff --git a/sb_builder/dashboard.py b/sb_builder/dashboard.py
index 9b04183..3280168 100644
--- a/sb_builder/dashboard.py
+++ b/sb_builder/dashboard.py
@@ -61,6 +61,10 @@ def muted(label):
return label
+CARD_STYLE = ("QFrame#card { background: palette(base);"
+ " border: 1px solid palette(mid); border-radius: 10px; }")
+
+
class Card(QFrame):
"""Rounded panel with a muted title; content goes into self.body."""
@@ -254,8 +258,7 @@ class Dashboard(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
- self.setStyleSheet("QFrame#card { background: palette(base);"
- " border: 1px solid palette(mid); border-radius: 10px; }")
+ self.setStyleSheet(CARD_STYLE)
self.tiles = {name: Tile(name) for name in ("Packages", "Built", "Last pull", "slackpkg")}
self.vm = Card("VM")
diff --git a/sb_builder/repository.py b/sb_builder/repository.py
index 38c6ecc..1eae22e 100644
--- a/sb_builder/repository.py
+++ b/sb_builder/repository.py
@@ -27,7 +27,8 @@ from collections import Counter
from PyQt6.QtCore import QAbstractTableModel, QModelIndex, QSortFilterProxyModel, Qt, pyqtSignal
from PyQt6.QtWidgets import QHBoxLayout, QLabel, QScrollArea, QSplitter, QTableView, QVBoxLayout, QWidget
-from .fmt import NA, fmt_bytes, fmt_time
+from .dashboard import CARD_STYLE, Tile
+from .fmt import NA, fmt_age, fmt_bytes, fmt_time
from .packages import OVERLAYS, table
from .ui import SP, action, chip, group_label, search_field
@@ -124,16 +125,15 @@ def overlay(row):
def summary(data):
- """The stats line above the table."""
- rows = data["rows"]
+ """{tile title: (value, detail)} for the tiles above the table."""
+ rows, published = data["rows"], data["published"]
by = Counter(overlay(r) for r in rows)
usize = sum(r["usize"] or 0 for r in rows)
- return " · ".join([
- f"{len(rows):,} packages", f"{fmt_bytes(sum(r['size'] for r in rows))} on disk",
- f"{fmt_bytes(usize)} uncompressed",
- *(f"{by[o]} {o}" for o in (*OVERLAYS, "upstream")),
- f"{sum(not r['published'] for r in rows)} unpublished",
- f"published {fmt_time(data['published']) if data['published'] else NA}"])
+ return {
+ "Packages": (f"{len(rows):,}", " · ".join(f"{by[o]} {o}" for o in (*OVERLAYS, "upstream"))),
+ "Size": (fmt_bytes(sum(r["size"] for r in rows)), f"{fmt_bytes(usize)} uncompressed"),
+ "Unpublished": (str(sum(not r["published"] for r in rows)), "built, not in PACKAGES.TXT"),
+ "Last publish": (fmt_age(published), fmt_time(published) if published else "")}
COLUMNS = ("name", "version", "build", "category", "size", "date", "published")
@@ -236,7 +236,7 @@ class RepositoryTab(QWidget):
self.table.setSelectionMode(QTableView.SelectionMode.SingleSelection)
self.table.verticalHeader().hide()
self.table.horizontalHeader().setStretchLastSection(True)
- for col, width in enumerate((220, 120, 80, 110, 90, 130)):
+ for col, width in enumerate((220, 120, 80, 110, 90, 150)):
self.table.setColumnWidth(col, width)
self.table.selectionModel().currentRowChanged.connect(self.show_detail)
self.detail = QLabel(textFormat=Qt.TextFormat.RichText, wordWrap=True,
@@ -264,12 +264,19 @@ class RepositoryTab(QWidget):
self.loaded = False
self.generation = 0
- self.stats = QLabel(wordWrap=True)
+ self.stats = QLabel(wordWrap=True) # loading and errors; the tiles hold the numbers
+ self.setStyleSheet(CARD_STYLE)
+ self.tiles = {name: Tile(name) for name in ("Packages", "Size", "Unpublished", "Last publish")}
+ self.tiles["Unpublished"].link(lambda: self.chips["unpublished"].setChecked(True))
+ tiles = QHBoxLayout()
+ for t in self.tiles.values():
+ tiles.addWidget(t)
self.count = QLabel()
search = QHBoxLayout()
search.addWidget(self.query)
search.addWidget(self.count)
layout = QVBoxLayout(self)
+ layout.addLayout(tiles)
layout.addWidget(self.stats)
layout.addLayout(search)
layout.addLayout(chips)
@@ -294,7 +301,10 @@ class RepositoryTab(QWidget):
if gen != self.generation:
return # an older Refresh, overtaken
self.model.set_rows(data["rows"] if data else [])
- self.stats.setText(err or summary(data))
+ self.stats.setText(err)
+ stats = summary(data) if data else {}
+ for name, tile in self.tiles.items():
+ tile.set(*stats.get(name, (NA, "")))
self.refilter()
def refilter(self):