I meant in the normal website view.
@ngraham, in lieu of bugzilla.mozilla.org/show_bug.cgi?id=2010435, being resolved, the best that I can check is BZ 5.2 and MBZ, but because both appear to lack a tree table view, I imagine that your best shot is to request it at bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&component=User%20Interface. [1] Note, though, that because KDEBZ is still on 5.0.2, we’d still need to upgrade to the latest upstream version, albeit something that should be done anyway.
Regardless, the REST API is quicker than the website, by far, and having its data piped into something that can represent the bugs in that manner wouldn’t be difficult to create:
-
#!/usr/bin/env python3 from __future__ import annotations import sys from collections import defaultdict from datetime import datetime from urllib.parse import parse_qs, urlparse import requests from PySide6.QtCore import Qt, QUrl from PySide6.QtGui import QDesktopServices, QStandardItem, QStandardItemModel from PySide6.QtWidgets import ( QApplication, QAbstractItemView, QHBoxLayout, QHeaderView, QLineEdit, QMainWindow, QMessageBox, QPushButton, QTreeView, QVBoxLayout, QWidget, ) BUG_URL_ROLE = Qt.ItemDataRole.UserRole BUGZILLA_REST_URL = "https://bugs.kde.org/rest/bug" class MainWindow(QMainWindow): def __init__(self) -> None: super().__init__() self.setWindowTitle("KDE Bugzilla Query Viewer") central = QWidget() self.setCentralWidget(central) layout = QVBoxLayout(central) search_layout = QHBoxLayout() layout.addLayout(search_layout) self.url_edit = QLineEdit() self.url_edit.setPlaceholderText( "Paste a Bugzilla buglist URL" ) search_layout.addWidget(self.url_edit) self.load_button = QPushButton("Load") self.load_button.clicked.connect(self.load_query) search_layout.addWidget(self.load_button) self.tree = QTreeView() layout.addWidget(self.tree) self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels( ["ID", "Summary", "Severity", "Status", "Created"] ) self.tree.setModel(self.model) self.tree.setUniformRowHeights(True) # Prevent inline editing entirely. self.tree.setEditTriggers( QAbstractItemView.EditTrigger.NoEditTriggers ) # Open bugs on double-click. self.tree.doubleClicked.connect(self.open_bug) self.tree.header().setSectionResizeMode( 1, QHeaderView.ResizeMode.Stretch ) def extract_rest_params(self, url: str) -> dict[str, str]: parsed = urlparse(url) query = parse_qs(parsed.query) params: dict[str, str] = {} for key in ( "quicksearch", "product", "component", "severity", "bug_status", "resolution", ): if key in query: params[key] = query[key][0] return params def load_query(self) -> None: try: params = self.extract_rest_params( self.url_edit.text().strip() ) if not params: raise ValueError( "No supported Bugzilla query parameters were found." ) params["include_fields"] = ( "id,summary,severity,status,creation_time" ) response = requests.get( BUGZILLA_REST_URL, params=params, timeout=30, ) response.raise_for_status() bugs = response.json()["bugs"] bugs.sort( key=lambda bug: datetime.fromisoformat( bug["creation_time"].replace("Z", "+00:00") ) ) grouped: dict[str, list[dict]] = defaultdict(list) for bug in bugs: grouped[bug.get("severity") or "unspecified"].append(bug) self.model.removeRows(0, self.model.rowCount()) for severity in sorted(grouped): severity_item = QStandardItem(severity) severity_item.setEditable(False) self.model.appendRow( [ severity_item, QStandardItem(), QStandardItem(), QStandardItem(), QStandardItem(), ] ) for bug in grouped[severity]: created = ( datetime.fromisoformat( bug["creation_time"].replace("Z", "+00:00") ) .astimezone() .strftime("%Y-%m-%d %H:%M:%S %z") ) url = ( f"https://bugs.kde.org/show_bug.cgi?id={bug['id']}" ) items = [ QStandardItem(str(bug["id"])), QStandardItem(bug["summary"]), QStandardItem(bug["severity"]), QStandardItem(bug["status"]), QStandardItem(created), ] for item in items: item.setData(url, BUG_URL_ROLE) item.setEditable(False) severity_item.appendRow(items) self.tree.expandAll() except Exception as exc: QMessageBox.critical(self, "Error", str(exc)) def open_bug(self, index) -> None: item = self.model.itemFromIndex(index) if item is None: return url = item.data(BUG_URL_ROLE) if url: QDesktopServices.openUrl(QUrl(url)) def main() -> int: app = QApplication(sys.argv) window = MainWindow() window.resize(1200, 700) window.show() return app.exec() if __name__ == "__main__": raise SystemExit(main())
