Browse catalog dialog (issue #10 phase 2) #67
Reference in New Issue
Block a user
Delete Branch "feat/10-browse-dialog"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the user-facing half of #10, on top of the already-merged signed-catalog core (#61/#65). Follows the final design from the 2026-07-12 "Decision + final design" comment on #10.
What's here
bcc_core.py(pure, GUI-free, per the design comment):CATALOG_CATEGORY_GROUPS/catalog_category_group()— collapses the raw 20-value taxonomy to the 7 UI chips (Files & Dev · Data · Search & AI · Cloud & Infra · Work · Home & Personal · Other). Unknown categories fall back to Other rather than dropping the entry.catalog_entry_matches_query()/filter_catalog_entries()/catalog_entries_in_group()— search-as-you-type (id/display/description/category) + category-chip filtering.format_freshness_hint()—last_releaseISO date → "Last updated N months/years ago";""when missing/unparseable/in the future.first_unfilled_focus_target()— finds the first<PLACEHOLDER>arg or blankenv_requiredkey so the GUI can focus it right after Add.load_bundled_catalog_entries()— reads+verifies+validates the bundledcatalog.json/.sigpair; returns the servers list or an empty list on any failure (missing file, bad signature, invalid schema). This is the load-bearing guarantee behind the dialog's "Catalog unavailable" empty state — never a half-trusted list.Bug fix in already-merged code:
catalog_entry_to_paste_json()only copiedconfig.env, ignoringenv_required— but in the shipped seed data,env_requiredis where 9 of 19 entries (postgres, github, notion, obsidian, brave-search, tavily, home-assistant, n8n, grafana) actually declare their secret var names;config.envis essentially unused for that purpose. Clicking Add on any of these would have silently produced a server with no env field at all for the user to fill in. Fixed to seedenv_requiredkeys as empty-string placeholders unlessconfig.envalready sets them (never overwrites a real value, still never ships a real secret —validate_catalogalready enforcesenv_requiredvalues must be"").bcc.py:BrowseCatalogDialog— search box, category chips, list (display/description/category/★/✓ official), detail pane (description, notes, homepage link, freshness hint, and the exact command rendered verbatim). Per-tier action:Add(basic) routes through the existing_import_serverpath so the duplicate-name prompt (#8) applies for free;Open setup docs(link-only) callsQDesktopServices.openUrland never auto-adds, and doesn't close the dialog.plain_label()helper (Qt.PlainText+html.escape, matchingcatalog_console.py's existing approach) or an inherently-plainQPlainTextEditfor the command preview —catalog.jsontakes community PRs, so every field is attacker-influenceable even though it's signed.ServerEditor.focus_target()— selects the first unfilled arg line, or opens the env-table cell editor on the first blank env row, after a catalog Add.<PLACEHOLDER>— never blocks a deliberate save, never lets one slip through unnoticed.bcc.spec: addeddata/catalog.json.sigtodatas— it was missing, so a frozen build would have shipped acatalog.jsonwith no matching.sigforresolve_catalog()to verify against, meaning the bundled catalog would always fail signature verification in a real build.Tests
+82 tests in
tests/test_core.py: category-group mapping (all 19 taxonomy values + unknown fallback + case-insensitivity), catalog search/filter, freshness-hint formatting (including the 23-vs-24-month rounding boundary),first_unfilled_focus_target, theenv_requiredfix (incl. a regression against the real shippedpostgresentry), andload_bundled_catalog_entriesunder valid/tampered-byte/wrong-key/missing-file/invalid-but-signed conditions, plus an end-to-end check against the realdata/catalog.json+.sig(19 entries, signature verifies).Status: 374 passed, 1 skipped (pre-existing).
ruff check .andruff format --check .both clean.What I could not verify
PySide6 cannot import in this build sandbox (
ImportError: libEGL.so.1, no system GL libs, no root to install them). SoBrowseCatalogDialog,ServerEditor.focus_target, andMainWindow.browse_catalogare not exercised at runtime — onlypy_compile/ast.parse-checked and reviewed by hand. All decision logic they depend on (filtering, grouping, freshness, focus-target selection, catalog loading) is pushed intobcc_core.pyand is unit-tested. Please eyeball the dialog live before shipping, especially:QListWidgetItemrow text (display\ndescription · group) — I couldn't confirm Qt renders the embedded\nthe way I expect across platforms; worth a visual check.ServerEditor.focus_target'sQTextCursorline-selection for the args page, and theenvtable'seditItem()call opening the inline editor as expected.Out of scope (per the task)
Remote fetch/cache (#61 follow-up), and no changes to
catalog_console.py,catalog_review.py,scripts/, workflows, ordata/catalog.jsonitself.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.