Applications: filter-dropdown fixes, app-stats 401 retry, and deploy-from-Git source/commit UX - #5424
Merged
norman-abramovitz merged 5 commits intoJun 5, 2026
Conversation
The per-CF Applications tab's Organization and Space filter dropdowns only ever showed "All". Unlike the other per-CF tabs (Routes, Services, Users) which read the shared EndpointDataService the parent CF page hydrates, the apps config keeps its OWN lazy org/space catalog so the multi-CF application wall doesn't saturate the network on mount. That catalog is gated behind ensureNamesLoaded(), triggered by the toolbar dropdowns' onOpen hook — which the per-CF tab never wired (only the global app wall did). Add the onOpen hook to both dropdowns, scoped to the route's single CNSI (tighter than the wall's all-endpoints default). First open of either dropdown now fetches this CF's org+space catalog; the service- side promise dedupes repeated opens to one fanout. Audited the sibling per-CF tabs: Routes/Services/Users already populate via the shared EndpointDataService, and Marketplace has no scope dropdowns by design — so the Applications tab was the only gap. Adds TestBed coverage asserting the dropdowns carry no locked CF entry and that first-open triggers ensureNamesLoaded for the scoped CNSI.
When no organization is selected, the applications space filter dropdown listed every space by its bare name. CF space names are only unique within an org, so a CF with space_1 in fifty different orgs rendered fifty identical "space_1" rows — impossible to tell apart or pick from. Label each space "<space> - <org>" when Org = All (sorted by space name then org name), collapsing back to the bare name once an org is selected and the scope is unambiguous. This matches what the Routes, Services and Users tabs already do, and applies to both the per-CF Applications tab and the global application wall (shared config service). Org names come from the same per-CF catalog that backs the Organization dropdown; an as-yet-unresolved org name falls back to the bare space name rather than a trailing " - ".
The app-detail stats poll fires on a ~30s cadence against a per-CF token with a ~20-minute life. A poll that fires in the final moments before expiry travels to CF (~700ms RTT) and is rejected with a 401 by the time CF validates it — newCapiClient's proactive expiry refresh can't catch a token that was still valid when the client was built. The result is a recurring 401 once per token cycle on a long-lived read. Add callWithCapiRetry: a small generic helper that runs an operation against a fresh capi client and, on a 401, rebuilds the client once and replays the operation. By retry time the stored token has genuinely expired, so the rebuild's newCapiClient proactively refreshes it and the replay succeeds. This is the reactive companion to the proactive check, mirroring the inline pattern in native_audit_events_reads.go but reusable by any native read/write handler. Wire both app-stats handlers through it: the single-app endpoint replays its lookup + stats pair, and the batched endpoint retries on its gating web-process lookup (the first CAPI call, which catches the expired token before the stats fan-out) so the rebuilt client carries the fresh token into the fan-out.
The deploy-from-Git source step crammed the gitscm fields onto one flat, placeholder-only list: an optional GitHub Enterprise URL and access token led, the required Project and Branch followed unmarked, and nothing showed that the "optional" auth actually gates the repo lookup for private / Enterprise repos. Replace the flat form with a Public / Private / Enterprise tab strip that reveals only the fields each path needs, in the order they're required: Public → Project, Branch Private → Access token, Project, Branch (host private repo) Enterprise → Base URL, Access token, Project, Branch The third tab is provider-aware — "GitHub Enterprise" for GitHub, "Self-hosted GitLab" for GitLab (the gitscm sub-form serves both). Every field now has a real label and a required marker; switching tabs clears the auth fields that don't belong to the new mode so a stale URL / token is never carried into the deploy. This is presentation only — the active mode is local component state derived from the existing githubEnterpriseUrl + accessToken bindings; no backend or store change. GitLab's token forwarding remains GitHub-only as before (a pre-existing, separately-tested behaviour). Also adds labels + required/optional markers to the Git URL and Docker source types for consistency. deriveGitMode + setGitMode are unit-tested; the three tabs, per-mode validity gating, and repo resolution were verified live.
The deploy-from-Git commit step always pinned a specific commit: it
auto-selected the newest commit and the step was only valid once a row
was chosen, so there was no way to say "just deploy whatever's at the
head of the branch." The backend already supports it — it skips the
`git reset` when the commit is empty — but the UI never sent an empty
commit.
Add a "Deploy the latest commit on {branch} (don't pin a commit)"
checkbox above the commit list. When on, the list is hidden, the step is
valid with no row selected, and the deploy sends an empty commit so CF
builds whatever HEAD points at (and every redeploy picks up new commits
automatically). Off, the pick-a-commit behaviour is unchanged.
Validity is now `useLatestHead || a commit is selected`; onNext sends ''
for latest-HEAD or the selected SHA otherwise. Toggling the checkbox
clears the radio selection while on and restores the newest-commit
default when switched back off.
This was referenced Jun 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A batch of Applications-area improvements found while working the deploy-from-Git flow and the per-CF tabs. Five focused commits:
1.
feat(cf-apps): populate the per-CF Org/Space filter dropdownsThe per-CF Applications tab's Org/Space dropdowns only ever showed "All" — unlike the other per-CF tabs (Routes/Services/Users) which read the shared
EndpointDataService, the apps config keeps its own lazy catalog that's gated behind anonOpenhook the tab never wired. Add the hook (scoped to the route's CNSI). Audited the sibling tabs — Apps was the only gap.2.
feat(cf-apps): disambiguate same-named spaces in the filter dropdownWith Org = All, the Space dropdown listed every space by bare name, so a CF with
space_1in N orgs showed N identical rows. Label each"<space> - <org>"when no org is selected (matching Routes/Services/Users); bare name once an org is picked. Applies to the per-CF tab and the global app wall.3.
fix(cf): retry app-stats reads once on a token-boundary 401The app-detail stats poll 401s once per ~20-min token cycle: a poll firing just before expiry is rejected by CF by the time it validates, and the proactive refresh can't catch a token that was valid at build time. Add
callWithCapiRetry— a reusable helper that rebuilds the client and replays once on a 401 (by retry time the token has genuinely expired, so the rebuild refreshes it). Both app-stats handlers route through it.4.
feat(deploy): tabbed access modes on the GitHub/GitLab source stepThe source step crammed an optional Enterprise URL + token ahead of the required Project/Branch, with no labels and no sign that the "optional" auth gates the repo lookup. Replace it with Public / Private / Enterprise tabs that reveal only each path's fields in dependency order, with labels + required markers; provider-aware third-tab label (GitHub Enterprise / Self-hosted GitLab). Presentation only — no backend/store change. Also labels the Git URL + Docker source types.
5.
feat(deploy): allow deploying the latest commit without pinning a SHAThe commit step always pinned a specific SHA. Add a "Deploy the latest commit on {branch} (don't pin a commit)" checkbox that sends an empty commit so CF deploys whatever HEAD points at (the backend already skips the reset when the commit is empty).
Addresses two items of #5400 (source-step UX, deploy-latest-HEAD) plus follow-ups to the per-CF tab work.
Testing
make check gategreen across all five commits (backend + frontend + prod AOT build).