Skip to content

feat: multi-namespace selection in the toolbar namespace picker - #43

Closed
zjy365 wants to merge 1 commit into
mainfrom
feat/multi-namespace-picker
Closed

zjy365 wants to merge 1 commit into
mainfrom
feat/multi-namespace-picker

Conversation

@zjy365

@zjy365 zjy365 commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Closes #31

Implements the spec in the issue: the toolbar namespace picker becomes multi-select, and the selected set becomes the list scope for the resource table, Helm releases, and Pod metrics.

Scope model (renderer-only; the wire stays single-namespace)

  • [] = All namespaces (cluster-wide snapshot, unchanged); one name = the existing single-namespace live-watch path, byte-for-byte; two or more = bounded per-namespace snapshot fan-out (limit 100 each, parallel, merged in selection order). No watch streams are opened for multi-scope.
  • Selection cap = 32, a named constant in the new pure module; cap rejection shows a footer message. Core caps, Rust shell, and DesktopApi signatures are untouched.

Changes

  • New lib/namespace-scope.ts (vitest-covered): toggle/cap, trigger summary (a, b +N), canonical order-insensitive scope-key serialization, merged-response helpers (per-ns pages → ordered rows, per-ns load-more token advancement).
  • useNamespaces owns namespaceScope: string[] (+ setNamespaceScope); context switch resets to [context default]/[] with a content-equality bail-out so array identity cannot churn scope-keyed effects.
  • useResourceList keys its effects on the scope key and reads the scope through a ref: single-namespace watch path untouched; multi path fans out one ordinary list request per namespace with a shared generation counter (scope change/refresh supersedes in-flight pages), merges rows in selection order, and advances load-more for every namespace that still has a token. A failed namespace degrades to "no rows from it"; the multi view is snapshot-only and the pane heading says N namespaces (snapshot, refresh to update). Stale-while-revalidate snapshots use the canonical scope key, so A→B→A retention works for merged scopes too.
  • Pod usage issues one metrics call per selected namespace on the same 15s timer (max 32), keyed by namespace/name so same-named pods cannot trade rows; an all-namespace failure surfaces as the table error, partial failures degrade to "—".
  • Helm fans out one single-namespace stream per selected namespace merged in selection order; per-namespace cursors, load-more advances all pending, cancel stops all, retained cursors are closed on leave.
  • Picker UX: Base UI Combobox multiple mode; click applies immediately (no Done step); direct-Enter toggles the typed name into the selection (IME-safe guard kept); the All-namespaces row clears the whole selection (zero-selection state); trigger shows the summary with a full-list tooltip past three names; selected rows keep the checkbox-style ItemIndicator; Escape closes without changing the selection; large-cluster progressive narrowing and the truncated footer are unchanged.
  • Wiring: palette select-namespace/openResource replace the selection with one namespace; create-dialog default uses a single selected namespace, else context default; checked-row reset and detail-close reset gate on the canonical scope key; context switch resets the selection.

Testing

  • lib/namespace-scope.test.ts: toggle/cap, key canonicalization, summary formatting, merge/load-more helpers.
  • Playwright renderer-smoke.spec.ts (57 passing): new end-to-end cases — multi-select merge with grouped rows + per-namespace request recording (and no watch), 32-cap rejection with footer message, Helm merged fan-out, pod usage across namespaces; existing single-namespace, IME, direct-Enter, cache-revisit, and Helm paging cases updated to toggle semantics and all green.
  • pnpm check green (typecheck, vitest, build, cargo test + clippy); go -C core test -race ./... and go vet green (no core changes).

The picker becomes multi-select (Base UI Combobox multiple mode). The
selected set is the list scope:

- exactly one namespace keeps the existing live-watch path byte-for-byte;
- the empty selection stays the All-namespaces cluster-wide snapshot;
- two or more namespaces fan out as ordinary single-namespace snapshot
  requests (limit 100 each) merged in selection order — no watch streams,
  so "at most one watch per list view" and the no-global-informer boundary
  are untouched. The cap is 32 (renderer-only constant).

New pure seam lib/namespace-scope.ts owns toggle/cap/summary/canonical
scope-key serialization plus the merged-response helpers. useNamespaces
holds namespaceScope: string[] (bail-out on equal contents so a context
switch cannot churn array identity); useResourceList/useHelm key their
effects on the order-insensitive scope key and read the scope through a
ref. Pod usage and Helm releases fan out per selected namespace; usage
is keyed by namespace/name so same-named pods cannot trade rows. Picker
UX: click applies immediately, direct-Enter appends (IME guard kept),
the All-namespaces row clears the selection, the trigger summarizes
(a, b +N with a full-list tooltip), and the 32-cap rejection shows a
footer message. Palette/context-switch/create-dialog/reset flows pin,
replace or clear the scope as before.

Covers #31
@zjy365

zjy365 commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Merged into #45 together with the live-rollout work (#39) — the two features touch adjacent wiring in App.tsx / ResourceDetailView.tsx, so they ship as one PR to avoid the conflict.

@zjy365 zjy365 closed this Sep 15, 2026
@zjy365
zjy365 deleted the feat/multi-namespace-picker branch September 15, 2026 15:15
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.

Support multi-namespace selection in the toolbar namespace picker

1 participant