Skip to content

refactor(tui): consolidate repetitive filter method pairs in model.go #34

@jongio

Description

@jongio

Code Quality Finding: Repetitive Filter Method Pairs

File: internal/tui/model.go
Lines: 2518–2723
Severity: C (moderate — structural duplication)

Description

The TUI model contains 10 filter methods organised as 5 symmetric pairs, one for flat sessions and one for grouped sessions:

Pair Sessions variant Groups variant
Hidden filterHiddenSessions filterHiddenGroups
Favorited filterFavoritedSessions filterFavoritedGroups
Attention filterAttentionSessions filterAttentionGroups
Plan filterPlanSessions filterPlanGroups
Work status filterWorkStatusSessions filterWorkStatusGroups

All five filterXGroups variants are structurally identical: check a guard condition, iterate groups, apply a per-session predicate, rebuild the group with filtered sessions, drop empty groups, and return. The only thing that varies is the predicate check.

Impact

  • Each new filter type requires two new nearly-identical functions.
  • Bug fixes or logic changes (e.g. empty-group handling) must be applied in five places.
  • The repetition makes the file harder to scan and adds maintenance surface.

Suggested Refactor

Introduce a small predicate helper and a shared filterSessionsWhere / filterGroupsWhere function:

func filterSessionsWhere(sessions []data.Session, keep func(data.Session) bool) []data.Session {
    out := make([]data.Session, 0, len(sessions))
    for _, s := range sessions {
        if keep(s) {
            out = append(out, s)
        }
    }
    return out
}

func filterGroupsWhere(groups []data.SessionGroup, keep func(data.Session) bool) []data.SessionGroup {
    out := make([]data.SessionGroup, 0, len(groups))
    for _, g := range groups {
        filtered := filterSessionsWhere(g.Sessions, keep)
        if len(filtered) > 0 {
            g.Sessions = filtered
            g.Count = len(filtered)
            out = append(out, g)
        }
    }
    return out
}

Each named filter then becomes a one-liner that passes a predicate, eliminating ~160 lines of near-identical boilerplate.

Notes

  • The existing logic is correct; this is a maintainability concern, not a bug.
  • The early-return guard in each function can be preserved as a pre-call check or folded into the predicate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    anti-slopAI anti-pattern detectionautomatedCreated by automation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions