Repository: derailed/k9s

Issue:
Favorite namespaces not limited to 9 in cluster config file
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_err.png" align="right" width="100" height="auto"/>

<br/>
<br/>
<br/>

**Describe the bug**  

In the file `~/.local/share/k9s/clusters/[cluster]/[context]/config.yaml`, there is a `favorites` list of the user's favorite namespaces. On the latest version of k9s (currently `v0.32.7`), this list is automatically filled with namespaces that the user visits, and it is limited to 9 items. However, in older versions of k9s, this wasn't enforced and the list could grow beyond 9 items. In those older versions, this resulted in bugs that prevented the user from being able to select multiple pods using `CTRL + SPACE`. The related issue is [this one](https://github.com/derailed/k9s/issues/2882), and this is the [pull request](https://github.com/derailed/k9s/pull/2881). The `CTRL + SPACE` bug is now resolved by the pull request.  

However, there is still an inconsistency present in the code: when installing the latest k9s version, old cluster config files are still loaded as normal, even though they might contain more than 9 namespaces in the favorites section. In `v0.32.7`, when such a config file is loaded, the `CTRL + SPACE` bug does not happen, but when the cluster's config file is saved, it still contains more than 9 favorite namespaces. I believe this is inconsistent with k9s' invariants and that the favorite namespaces list should automatically be capped to 9 immediately upon loading the file, as well as when saving it again.  

If the maintainers agree that this should be the expected behavior, I would like to claim this issue and resolve it in a pull request myself. The reason why I'm asking is because I need it for a school project, and because I actually use k9s a lot, so being able to contribute to the project is interesting to me, even if it's only a small fix such as this one.

**To Reproduce**
1. Connect to a cluster with 10 or more namespaces using an old k9s version (e.g. `v0.32.5` or older) 
2. Randomly enter and exit namespaces until more than 9 are accumulated in the config file (unfortunately, I haven't discovered how exactly this happens, but it will happen after some trial and error and it was fixed in the latest version anyway)
3. Reload k9s (still `v0.32.5`) and confirm that now `CTRL + SPACE` doesn't work in `pods`
4. Upgrade to latest k9s (`v0.32.7`, also tested with latest master, `commit SHA 6b5d24f5741a1789fb97ba3e11f0ee868d93459d`)
5. Randomly enter and exit namespaces again -> `CTRL + SPACE` will now work in `pods`
6. Checking the cluster config file, you will see that it still contains more than 9 namespaces in the favorites list

**Expected behavior**  

The favorite namespaces list in the cluster config file should be reset to at most 9 namespaces after being opened by the latest k9s version.

**Versions (please complete the following information):**

- OS: [Pop!_OS 22.04 LTS (Linux 6.9.3)]
- K9s: [v0.32.7]
- K8s: [v1.31.2]

Discussion:

Solution patch:
diff --git a/internal/config/data/ns.go b/internal/config/data/ns.go
index 14b1c667..8702e88c 100644
--- a/internal/config/data/ns.go
+++ b/internal/config/data/ns.go
@@ -52,6 +52,8 @@ func (n *Namespace) merge(old *Namespace) {
 		}
 		n.Favorites = append(n.Favorites, fav)
 	}
+
+	n.trimFavNs()
 }
 
 // Validate validates a namespace is setup correctly.
@@ -69,12 +71,7 @@ func (n *Namespace) Validate(c client.Connection) {
 		}
 	}
 
-	if len(n.Favorites) > MaxFavoritesNS {
-		log.Debug().Msgf("[Namespace] Number of favorite exceeds hard limit of %v. Trimming.", MaxFavoritesNS)
-		for _, ns := range n.Favorites[MaxFavoritesNS:] {
-			n.rmFavNS(ns)
-		}
-	}
+	n.trimFavNs()
 }
 
 // SetActive set the active namespace.
@@ -135,3 +132,10 @@ func (n *Namespace) rmFavNS(ns string) {
 
 	n.Favorites = append(n.Favorites[:victim], n.Favorites[victim+1:]...)
 }
+
+func (n *Namespace) trimFavNs() {
+	if len(n.Favorites) > MaxFavoritesNS {
+		log.Debug().Msgf("[Namespace] Number of favorite exceeds hard limit of %v. Trimming.", MaxFavoritesNS)
+		n.Favorites = n.Favorites[:MaxFavoritesNS]
+	}
+}



Test patch:
diff --git a/internal/config/data/context_int_test.go b/internal/config/data/context_int_test.go
index b4a78b24..92fb59b4 100644
--- a/internal/config/data/context_int_test.go
+++ b/internal/config/data/context_int_test.go
@@ -75,6 +75,26 @@ func Test_contextMerge(t *testing.T) {
 			c2: &Context{},
 			e:  NewContext(),
 		},
+		"too-many-favs": {
+			c1: &Context{
+				Namespace: &Namespace{
+					Active:    "ns1",
+					Favorites: []string{"ns1", "ns2", "ns3", "ns4", "ns5", "ns6", "ns7", "ns8", "ns9"},
+				},
+			},
+			c2: &Context{
+				Namespace: &Namespace{
+					Active:    "ns10",
+					Favorites: []string{"ns10", "ns11", "ns12"},
+				},
+			},
+			e: &Context{
+				Namespace: &Namespace{
+					Active:    "ns1",
+					Favorites: []string{"ns1", "ns2", "ns3", "ns4", "ns5", "ns6", "ns7", "ns8", "ns9"},
+				},
+			},
+		},
 	}
 
 	for k, u := range uu {