Skip to content

Smarter Foreman repo list: sections, favorites, and animated moves#59

Merged
kyleve merged 7 commits into
mainfrom
feat/foreman-smarter-repo-list
Jul 6, 2026
Merged

Smarter Foreman repo list: sections, favorites, and animated moves#59
kyleve merged 7 commits into
mainfrom
feat/foreman-smarter-repo-list

Conversation

@kyleve

@kyleve kyleve commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Makes the Foreman sidebar "smarter" and restructures how per-repo state is persisted.

  • Sectioned sidebar — repos are grouped into an Enabled section on top and a Disabled section below, with favorites floated to the top of each. The ordering is a pure, unit-tested rule (RepoSection.sections(from:)) in ForemanCore; the view only renders it.
  • Favoriting — a new persisted, worker-free Repo.isFavorite, toggled from a right-click context menu on the sidebar row (with a star glyph on favorited rows) and a star button in the detail view's toolbar.
  • Per-repo persisted record — collapses ForemanConfiguration's parallel enabledRepoIDs + repoOptions into a single RepoConfiguration (isEnabled, isFavorite, options) keyed by RepoID, so the flags and options can't drift apart. This is a breaking change to the on-disk JSON — intentional, as Foreman has no users yet (no migration / custom decoder). A repo left at RepoConfiguration.standard has no entry, so the file stays free of no-op records.
  • Animated moves — the sidebar renders a single flat ForEach of headers + rows (one identity space) rather than SwiftUI Sections, so a repo glides across the group boundary when toggled (instead of a cross-container remove/insert). .animation(.snappy, value:) keyed on the flattened row identities tweens every reorder (toggle, favorite, rescan).
    • Tradeoff (accepted): custom inline group headers don't get macOS's native sidebar section-header treatment (e.g. hover-collapse chevron).

Test plan

  • ./swiftformat --lint
  • tuist test Foreman-macOS-Tests --no-selective-testing -- -destination 'platform=macOS' (app target builds; all suites pass)
  • New/updated ForemanCore coverage:
    • RepoSectionTests — enabled/disabled partition, favorites float to the top of each section, empty sections omitted, alphabetical order otherwise preserved.
    • WorkerConfigStoreTests — save/load round-trip incl. isFavorite, configuration(for:) defaults to .standard, prune drops stale per-repo entries only under the scan directory.
    • RepoTestsisFavorite persists, same-value is a no-op, and it never starts/stops the worker.
    • ForemanServicesTests — favoriting writes through to the saved record and a saved favorite is restored on launch.
  • Manual: toggling enable moves a repo between groups with a glide; favoriting floats it to the top; selection is preserved across moves.

Made with Cursor

kyleve and others added 6 commits July 5, 2026 20:37
Collapse ForemanConfiguration's parallel enabledRepoIDs/repoOptions into a
single RepoConfiguration record per RepoID (isEnabled, isFavorite, options),
dropping the old on-disk format (Foreman has no users yet). Add a persisted,
worker-free Repo.isFavorite, and RepoSection — the pure, tested enabled/
disabled sectioning rule that floats favorites to the top of each section.

Co-authored-by: Cursor <cursoragent@cursor.com>
Render session.repoSections as Enabled/Disabled sections in the sidebar, show
a star on favorited rows with a right-click Add/Remove Favorite context menu,
and add a star toggle to the worker detail view's toolbar.

Co-authored-by: Cursor <cursoragent@cursor.com>
Attach .animation(.snappy, value:) to the sidebar List keyed on the flattened
row order, so a repo tweens as it moves between the Enabled/Disabled sections
or floats within a section on favorite — regardless of what triggered it.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the sidebar's SwiftUI Sections with a single flat ForEach of headers
and rows sharing one identity space, so a repo moving between the Enabled and
Disabled groups animates as one glide rather than a cross-container
remove/insert. Group headers render inline and are selection-disabled; the
.animation is keyed on the flattened row identities.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Correct the RepoSection doc (the app renders group headers in a flat list,
  not SwiftUI Sections).
- Build the persisted record directly from the repo in repoDidChange instead
  of reading-then-overwriting the existing entry.
- Cover that disabling a favorited repo keeps its entry with isFavorite set.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kyleve kyleve enabled auto-merge (squash) July 6, 2026 01:11
Resolve AGENTS conflicts in favor of main's slimmed module-shape docs:
main reduced every AGENTS.md to terse invariants (per-type detail now
lives in each module's README.md), so the verbose Key-types/invariants
additions from this branch are dropped. The RepoConfiguration / isFavorite
/ RepoSection detail is already carried by ForemanCore/README.md; folded
the new sidebar sections + favoriting affordances into Foreman's app
README so that user-facing behavior stays documented.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kyleve kyleve merged commit 095bd79 into main Jul 6, 2026
3 checks passed
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.

1 participant