PR 19793 review, round two

rancher/dashboard PR 19793 (codyrancher), re-requested after 2504b41ff, reviewed 2026-11-05. Round one is here, though its preview links now show the new code.

Preview: rancherpr19793r.mf-created-dashboard.ui.rancher.space, built from 2504b41ff, backend mf Rancher (v2.16.0-7758e3e-head). PR + no-clear: rancherpr19793-fixr.mf-created-dashboard.ui.rancher.space, built from bdbbd7de2, which is the PR with card 1's change, local only and not pushed. Baseline: the shared dashboard-master preview, rebuilt today from 261b8932f, the current tip.

Verdict: one change left, then approve

Test it yourself

Click Log in as a local user, then use issue-8544-member. The password is in ~/Projects/pr-reviews/pr19793-fixtures/password.txt on your Mac.

  1. Get there: in the top nav, filter to Project: view-only-8544 only. This user can create in another project, so Create is still offered.
  2. Secret: open PR: Create Secret and pick Opaque. The Namespace field isn't there, and Create stays disabled once you type a name.
  3. Chart install: open PR: Chart install. Namespace is blank, but Proceed and Install both work. Install fails with namespaces "default" already exists. It only sends a request, and nothing gets installed for this user.
  4. Compare: open PR + no-clear: Create Secret or master with the same filter. The field shows, and Create gives the clear "forbidden" message.
  5. Afterwards: set the filter back to Only User Namespaces so the next test starts clean.
Your review, Cody's answers, and what I found
Your commentCody's answerChecked on the new build
The namespace the form opens on isn't checked. A read-only namespace that sorts first opens selected and listed, and Create is forbidden."when the check returns, a pre-selected namespace that exists but does not allow creating the type moves to the first allowed one, or is cleared if there is none."The move works. It opens on secrets-ns1 for issue-8544-first and issue-8544-cm, on Secret, Deployment and chart install. Create returned 201. The "or is cleared" half is card 1.
allowedNamespaces has lost its last real use. Maybe keep it on shell or find a use, mostly pointing it out."Kept it because it is a root-store getter extensions can call", marked @deprecated. "Happy to remove it in this PR if you would rather."Fair. A runtime break for third-party extensions isn't worth it for a few lines. Deprecated is what I'd accept. The unused fixture line in the test and the unread mapGetters entry remain, and neither is worth another round.
This file is quite small, and Richard usually pushes against new utils."I'm fine to consolidate. Moving it to NamespaceSelect and the tests into NamespaceSelect.test.ts."Done. The file and its test file are gone. The function now uses the component's own store, so store: any went with it. const namespaces: any[] remains, which isn't worth raising.
Findings
1

Clearing the namespace breaks the Secret form and chart install

shell/components/form/NamespaceSelect.vue:265-268 (new in 2504b41ff)
Should fix

When no namespace in the list allows creating, the commit does namespace.value = null and emits null. Nothing else in the forms expected a null namespace. The select's own empty value is '', and the emit type had to be widened to string | null just for this.

Master: the Namespace field shows view-only-ns and Create gives a clear forbidden error
master, Secret: the field shows, and Create gives a clear "forbidden".
PR: the Namespace field is gone, leaving a gap before Name
PR, Secret: the Namespace field is gone. Create stays disabled, with no message.
PR: chart install shows namespaces default already exists
PR, chart install: blank field, Install enabled, then namespaces "default" already exists.
PR with the clear branch removed: same as master
PR + no-clear: same as master.

What happens, and why

Who reaches it

Anyone with no creatable namespace in the current list, which is more than users with no rights at all. issue-8544-member can create in another project but gets here just by filtering the top nav to a read-only project, because the list stays inside the filter.

The fix

Drop the else branch and put the emit type back to string, so the value stays as it is when nothing is allowed. That matches master: the namespace shows, and Create gives the clear "forbidden" message from the server. All the problems above share this one cause, so they all go away, and it's fewer lines.

Switching null to '' looks tempting but only helps Secret. targetNamespace treats both as empty, so chart install would still target default.

