Skip to content

Remember filters across kind and section switches - #2022

Merged
arlenvasconcelos merged 9 commits into
skyhook-io:mainfrom
arlenvasconcelos:arlen/rad-622-filter-state-across-kind-and-section-switches
Oct 13, 2026
Merged

arlenvasconcelos merged 9 commits into
skyhook-io:mainfrom
arlenvasconcelos:arlen/rad-622-filter-state-across-kind-and-section-switches

Conversation

@arlenvasconcelos

@arlenvasconcelos arlenvasconcelos commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Description

Refs #1864.

Filters were lost when you moved around. Switching resource kinds cleared the column and problem filters. Leaving Resources and coming back through the nav rail opened a bare Pods list. A reload lost everything.

Each kind keeps its filters, per cluster

  • Each kind's column and problem filters are saved in localStorage, keyed by API base + context, so clusters never share them. In Radar Hub each cluster mounts with its own API base, so each cluster keeps its own filters there too. Pods → Services → Pods brings the Pods filters back, and so does a reload or a new tab.
  • The URL stays the source of truth. A URL that carries its own list state (filters, problems, search, labels, owner, resource, â€Ķ) is shown as is. Only a bare /resources/<kind> restores the saved filters, and it writes them into the URL with replace.
  • What gets saved is the last filters chosen for that kind, either by the user or by a link that carries filters. A restore never saves again. A link without filters (one resource, an owner's pods, a search) leaves the saved filters alone. Clear filters removes them.
  • Each tab keeps what it has shown, in sessionStorage: a reload or a duplicated tab keeps the tab's own filters, while a new tab opens with the last saved ones. Filters saved in another tab only seed a kind the first time this tab opens it.
  • Bare /resources and the Resources rail item go to the last kind. This also covers Radar Hub's rail, which links to bare /resources.
  • Sort is unchanged: it was already remembered per kind.

Each section returns to its last list (per tab)

  • The nav rail and section shortcuts go back to the section's last list URL. Detail sub-routes are not remembered, so the rail always lands on the list.
  • Only the params that shape each section's list are kept, from a per-section allowlist (viewMemory.ts). Everything else is dropped: the namespace pick, the investigation focus, drawers and details opened on top of the list (e.g. an open Application). A param a view adds later is forgotten until it is listed, never replayed by mistake.
  • It is kept per tab and per cluster in sessionStorage: it survives a reload and is copied to a duplicated tab, a new tab starts without it, and switching context keeps each cluster's own.

Active filters are visible

  • Clear filters is highlighted and shows a count.
  • A line says when filters were restored from the last visit, with a Clear link.
  • Active filters show as removable chips above the table, as well as in the empty state.

"Apply to all sections" in the Namespace column filter

  • It is offered when at least one namespace is included. It replaces the header namespace picker's selection with those namespaces and briefly highlights the picker.
  • Once the change lands, the header picker owns the namespace scope: the Namespace column filter is cleared on every kind of that cluster, not just the current one. Other column and problem filters stay. If the change fails, nothing is cleared.
  • It also works in Radar Hub: the pick reaches Hub's namespace chip through ?namespaces=. It is not offered with cache-scoped namespaces, where the scope is locked.

Other changes

  • A kind switch that restores filters adds one history entry instead of two.
  • The URL sync now also reads problem filters, so Back keeps them.

Notes

  • This stores filter values in localStorage, unlike the filter-state contract used by Applications, GitOps and Checks. The per-cluster key, the URL-wins rule and the "restored" line are there so saved filters never show up unexplained.
  • New optional props on ResourcesView: rememberedKindSearch, onKindFiltersChange, onApplyNamespacesToAllSections. Hosts that don't pass them keep today's behavior. Radar Hub gets them through @skyhook-io/radar-app with no change on its side.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

How has this been tested?

  • Unit tests:

    • kindFilterStore.test.ts: per-cluster and per-group keys, tab isolation, reload / duplicated tab / new tab, unavailable storage, clearing one column on every kind.
    • viewMemory.test.ts: the per-section allowlist, list-only routes, reload per cluster, never shared with a new tab.
    • ResourcesView.kind-filter-memory.test.ts: restore of filters, excludes and problems.
    • ActiveFilterBar.test.tsx.
  • make tsc, web npm test and the k8s-ui suite pass.

  • By hand on a remote EKS cluster:

    • Pods filter → Topology → rail back to filtered Pods.
    • Kind switch shows the restored line and chips.
    • Reload of bare /resources/pods restores the filters.
    • An open Application → leave → rail returns to the list, not the app.
    • The Timeline view survives a rail round-trip.
    • Apply to all sections sets the picker and clears a Namespace filter saved on another kind.
    • Tabs: a duplicated tab keeps the source tab's filters and section memory; after another tab saves different filters, a reload keeps the tab's own and a new tab gets the latest saved.
    • Same flow embedded in a local Radar Hub (local radar-app linked into radar-hub-web, kind cluster): Hub chip set, Namespace filter cleared on Pods and Deployments, kept after reload.
  • Tested locally with minikube/kind

  • Tested against a remote cluster

  • Added/updated unit tests

Checklist

  • My code follows the project's coding standards
  • I have performed a self-review of my code
  • I have added comments where necessary
  • My changes generate no new warnings
  • Any dependent changes have been merged

@arlenvasconcelos
arlenvasconcelos marked this pull request as ready for review October 9, 2026 03:54
@arlenvasconcelos
arlenvasconcelos marked this pull request as draft October 9, 2026 03:54
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

PR Summary by Qodo

Remember filters across resource kinds and section switches

âœĻ Enhancement 🐞 Bug fix 🧊 Tests 🕐 40+ Minutes

Grey Divider

AI Description

â€Ē Persist per-cluster resource filters and restore them on bare kind URLs without overriding
 explicit URL state.
â€Ē Return section navigation to its last list while excluding detail and transient parameters.
â€Ē Show active filters and let users promote namespace filters to the global picker.
Diagram

graph TD
  Session["Section memory"] --> App["App router"] --> Adapter["Web adapter"] --> View["Resources view"] --> Chips["Filter chips"]
  Local[("Local storage")] --> Store["Kind filter store"] --> App
  View --> URL["Route URL"] --> App
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep all memory in the URL
  • ➕ Avoids localStorage and cross-tab state semantics.
  • ➖ Cannot restore a kind's previous filters from a bare URL after reload or in a new tab.
2. Persist complete section URLs
  • ➕ Requires less per-section parameter maintenance.
  • ➖ Can unexpectedly reopen details, drawers, or stale namespace and investigation state.

Recommendation: Keep the PR's split strategy: URL state governs the current view, cluster-scoped storage seeds bare kind lists, and allowlisted session memory supports section navigation. Its explicit boundaries avoid replaying transient state; review URL-sync transitions and namespace promotion carefully.

Files changed (12) +840 / -84

Enhancement (6) +493 / -83
ActiveFilterBar.tsxAdd reusable active-filter bar +86/-0

Add reusable active-filter bar

â€Ē Displays removable column, problem, and label filters, plus an optional restored-filter notice and Clear action.

packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx

ResourcesView.tsxRestore kind filters and expose active-filter controls +190/-73

Restore kind filters and expose active-filter controls

â€Ē Adds optional host callbacks for remembered filters and namespace promotion. Synchronizes restored filters with the URL, preserves explicit link state, reads problem filters on navigation, and shows filter chips and a count.

packages/k8s-ui/src/components/resources/ResourcesView.tsx

App.tsxWire cluster filter persistence and section navigation +68/-9

Wire cluster filter persistence and section navigation

â€Ē Records per-session list routes, initializes a cluster-scoped filter store, and routes bare Resources visits to the last kind. Connects filter callbacks and promotes included namespaces to the header picker after a successful scope change.

web/src/App.tsx

ResourcesView.tsxForward filter-memory callbacks to the shared view +7/-1

Forward filter-memory callbacks to the shared view

â€Ē Adds optional props for remembered kind filters, filter changes, and namespace promotion, then passes them to the k8s-ui Resources view.

web/src/components/resources/ResourcesView.tsx

kindFilterStore.tsPersist per-kind filters and the last resource kind +87/-0

Persist per-kind filters and the last resource kind

â€Ē Stores filters under cluster and kind keys in localStorage while retaining each tab's first-read values. Supports clearing a column across saved kinds and degrades when storage is unavailable.

web/src/utils/kindFilterStore.ts

viewMemory.tsRemember each section's last list URL for the session +55/-0

Remember each section's last list URL for the session

â€Ē Records only list routes and per-section allowlisted query parameters, excluding detail and cross-view state. Keeps entries in memory and exposes a clear operation for context switches.

web/src/utils/viewMemory.ts

Refactor (2) +35 / -1
resource-utils.tsCentralize resource-filter query conversion +31/-0

Centralize resource-filter query conversion

â€Ē Defines resource-list filter parameters and helpers to parse and serialize per-kind column and problem filters without retaining inactive exclude flags.

packages/k8s-ui/src/components/resources/resource-utils.ts

navigation.tsShare navigation parameter and list-route definitions +4/-1

Share navigation parameter and list-route definitions

â€Ē Exports cross-view parameters and a Resources list-path pattern for use by routing and memory helpers.

web/src/utils/navigation.ts

Tests (4) +312 / -0
ActiveFilterBar.test.tsxTest active-filter chips and restore controls +78/-0

Test active-filter chips and restore controls

â€Ē Covers empty rendering, excluded-column labels, chip clear handlers, and the restored-state Clear action.

packages/k8s-ui/src/components/resources/ActiveFilterBar.test.tsx

ResourcesView.kind-filter-memory.test.tsTest kind-filter serialization and URL intent +52/-0

Test kind-filter serialization and URL intent

â€Ē Checks filter and exclude round-trips, omission of unrelated parameters, and which URLs block automatic restoration.

packages/k8s-ui/src/components/resources/ResourcesView.kind-filter-memory.test.ts

kindFilterStore.test.tsTest cluster-scoped filter storage +113/-0

Test cluster-scoped filter storage

â€Ē Covers cluster and API-group isolation, last-kind recording, tab-local reads, unavailable storage, clearing filters, and removing one column across saved kinds.

web/src/utils/kindFilterStore.test.ts

viewMemory.test.tsTest section list-memory boundaries +69/-0

Test section list-memory boundaries

â€Ē Verifies allowlisted list parameters, exclusion of details and transient state, cleared-list recording, and explicit memory clearing.

web/src/utils/viewMemory.test.ts

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (1) 📎 Requirement gaps (0) ðŸŽĻ UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Shared links can claim filters were restored 🐞 Bug ≡ Correctness
Description
filtersRestored checks only whether the current filters equal restoredKindSearch, which remains
set after a same-kind URL navigation. When a link supplies its own filters matching the remembered
values, the list incorrectly says those filters were restored from the last visit.
Code

packages/k8s-ui/src/components/resources/ResourcesView.tsx[5921]

+  const filtersRestored = !!kindFiltersSearch && kindFiltersSearch === restoredKindSearch
Evidence
Restoration sets restoredKindSearch, but URL synchronization changes it only when the kind
changes. The notice then uses value equality alone, even though the URL-sync path accepts filters
for the same kind.

packages/k8s-ui/src/components/resources/ResourcesView.tsx[4624-4637]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[4679-4687]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[5912-5921]
packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx[35-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The restored notice relies on filter-value equality, so a same-kind URL with its own matching filters can be labeled as restored.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[4627-4637]
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[5912-5921]
## Recommended Fix
Track restoration provenance separately from serialized filter values. Clear it when a same-kind URL supplies its own list state or the user edits the filters, and display the notice only while the current state came from restoration.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Namespace action appears before scope loads 🐞 Bug ≡ Correctness
Description
App passes onApplyNamespacesToAllSections while namespaceScope is undefined because the
condition excludes only a confirmed cache-scoped cluster. If a namespace column filter is available
before that query resolves, the action can submit an arbitrary selection even on a cache-scoped
cluster.
Code

web/src/App.tsx[2306]

+            onApplyNamespacesToAllSections={embedded || namespaceScope?.cacheScoped || !kindFilterStore ? undefined : applyNamespacesToAllSections}
Evidence
The optional-chain condition treats an absent scope as eligible; the resource view renders and
invokes the supplied action, while the mutation itself treats missing scope as potentially requiring
a cache rebuild.

web/src/App.tsx[2304-2306]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[6801-6808]
web/src/App.tsx[1478-1484]
web/src/api/client.ts[6819-6834]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The namespace promotion action is available while namespace-scope data is missing, so cache-scoped clusters can briefly expose it.
## Fix Focus Areas
- web/src/App.tsx[2304-2306]
## Recommended Fix
Pass the callback only when namespace-scope data has loaded and explicitly reports `cacheScoped === false`. Keep it unavailable while scope is unknown.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Dismissing restored filters also wipes the namespace pick 🐞 Bug ≡ Correctness
Description
The "Filters restored from your last visit — Clear" link is wired to clearAllFilters. That
function clears search, regex, labels, owner and show-inactive too, then calls
onClearNamespaces?.(). In the web app onClearNamespaces is clearAllNamespaces, which saves an
empty namespace pick to the server. So a user who only meant to dismiss a kind's restored
column/problem filters also loses their header namespace scope in every section, plus any search or
label filter they had typed.
Code

packages/k8s-ui/src/components/resources/ResourcesView.tsx[R6481-6482]

+            restored={filtersRestored}
+            onClearAll={clearAllFilters}
Evidence
ActiveFilterBar shows the restored line with a Clear button that calls onClearAll. ResourcesView
passes clearAllFilters as onClearAll. clearAllFilters resets every list filter and ends with
onClearNamespaces?.(). App passes onClearNamespaces={clearAllNamespaces}, which runs
setActiveNamespace.mutate({ namespaces: [] }, { onSuccess: () => setNamespaces([]) }). That clears
the per-user namespace pick held on the server.

packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx[35-48]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[4795-4814]
web/src/App.tsx[1467-1474]
web/src/App.tsx[2301-2303]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The "Clear" link next to "Filters restored from your last visit" calls `clearAllFilters`. That also clears search, labels, owner, show-inactive and the global namespace pick (through `onClearNamespaces`). The user only wanted to dismiss the restored per-kind filters.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[6472-6485]
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[4795-4814]
## Recommended Fix
Add a `clearKindFilters` callback that only runs `setColumnFilters({})`, `setColumnFilterExcludes({})` and `setProblemFilters([])`. These are user edits, so the save effect will record '' for the kind. Pass that callback as `onClearAll` to the table's `ActiveFilterBar` instead of `clearAllFilters`. Leave the toolbar's "Clear filters" button as it is.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (4)
4. Filter chips ignore theme backgrounds 📘 Rule violation ⚙ Maintainability
Description
ActiveFilterBar styles its problem and label filter chips with hardcoded bg-red-500/15 and
bg-green-500/15 classes instead of theme background tokens. Whenever either filter is active, its
chip uses a fixed palette background, including on hover.
Code

packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx[66]

+          className="flex items-center gap-1 px-2 py-1 text-xs bg-red-500/15 text-red-700 dark:text-red-300 rounded-md hover:bg-red-500/25 transition-colors"
Evidence
The checklist requires theme background tokens for modified frontend elements. The new filter bar
uses hardcoded red and green background utilities on its problem and label chips, with no documented
design-spec exception.

Rule 3036653: Use theme background tokens instead of hardcoded utility color classes
packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx[62-77]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The problem and label filter chips use hardcoded background color utilities instead of theme background tokens.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx[66-77]
## Recommended Fix
Replace the hardcoded background and hover background classes on both chips with appropriate theme background tokens.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Applications reopens an old detail ✓ Resolved
Description
cleanSearch leaves the app query parameter in the URL remembered for /applications, even
though that parameter selects an application detail. After a user opens an app and leaves the
section, returning through section navigation restores the detail rather than the list.
Code

web/src/utils/viewMemory.ts[R10-11]

+  'workload', 'run',
+  'drawer', 'event',
Evidence
ApplicationsView uses ?app to select and render a detail. The new memory code preserves that
parameter on the accepted /applications path, and section navigation uses the recorded URL.

web/src/components/applications/ApplicationsView.tsx[107-123]
web/src/components/applications/ApplicationsView.tsx[145-149]
web/src/utils/viewMemory.ts[6-20]
web/src/utils/viewMemory.ts[28-38]
web/src/App.tsx[539-547]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Applications detail selector is being remembered as part of its list URL, so section navigation reopens an old detail.
## Fix Focus Areas
- web/src/utils/viewMemory.ts[6-12]
- web/src/components/applications/ApplicationsView.tsx[107-123]
## Recommended Fix
Add `app` to the detail query parameters removed before recording section memory, and test a return to Applications after opening a detail.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Section switches forget nested lists 🐞 Bug ≡ Correctness
Description
viewMemory.record accepts only a section's root path, except for Resources, so it rejects list
screens beneath /capacity and /cnpg. Returning through the section shortcut opens the root
screen instead of the last demand, activity, or database screen, losing that screen's URL filters.
Code

web/src/utils/viewMemory.ts[R36-38]

+      const resourceList = view === 'resources' && RESOURCE_LIST_PATH.test(path)
+      if (!resourceList && path !== (view === 'home' ? '/' : `/${view}`)) return
+      sections.set(view, path + query)
Evidence
Capacity selects its demand and activity lists by pathname, and CNPG defines several nested screen
paths. None passes the new root-only recording guard, so setMainView cannot restore them.

web/src/utils/viewMemory.ts[31-38]
web/src/components/capacity/CapacityView.tsx[27-69]
web/src/components/capacity/CapacityDemand.tsx[107-116]
web/src/components/cnpg/routes.ts[3-9]
web/src/App.tsx[542-551]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The list-only route guard discards Capacity and CNPG list screens that have paths beneath their section root.
## Fix Focus Areas
- web/src/utils/viewMemory.ts[31-38]
- web/src/components/capacity/CapacityView.tsx[27-69]
- web/src/components/cnpg/routes.ts[3-9]
## Recommended Fix
Recognize the known nested list-screen routes for these sections while continuing to reject pool and resource detail routes; test restoring their paths and query filters.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Kind switches can overwrite saved filters 🐞 Bug ≡ Correctness
Description
The kind-change effect restores the selected kind's filters only after the earlier URL-write effect
has run with the new kind and the previous kind's filter state. On a sidebar switch, that first
write navigates to a URL carrying the wrong filters; if its router update is processed before the
restored-filter write, URL sync can treat them as the new kind's choice and save them.
Code

packages/k8s-ui/src/components/resources/ResourcesView.tsx[R5213-5217]

+    if (isSyncingFromURL.current) return
+    filtersArrivedRef.current = 'restore'
+    const restored = kindFiltersToSearch(kindFiltersFromSearch(rememberedKindSearch?.(selectedKind)))
+    const remembered = kindFiltersFromSearch(restored)
+    setColumnFilters(remembered.columnFilters)
Evidence
The sidebar changes selectedKind alone. The URL-write effect appears before the new restoration
effect and serializes the current filters with that selected kind; URL sync and the save effect can
subsequently accept nonempty filters from the resulting URL.

packages/k8s-ui/src/components/resources/ResourcesView.tsx[6004-6012]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[4848-4898]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[5201-5221]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[4650-4665]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[5232-5243]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A sidebar kind switch can write the previous kind's filters to the new kind's URL before restoration runs.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[4848-4898]
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[5207-5221]
## Recommended Fix
Prevent the URL-write effect from running while `filtersKind` differs from the selected kind, then let it perform the pending kind navigation after the new kind's filters are installed. Test a switch between two kinds with different saved filters.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

8. Applying namespaces can wipe another kind's filter 🐞 Bug ≡ Correctness
Description
The "Apply to all sections" handler calls clearColumnFilter(col.key) after the asynchronous
namespace change resolves, clearing the current Namespace filter rather than necessarily the kind
and selection submitted. If the user switches kinds or edits the filter while the request is
pending, the callback removes those newer values; after a kind switch, the save effect also writes
the cleared filter to the new kind's localStorage entry.
Code

packages/k8s-ui/src/components/resources/ResourcesView.tsx[R6836-6841]

+                                    onClick={() => {
+                                      setOpenColumnFilter(null)
+                                      // Keep the column filter until the scope change lands; a failed one keeps the user's filter.
+                                      Promise.resolve(onApplyNamespacesToAllSections(activeFilterValues))
+                                        .then(() => clearColumnFilter(col.key), () => {})
+                                    }}
Evidence
The action closes the dropdown without preventing subsequent edits, and its success callback calls
clearColumnFilter. That function uses functional state updates to remove the column's current
filter values; the kind-change effect restores another kind's filters into that same state around
lines 5211-5221, and the save effect writes a subsequent clear through onKindFiltersChange around
lines 5233-5243 when filtersArrivedRef is null.

packages/k8s-ui/src/components/resources/ResourcesView.tsx[3841-3853]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[5233-5243]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[6833-6846]
packages/k8s-ui/src/components/resources/ResourcesView.tsx[3841-3852]
web/src/App.tsx[1468-1474]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A pending "Apply to all sections" request can clear a different kind's Namespace filter or erase edits made after submission; a clear after a kind switch can also be saved to that kind's localStorage entry.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[6833-6846]
- packages/k8s-ui/src/components/resources/ResourcesView.tsx[3841-3852]
## Recommended Fix
When the button is clicked, record `selectedKindIdentity` using a ref holding the current identity, along with the submitted Namespace filter values and exclude mode. On success, call `clearColumnFilter(col.key)` only if the current kind identity and filter selection still match those recorded at submission; preserve the filter on failure.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
ðŸ’Ą Did you know, you can turn these tips off under Display > Comment parts

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread packages/k8s-ui/src/components/resources/ActiveFilterBar.tsx
Comment thread web/src/utils/viewMemory.ts Outdated
Comment thread web/src/utils/viewMemory.ts Outdated
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx
Switching resource kinds cleared the column and problem filters, and
leaving Resources from the nav rail dropped back to a bare Pods list.

Keep a per-session memory of each kind's filters and each section's
last list URL, recorded from the router location so the URL stays the
source of truth. A user kind switch restores that kind's filters; the
rail and other section shortcuts return to the remembered list. Links
that navigate with their own params, Back/Forward and URL-driven kind
changes are unchanged. The namespace pick, investigation focus and
drawer/detail params are never remembered. Memory lives in the app
mount, so a reload or context switch forgets it and Radar Hub keeps
clusters apart.

The Namespace column filter gets "Apply to all sections": it sets the
header namespace picker to the included values, clears the column
filter once that lands, and flashes the picker. Not offered when
embedded or under cache-scoped namespaces.
Session memory lost a kind's filters on reload, in a new tab, after a
desktop restart and whenever Radar Hub remounted the cluster view.

Keep each kind's column and problem filters in localStorage, per
cluster. The URL stays the source of truth: a URL with its own list
state is shown as is, and only a bare /resources/<kind> restores the
saved filters, rewriting the URL with replace. The saved filters are
the last ones chosen, by the user or by a link that carries filters; a
restore never saves again, and a link without filters (one resource,
an owner's pods, a search) leaves them alone. Clear filters removes
them.

Each tab keeps what it has shown, so filters chosen in another tab
don't change it; localStorage only seeds a kind the first time a tab
reads it. Bare /resources, which Radar Hub's rail links to, and the
Resources rail item go to the last kind.

Make active filters visible: Clear filters shows an accent and a count,
a line says when filters were restored from the last visit, and the
active filters show as removable chips above the table as well as in
the empty state.

A kind switch that restores filters now adds one history entry instead
of two, and the URL sync also reads problem filters, so Back keeps them.
â€Ķst params

"Apply to all sections" hands the namespace scope to the header picker.
A Namespace column filter saved on another kind then narrowed or emptied
that kind's list with nothing but a chip to explain it, so applying now
clears the Namespace column on every kind of the cluster. Other column
and problem filters stay.

Section memory kept every param except a blocklist, so a param a view
added later was replayed as list state: an open Application reopened
when returning from the rail. Each section now keeps only the params
that shape its list; anything else is dropped. Timeline keeps `time`,
which the Home warnings link sets.

A fresh load of bare /resources mounted the list before the last kind
was known, so it landed on Pods and saved Pods as the last kind. The
list now waits for the redirect. Apply to all sections is offered once
the per-cluster store exists.

The Resources filter params, the filters query helpers and the list
route pattern each have one definition now.
@arlenvasconcelos
arlenvasconcelos force-pushed the arlen/rad-622-filter-state-across-kind-and-section-switches branch from 74315b8 to 393c289 Compare October 11, 2026 17:17
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx Fixed
@arlenvasconcelos
arlenvasconcelos marked this pull request as ready for review October 11, 2026 21:54
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx
Comment thread web/src/App.tsx Outdated
Comment thread packages/k8s-ui/src/components/resources/ResourcesView.tsx Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 393c289

The host's namespace picker follows ?namespaces=, which the app mirrors from
the server pick, so applying the namespaces reaches it as well.
@cursor

cursor Bot commented Oct 11, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

On a kind switch the URL write ran once with the previous kind's filters
before the new kind's were restored, pushing a URL with the wrong filters.
â€Ķ and duplicate

A reload or a duplicated tab keeps the tab's own Resources filters and
section memory (sessionStorage); a new tab starts from the last saved
filters. Section memory is now kept per cluster instead of being cleared
on context switch.
The Clear link next to "Filters restored" now resets only the kind's
column and problem filters. Search, labels and the namespace pick stay.
The link is always underlined so it reads as an action.
â€Ķstate-across-kind-and-section-switches

# Conflicts:
#	web/src/App.tsx
@arlenvasconcelos
arlenvasconcelos merged commit 86ae0f5 into skyhook-io:main Oct 13, 2026
9 checks passed
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.

3 participants