Skip to content

fix: space apps count scoping, paging, and summary tile counts#5693

Merged
norman-abramovitz merged 8 commits into
cloudfoundry:developfrom
nabramovitz:fix/space-apps-count-scope
Jul 24, 2026
Merged

fix: space apps count scoping, paging, and summary tile counts#5693
norman-abramovitz merged 8 commits into
cloudfoundry:developfrom
nabramovitz:fix/space-apps-count-scope

Conversation

@nabramovitz

Copy link
Copy Markdown
Contributor

What

The "apps count" on the space summary tile should carry the user into that space's Applications, and the counts shown there should be honest. Chasing that turned up a small family of paging/scope/count defects that all shared the same roots, so this fixes the class rather than the one symptom.

Closes #5670.

The defect class

  • Stale page index survived a shrinking dataset. Narrowing a scope (or a filter) could leave the list parked on a page that no longer exists, showing an empty table. Page index is now clamped to the last available page everywhere it's consumed (cf ViewPipeline, endpoints, autoscaler; kube/git/local pagers).
  • Space scope narrowed the filter, not the dataset. For cf-apps and cf-service-instances, a space scope was applied as a user filter — so headers reported filtered subtotals instead of the scope's true totals. Scope now narrows the dataset itself; totalItems/headers read the scope's real totals.
  • Cross-session page index leaked between scopes. ListStateStore no longer restores a persisted pageIndex across sessions; resetPageOnScopeChange(scopeKey) is called from the list services so a new scope always starts on page 1.
  • Filter is a detour, not a destination. Typing a name filter jumps to page 1; erasing it restores the position you were on before filtering (SignalListComponent, prefilterPageIndex).
  • Space summary tiles showed 0 apps/routes for every space. getNativeSpaceDetail (jetstream) now enriches the space detail with real application and route counts. Go test red→green.

Verification

  • Full make check gate green: lint (0 errors), frontend vitest 3215 passed / 2 skipped, production build, full jetstream Go suite.
  • Live-verified against a real CF (space Applications tab, scope headers, filter enter/erase round-trip, summary tiles).

Notes

A related restoration — app deletion optionally co-deleting routes — is tracked separately in #5692 and is out of this PR.

pageIndex persists in the shared list state across navigation, so a
stale index can point past the end of a smaller data set — the slice
then rendered an empty page over a non-empty list and the pager
labelled it '85 – 1 of 1' (cloudfoundry#5670, a 1-app space after wall browsing).

Clamp the slice in ViewPipeline (all three copies) and describe the
clamped page in the SignalListComponent pager: rangeText and the
prev/next disable/navigation logic derive from effectivePageIndex, so
the label can't lie and the first interaction snaps the stored signal
back into range. Non-positive page size (the 'All' sentinel) now
renders all rows in the cf and autoscaler copies too, matching the
endpoints copy. No auto-snap of the signal itself: totalPages shrinks
transiently during incremental multi-CNSI drains, and snapping then
would destroy the user's persisted wall position.
The per-space Apps tab pinned its scope inside the filter predicate,
but the 'Total X' header deliberately reads view.totalItems — the
UNFILTERED count (a2807cf) — so a 1-app space showed the
endpoint-wide 82 (cloudfoundry#5670). Scope now applies between the orchestrator
and the ViewPipeline via a computed over a lock signal (the pattern
cf-users-signal-config already uses), making totalItems mean 'in this
page's scope' everywhere without touching the count definitions.

Also drops the benign-nudge re-derivation hack (the lock is a real
signal now) and resets pageIndex on space mount — a space visit is a
fresh context, like the existing viewMode/pageSize per-space defaults.
Page position is navigation state, not a preference: ListStateStore no
longer restores pageIndex from localStorage (a prior session's index
points into whatever data happened to be loaded then), and the bound
state gains resetPageOnScopeChange(scopeKey) — every list config
service calls it from its initialize path, so switching to a different
data set (another org's spaces, a space tab after wall browsing,
another app) starts at page 1 while same-scope re-entry (wall → app
detail → wall) keeps position. Component-provided per-mount configs get
the same behaviour from the bind() change alone.

Also clamps the remaining pager copies the earlier clamp commit did not
reach — the kube view pipeline and its inline copies, github-commits,
and the component-local pagers (backup-endpoints, helm history/
versions, kube-config import/selection) — so no pager anywhere can
render an empty page over a non-empty list.
Same treatment cf-apps got: the service-instances space/type/offering
scope moves out of the user filter into a scoped dataset between the
orchestrator and the ViewPipeline (shared rebuild() for the three
initialize variants). The space Services and User Services tab headers
switch from totalFilteredResults — a workaround that made the headline
track the user's filter input, the exact bug a2807cf fixed — back to
a now scope-true view.totalItems.
… erase

Typing in the name filter redefines the result set, but the pager kept
its position — mid-list, the clamp landed on the filtered set's last
page and matches that sort earlier stayed hidden (filter 'cf' from page
4 of 56 apps showed 13-16 of 16 without cf-env). Route the input through
onNameFilterChange, which resets pageIndex like the dropdown, sort, and
filter-field paths already do.

Entering the filter from an empty box saves the unfiltered position and
erasing it restores it, so filtering from page 2 returns to page 2 —
even after paging within the filtered results. The data-layer clamp
covers a restored index that outlived a shrunken data set.
getNativeSpaceDetail built its payload from the bare /v3/spaces/{guid}
resource, which carries no counts — so the space summary's Applications
and Routes tiles showed 0 for every space (a space with 48 live routes
rendered '0 Routes'). Enrich with the existing per-space count helpers
(one space_guids-filtered /v3/apps + /v3/routes each), lazy-non-fatal
like the list handlers.

Investigation note: the org summary's route count was already correct —
CF filters /v3/routes by organization_guids server-side; the zeros in
the spaces catalog are the deliberate unenriched name-resolver path.

@norman-abramovitz norman-abramovitz 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.

LGTM

@norman-abramovitz
norman-abramovitz merged commit 70e99f3 into cloudfoundry:develop Jul 24, 2026
22 checks passed
@nabramovitz
nabramovitz deleted the fix/space-apps-count-scope branch July 24, 2026 12:01
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.

The apps count section should bring the user to those applications

2 participants