Skip to content

Add a Top-Level Only filter to the Installed and Upgrades lists - #242

Closed
graindt wants to merge 3 commits into
Homebrew:mainfrom
graindt:feat/top-level-package-filter
Closed

graindt wants to merge 3 commits into
Homebrew:mainfrom
graindt:feat/top-level-package-filter

Conversation

@graindt

@graindt graindt commented Sep 22, 2026

Copy link
Copy Markdown

What and why

The Installed and Upgrades tabs list every installed package, including libraries that were pulled in as dependencies, so finding what you actually installed means mentally skipping packages like openssl. This adds a "Top-Level Only" checkbox next to the scope picker on both tabs that hides every package another installed package depends on — the same definition as brew leaves.

  • Dependency edges come from the existing brew info --installed --json=v2 inventory, computed over the full installed inventory rather than the filtered subset, so no new brew invocations run and the Upgrades tab does not misclassify a package whose only dependent is itself up to date.
  • Filtering is client-side and composes with the existing scope picker and search query. Selection behaves like the scope picker: a hidden selection falls back to the first visible row and is restored when the filter is cleared.
  • While the filter is on, Upgrade All names the visible rows explicitly (brew upgrade git wget), because neither brew upgrade nor the kind flags can express top-level only. The Show All Upgrades empty-state action resets the checkbox alongside the scope and the search.
  • The toggle label truncates under narrow windows instead of raising the list column's minimum width, which would otherwise break the saved window-size restore covered by WindowFrameUITests.

Validation

Environment: macOS 27.0 (26A428), Mac mini (arm64), Xcode 27.0 (27A266a), Swift 6.2.

  • scripts/test (BrewKit + BrewUILint packages): pass, including 21 new unit tests covering the filter on both view models (composing with scope and search, dependency edges over the full inventory, selection fallback and restore, subtitle switches, upgradeSelection falling back to explicit names, bulkUpgradeSummary copy, resetFilters).
  • scripts/test-ui (Brew-UI plan): full run passed 46 of 49 tests. The two new UI tests (dependency rows hidden on both tabs, via a new installedTopLevel fixture scenario) passed in that run. The 3 failures (WindowFrameUITests window-size restore, ListFocusUITests and SelfUpgradeUITests focus/foreground waits) each passed when re-run individually; they are focus flakes of running the windowed suite on a busy Mac, not related to this change.
  • mint run swiftformat --lint .: clean.
  • mint run swiftlint lint --strict: 0 violations.
  • BrewUILint over the production tree: clean.

Not run: scripts/test-e2e (not requested; it installs and uninstalls hello against real Homebrew), and the manual VoiceOver and light/dark appearance passes — the checkbox uses the standard system checkbox style and carries accessibility identifiers, but a human pass is still outstanding.

  • I followed the conventions and workflow, checked for duplicate PRs and kept this change focused.
  • I added regression coverage for bug fixes or explained why automated coverage is impractical, and reported the relevant validation above.

Screenshots

Visible change: the Installed and Upgrades filter bars now show a "Top-Level Only" checkbox to the right of the All/Formulae/Casks picker.

AI assistance

  • AI was used to generate or assist with generating this PR.

Implemented end to end by the GLM5.3 from the request to add a top-level package checkbox to the Installed and Upgrades pages: production code, unit tests, UI tests, fixtures, and every validation run listed above, executed locally on the contributor's machine. All listed checks were therefore performed by the agent; human review and the outstanding manual checks remain.

A checkbox next to the scope picker on both tabs hides every package
that another installed package depends on, matching brew leaves
semantics. Dependency edges come from the existing inventory snapshot
over the full installed inventory, so no new brew invocations run and
the Upgrades tab does not misclassify a package whose only dependent
is itself up to date.

While the filter is on, Upgrade All names the visible rows explicitly
because brew upgrade and the kind flags cannot express top-level only,
and the Show All Upgrades empty-state action resets it alongside the
scope picker and the search query.