Tested: the 2 touched suites pass (60 tests, with Cody's clears test changed to expect the value kept), lint is clean, and there are no new type errors. In the browser with the same filter, Secret, ConfigMap and chart install all match master, and the chart request goes out with view-only-ns, not null.

Fix diff (for you, not for the GitHub comment)
--- a/shell/components/form/NamespaceSelect.vue
+++ b/shell/components/form/NamespaceSelect.vue
@@ -51,7 +51,7 @@ interface Props {
   createAllowed?: boolean;
   /**
    * schema id of the resource being created; in create mode only namespaces the user may create it in are listed, and
-   * an existing pre-selected namespace the user may not create it in is replaced by the first one listed (or cleared)
+   * an existing pre-selected namespace the user may not create it in is replaced by the first one listed
    */
   resourceType?: string | null;
   rules?: Validator[];
@@ -84,7 +84,7 @@ const props = withDefaults(defineProps<Props>(), {
   required:                false,
 });
 
-const emit = defineEmits<{(e: 'update:value', value: string | null): void, (e: 'isNamespaceNew', value: boolean): void}>();
+const emit = defineEmits<{(e: 'update:value', value: string): void, (e: 'isNamespaceNew', value: boolean): void}>();
 
 const store = useStore();
 const { t } = useI18n(store);
@@ -262,9 +262,6 @@ function leaveNamespaceNotAllowingCreate(allowed: Set<string>) {
 
   if (firstAllowed) {
     emitChange(firstAllowed);
-  } else {
-    namespace.value = null;
-    emit('update:value', null);
   }
 }
 
2

The move also applies to clones, and that seems right

shell/components/form/NamespaceSelect.vue:254-263
Your call

You raised keeping the value in your review. My earlier fix only moved the automatic default, while Cody's moves any existing namespace the user can't create in. So cloning a ConfigMap from a read-only namespace now opens on the first allowed namespace, without saying so. I think that's better: the user couldn't have saved in the source anyway, the new namespace is visible before saving, and a clone from an allowed namespace stays where it was. Nothing to raise unless you feel differently.

Is the value kept when it should be?
Starting valuemasterPRRight?
Automatic default, not allowed (issue-8544-first, issue-8544-cm)stays, Create forbiddenmoves to secrets-ns1Yes
Last-used, allowed (secrets-ns2)not runstays on secrets-ns2Yes
Last-used, not allowed (view-only-ns)not runmoves to secrets-ns1Yes
Clone, source allowed (secrets-ns2)staysstaysYes
Clone, source read-only (view-only-ns)stays, listedmoves to secrets-ns1Yes, see card 2
New namespace typed on chart install, then Proceed and Backnot runstays on zz-pr19793-typedYes
Check fails (forced 500)no check on masterstays, every namespace listedYes
Nothing allowed in the liststays, Create forbiddencleared to nullNo, card 1
What else I checked
CheckResult
Lists, master vs PR5 users across Secret, ConfigMap, Deployment and chart install. Member lists are unchanged, and issue-8544 and issue-8544-first list the correct two namespaces.
Does a cleared namespace fall into default on normal creates?No. Steve rejects a missing namespace, and ConfigMap never sends the request. Only chart install has the fallback.
Round one's checksThe permission truth table and top-nav filter tests ran on ee30ed3c4. The check logic only moved in this commit, so I didn't rerun the truth table. The lists above still match.
Tests on the PR headThe 2 touched suites pass (60 tests). No new type errors, and lint is clean.
CI at 2504b41ffAll green except Branch Milestone, which fails on the other 2.17 PRs too. The kubewarden e2e passes this time.
DescriptionThe setup script now uses aaa-view-ns, so it shows the case. The Harvester line is still there because the note was cut from the submitted review. Not worth raising alone, and you could mention it if you comment anyway.
Side effects of testingOne real Secret was created to check Cody's claim, then removed. No installs, operations or typed namespaces exist, and the fixture users' preferences are reset.
Suggested review (Comment)

Your usual shape: an intro, one inline comment, no code and no preview link. If you want the screenshots from card 1 on it, they still need uploading. I'd also resolve the shell/utils thread and answer Cody's question on the allowedNamespaces one.

Body

The move works well, thanks. It opens on an allowed namespace now and keeps a value the user can create in. One more thing on the clear path.

shell/components/form/NamespaceSelect.vue, line 265

Could we drop this branch and leave the value as it is when nothing is allowed? A user can get here just by filtering the top nav to a read-only project.

On the Secret form the Namespace field disappears. Its validators use (val = '') => val.length, so null throws while the select renders, and Create stays disabled with no message. On chart install the field is blank but Install stays enabled. It fails with namespaces "default" already exists, or if the user can see default it sends an empty namespace, which Rancher turns into default. It would also clear the locked select on the Fleet AppCo create form.

Without the branch this matches master: the namespace shows and Create gives the clear "forbidden" message. Using '' instead wouldn't be enough, because chart install treats it the same way.

Reply on the allowedNamespaces thread

Deprecated sounds good to me, no need to remove it here.