Skip to content

ui: shared ClusterSwitcher + Radar loading icon#548

Merged
nadaverell merged 1 commit intomainfrom
feat/cluster-switcher-and-radar-loading-icon
Apr 27, 2026
Merged

ui: shared ClusterSwitcher + Radar loading icon#548
nadaverell merged 1 commit intomainfrom
feat/cluster-switcher-and-radar-loading-icon

Conversation

@nadaverell
Copy link
Copy Markdown
Contributor

@nadaverell nadaverell commented Apr 27, 2026

Summary

  • Shared ClusterSwitcher (in @skyhook-io/k8s-ui, re-exported from @skyhook-io/radar-app) replaces two divergent cluster-picker UIs. OSS Radar's ContextSwitcher rewrites on top of it; Radar Hub's HubClusterSwitcher will too in a follow-up Hub PR. Hub's picker previously rendered the raw gke_<account>_<region>_<cluster> context with a Cluster: prefix and no truncation — overflowing into the connection indicator and the view tabs on narrower screens. The primitive enforces max-w-[120px] sm:max-w-[220px] truncate.
  • Loading icon swap: replace the generic lucide Loader2 spinner with the Radar-branded SVG (sweep arm + pinging blips) across the auth barrier, connecting/switching overlays, Audit, Cost, Home, Resources, the pod/image filesystem modals, and the traffic-test wizard. SVG lives in @skyhook-io/k8s-ui (exports: ./assets/radar/radar-icon-loading.svg) so Hub consumes the same asset.

Why

The picker divergence wasn't just cosmetic — Hub had no overflow protection, dropped active-session confirmation, dropped search, and would render with a different brand color than OSS once --color-brand-* tokens diverged. Pulling the primitive into k8s-ui means both apps stay in sync, and the OSS rewrite drops ~290 lines.

While here: the OSS ContextSwitcher previously swallowed fetchSessionCounts failures with a console.error and silently switched, killing port-forwards/terminals without warning. It now surfaces a toast.

Notable design decisions

  • href on a ClusterSwitcherItem takes precedence over the parent's onSelect — documented in JSDoc rather than hidden behind a discriminated union (two consumers don't justify the type complexity).
  • ESC and click-outside listeners attach only while the dropdown is open, so a stacked modal (the active-sessions confirm dialog) doesn't get its escape key intercepted.
  • Selection styling uses .selection / .selection-text classes so the active row picks up Hub's brand color, not Radar-blue.
  • Status (dot) and badge (right-anchored pill) are rendered in distinct slots so future callers passing both don't collide.

Ship order

@skyhook-io/k8s-ui must publish first (radar-app peer-deps >=1.5.0); then radar-app. Hub's PR will pin the new versions.

Test plan

  • npm run tsc clean in web/
  • make frontend builds without warnings (other than pre-existing elkjs dynamic-import warning)
  • Verify Radar's switcher trigger truncates correctly on a long context (e.g., GKE)
  • Verify Radar's connecting/switching overlays render the new icon at the same vertical position
  • Verify the search-result count footer ("3 of 12 clusters") appears when filtering

Note

Medium Risk
Medium risk because it refactors the cluster context-switching UI and interaction flow (selection, grouping, session-confirmation) and replaces loading indicators across multiple views, which could introduce UX regressions or switching edge cases.

Overview
Introduces a reusable ClusterSwitcher component in @skyhook-io/k8s-ui (and re-exports it from both k8s-ui and @skyhook-io/radar-app) to standardize cluster/context picking with search, grouping, keyboard navigation, truncating trigger text, and optional error/footer slots.

Refactors OSS Radar’s ContextSwitcher to use the shared switcher, preserving the active-session confirmation prompt and improving failure handling by surfacing a toast when session-count checks fail (instead of silently switching).

Adds a branded animated Radar SVG loading icon to k8s-ui exports and swaps multiple Loader2 spinners in both k8s-ui (resources loading state) and the web app (auth redirect, connecting/switching overlays, audit/cost/home, filesystem modals, traffic wizard) to use the shared asset.

Reviewed by Cursor Bugbot for commit 7b3a537. Bugbot is set up for automated code reviews on this repo. Configure here.

ClusterSwitcher (@skyhook-io/k8s-ui): generic trigger+dropdown primitive
shared by OSS Radar's kubeconfig context switcher and Radar Hub's cluster
picker. Both call sites previously diverged — Hub showed the raw kubeconfig
context with a "Cluster:" prefix and no truncation, overflowing into the
connected indicator and view tabs on narrower screens. The primitive parses,
truncates (max-w-[120px] sm:max-w-[220px]), supports search/keyboard nav,
group headers, status dots, badges, footer slots, and href-based or callback
selection. Re-exported from @skyhook-io/radar-app for embedders.

OSS ContextSwitcher rewrite drops ~290 lines by consuming the primitive
while keeping kubeconfig parsing, group sort (GKE → EKS → AKS → Other),
active-session confirmation modal, in-cluster mode badge, and switch-error
toast fallback. Now also surfaces a toast when fetchSessionCounts fails
instead of silently switching and killing port-forwards/terminals.

Loading icon: replace lucide Loader2 spinner with the Radar-branded SVG
(sweep arm + pinging blips) across AuthBarrier, connecting/switching
overlays, AuditView, CostView, HomeView, ResourcesView, image/pod
filesystem modals, and the traffic-test wizard. SVG ships through k8s-ui's
package.json `exports` so Hub can consume the same asset.
@nadaverell nadaverell requested a review from hisco as a code owner April 27, 2026 19:36
@nadaverell nadaverell merged commit d4cff5d into main Apr 27, 2026
8 checks passed
@nadaverell nadaverell deleted the feat/cluster-switcher-and-radar-loading-icon branch April 27, 2026 21:00
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