The toggle label truncates under narrow windows instead of raising the
list column's minimum width, which would otherwise break the saved
window-size restore covered by WindowFrameUITests.
Copilot AI lite review requested due to automatic review settings September 22, 2026 07:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The change is well covered by new unit and UI tests and integrates cleanly with existing filtering and selection behaviour, with only minor optional performance tuning suggested.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

Adds a client-side "Top-Level Only" filter to the Installed and Upgrades tabs so users can hide dependency packages (brew leaves-style) and focus on packages they manage directly, while preserving existing scope, search and selection behaviour.

Changes:

  • Introduces a top-level-only toggle in both Installed and Upgrades filter bars, including new accessibility identifiers.
  • Extends Installed and Upgrades view models to compute and apply top-level filtering, including upgraded Upgrade All behaviour when filtering requires explicit package names.
  • Adds unit tests, UI tests and a new UI fixture scenario covering dependency hiding and selection behaviour.
File Description
Tests/​BrewFeatureInstalledTests/​UpgradesViewModelTopLevelTests.swift Adds unit coverage for top-level filtering, selection and upgrade command behaviour on the Upgrades view model.
Tests/​BrewFeatureInstalledTests/​InstalledViewModelTopLevelTests.swift Adds unit coverage for top-level filtering composition with scope and search, plus selection fallback/restore on Installed.
Sources/​BrewRepositoryInterfaces/​Protocols/​InstalledInventoryObserving+TopLevel.swift Adds a repository-derived dependency ID set used to identify non-top-level packages.
Sources/​BrewFeatureInstalled/​Views/​UpgradesPackagesView.swift Replaces the scope-only picker with a filter bar that includes the new checkbox toggle.
Sources/​BrewFeatureInstalled/​Views/​InstalledPackagesView.swift Replaces the scope-only picker with a persistent filter bar including the new checkbox toggle.
Sources/​BrewFeatureInstalled/​ViewModels/​UpgradesViewModel.swift Applies top-level filtering to the outdated list, adjusts selection re-homing and updates Upgrade All semantics and copy.
Sources/​BrewFeatureInstalled/​ViewModels/​InstalledViewModel.swift Applies top-level filtering to the installed inventory and aligns selection re-homing with filter changes.
Sources/​BrewAccessibilityID/​AXID.swift Adds AX identifiers for the two new top-level filter toggles.
BrewUITests/​Tests/​InstalledUITests.swift Adds UI tests asserting dependencies are hidden by the top-level filter in both Installed and Upgrades tabs.
BrewUITests/​Screens/​UpgradesScreen.swift Adds a screen action for toggling the Upgrades top-level filter checkbox.
BrewUITests/​Screens/​InstalledScreen.swift Adds a screen action for toggling the Installed top-level filter checkbox.
BrewUITests/​Harness/​BrewUITestScenario.swift Adds a new installedTopLevel scenario for deterministic UI testing.
BrewUITests/​Fixtures/​ScenarioFixtures.swift Adds fixture data modelling a dependency chain where the dependency is also outdated, ensuring both tabs exercise the filter.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Sources/BrewFeatureInstalled/ViewModels/InstalledViewModel.swift
Comment on lines 64 to 71
.loaded(
Self.filteredContent(
InstalledPackagesContent(packages: repository.outdatedPackages),
scope: scope,
showsTopLevelPackagesOnly: showsTopLevelPackagesOnly,
dependencyPackageIDs: repository.userManagedDependencyPackageIDs,
query: searchQuery,
),
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@graindt graindt changed the title Add a Top-Level Only filter to the Installed and Upgrades lists. Add a Top-Level Only filter to the Installed and Upgrades lists Sep 22, 2026
@graeme

graeme commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

An alternative to this has been merged in #244. It's only on the installed tab but I think that's fine for now as is.

@graeme graeme closed this Sep 22, 2026
@graindt

graindt commented Sep 23, 2026

Copy link
Copy Markdown
Author

It's better to add the filter to Upgrades lists page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants