diff --git a/ui/app/components/page/namespaces.hbs b/ui/app/components/page/namespaces.hbs
index 6181b3f74a..46b88b326b 100644
--- a/ui/app/components/page/namespaces.hbs
+++ b/ui/app/components/page/namespaces.hbs
@@ -16,90 +16,150 @@
@breadcrumbs={{array (hash label="Vault" route="vault.cluster.dashboard" icon="vault") (hash label="Namespaces")}}
/>
+ <:badges>
+
+
+ <:actions>
+ {{#unless @model.namespaces}}
+
+
+ {{/unless}}
+
-
-
-
-
-
-
-
- Create namespace
-
-
-
-
-
- {{#if @model.namespaces.length}}
-
-
- {{list.item.id}}
-
-
-
-
- {{#let (concat this.namespace.path (if this.namespace.path "/") list.item.id) as |targetNamespace|}}
- {{#if (includes targetNamespace this.namespace.accessibleNamespaces)}}
- Switch to namespace
- {{/if}}
- {{/let}}
- Delete
-
- {{#if (eq this.nsToDelete list.item)}}
-
- {{/if}}
-
-
- {{else}}
-
-
+
+
-
+
+
+
+
+ Create namespace
+
+
+
+
+
+ {{#if @model.namespaces.length}}
+
+
+ {{list.item.id}}
+
+
+
+
+ {{#let (concat this.namespace.path (if this.namespace.path "/") list.item.id) as |targetNamespace|}}
+ {{#if (includes targetNamespace this.namespace.accessibleNamespaces)}}
+ Switch to namespace
+ {{/if}}
+ {{/let}}
+ Delete
+
+ {{#if (eq this.nsToDelete list.item)}}
+
+ {{/if}}
+
+
+ {{else}}
+
+
+
+ {{/if}}
+
+ {{else}}
+ {{#if this.showSetupAlert}}
+
+ Your current setup is 1 namespace.
+ Based on your answer about your security policy in the Guided start, no new namespaces are required.
+
{{/if}}
-
+
+
+
+
+
+
+
+
+
+
+
+ {{/if}}
+
{{/if}}
+
{{else}}
{{/if}}
\ No newline at end of file
diff --git a/ui/app/components/page/namespaces.ts b/ui/app/components/page/namespaces.ts
index 2ce1b7b61c..0976b8e81e 100644
--- a/ui/app/components/page/namespaces.ts
+++ b/ui/app/components/page/namespaces.ts
@@ -10,6 +10,7 @@ import Component from '@glimmer/component';
import keys from 'core/utils/keys';
import type ApiService from 'vault/services/api';
+import type FlagsService from 'vault/services/flags';
import type FlashMessageService from 'vault/services/flash-messages';
import type NamespaceService from 'vault/services/namespace';
import type RouterService from '@ember/routing/router-service';
@@ -45,6 +46,7 @@ interface NamespaceModel {
export default class PageNamespacesComponent extends Component {
@service declare readonly api: ApiService;
@service declare readonly router: RouterService;
+ @service declare readonly flags: FlagsService;
@service declare readonly flashMessages: FlashMessageService;
@service declare namespace: NamespaceService;
@@ -53,6 +55,7 @@ export default class PageNamespacesComponent extends Component {
// browser query param to prevent unnecessary re-renders.
@tracked query;
@tracked nsToDelete = null;
+ @tracked showSetupAlert = false;
@tracked hasDismissedWizard = false;
wizardId = 'namespace';
@@ -68,6 +71,21 @@ export default class PageNamespacesComponent extends Component {
}
}
+ // show the full available namespace path e.g. "root/ns1/child2", "admin/ns1/child2"
+ get namespacePath() {
+ if (this.namespace.inRootNamespace) {
+ return 'root';
+ }
+
+ // For nested namespaces, show "root/" prefix if not HVD managed and no separate user root
+ if (!this.namespace.userRootNamespace && !this.flags.isHvdManaged) {
+ return `root/${this.namespace.path}`;
+ }
+
+ // If there is a userRootNamespace or it is HVD managed, then the path alone will suffice
+ return this.namespace.path;
+ }
+
get showWizard() {
// Show when there are no existing namespaces and it is not in a dismissed state
return !this.hasDismissedWizard && !this.args.model.namespaces?.length;
@@ -123,6 +141,11 @@ export default class PageNamespacesComponent extends Component {
}
}
+ @action
+ enterGuidedStart() {
+ this.hasDismissedWizard = false;
+ }
+
@action handlePageChange() {
this.args.onRefresh();
}
diff --git a/ui/app/components/wizard/namespaces/namespace-wizard.hbs b/ui/app/components/wizard/namespaces/namespace-wizard.hbs
index f5c0b36287..3068b35da7 100644
--- a/ui/app/components/wizard/namespaces/namespace-wizard.hbs
+++ b/ui/app/components/wizard/namespaces/namespace-wizard.hbs
@@ -17,9 +17,9 @@
<:exit>
- {{#unless (eq this.wizardState.creationMethod this.methods.UI)}}
+ {{#if this.shouldShowExitButton}}
- {{/unless}}
+ {{/if}}
<:submit>
{{#if (eq this.wizardState.securityPolicyChoice this.policy.FLEXIBLE)}}
diff --git a/ui/app/components/wizard/namespaces/namespace-wizard.ts b/ui/app/components/wizard/namespaces/namespace-wizard.ts
index 853da7f53a..098e01d73c 100644
--- a/ui/app/components/wizard/namespaces/namespace-wizard.ts
+++ b/ui/app/components/wizard/namespaces/namespace-wizard.ts
@@ -72,9 +72,17 @@ export default class WizardNamespacesWizardComponent extends Component {
}
}
+ get isFinalStep() {
+ return this.currentStep === this.steps.length - 1;
+ }
+
+ get shouldShowExitButton() {
+ // Show exit button unless we're on the final step with UI creation method
+ return !(this.wizardState.creationMethod === CreationMethod.UI && this.isFinalStep);
+ }
+
get exitText() {
- return this.currentStep === this.steps.length - 1 &&
- this.wizardState.securityPolicyChoice === SecurityPolicy.STRICT
+ return this.isFinalStep && this.wizardState.securityPolicyChoice === SecurityPolicy.STRICT
? 'Done & Exit'
: 'Exit';
}
diff --git a/ui/app/components/wizard/namespaces/step-3.ts b/ui/app/components/wizard/namespaces/step-3.ts
index 4b3cdd8cd2..c8061e4536 100644
--- a/ui/app/components/wizard/namespaces/step-3.ts
+++ b/ui/app/components/wizard/namespaces/step-3.ts
@@ -70,7 +70,7 @@ export default class WizardNamespacesStep3 extends Component {
icon: 'sidebar',
label: CreationMethod.UI,
description:
- 'Apply changes immediately. Note: Changes made here may be overwritten if you also use Infrastructure as Code (Terraform).',
+ 'Apply changes immediately. Note: Changes made in the UI will be overwritten by any future updates made via Infrastructure as Code (Terraform).',
},
];
tabOptions = ['API', 'CLI'];
diff --git a/ui/tests/acceptance/access/namespaces/index-test.js b/ui/tests/acceptance/access/namespaces/index-test.js
index f4b2230c42..208081b715 100644
--- a/ui/tests/acceptance/access/namespaces/index-test.js
+++ b/ui/tests/acceptance/access/namespaces/index-test.js
@@ -74,21 +74,9 @@ module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
const testNS = 'test-create-ns-ui';
// Verify test-create-ns does not exist in the Manage Namespace page
- await fillIn(GENERAL.filterInputExplicit, testNS);
- await click(GENERAL.button('Search'));
- await waitFor(GENERAL.emptyStateTitle, {
- timeout: 2000,
- timeoutMessage: 'timed out waiting for empty state title to render',
- });
- assert
- .dom(GENERAL.emptyStateTitle)
- .hasText(
- 'No namespaces yet',
- 'Empty state is displayed when searching for the namespace we have created in the UI but have not refreshed the list yet'
- );
// Create a new namespace in the UI
- await click(GENERAL.linkTo('create-namespace'));
+ await click(GENERAL.button('create-namespace'));
await fillIn(GENERAL.inputByAttr('path'), testNS);
await click(GENERAL.submitButton);
@@ -113,11 +101,11 @@ module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
// Setup: Create namespace(s) via the CLI
const testNS = 'asdf';
await runCmd(createNS(testNS), false);
+ await click(GENERAL.button('refresh-namespace-list'));
// Search for created namespace// Enter search text
await fillIn(GENERAL.filterInputExplicit, testNS);
await click(GENERAL.button('Search'));
- await click(GENERAL.button('refresh-namespace-list'));
// Verify the menu options
await waitFor(GENERAL.menuTrigger, {
@@ -135,11 +123,11 @@ module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
// Setup: Create namespace(s) via the CLI
const testNS = 'test-create-ns-switch';
await runCmd(createNS(testNS), false);
+ await click(GENERAL.button('refresh-namespace-list'));
// Search for created namespace
await fillIn(GENERAL.filterInputExplicit, testNS);
await click(GENERAL.button('Search'));
- await click(GENERAL.button('refresh-namespace-list'));
// Switch namespace
await waitFor(GENERAL.menuTrigger);