- {{#if list.empty}}
-
-
-
- {{else}}
+
+ {{#if this.model.namespaces.length}}
+
{{list.item.id}}
@@ -37,11 +44,14 @@
- {{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
- {{#if (includes targetNamespace this.accessibleNamespaces)}}
+ {{#let
+ (concat this.namespaceService.path (if this.namespaceService.path "/") list.item.id)
+ as |targetNamespace|
+ }}
+ {{#if (includes targetNamespace this.namespaceService.accessibleNamespaces)}}
- Switch to Namespace
+ Switch to namespace
{{/if}}
@@ -52,22 +62,21 @@
{{/if}}
+ {{else}}
+
+
+
{{/if}}
{{else}}
diff --git a/ui/lib/core/addon/components/list-view.hbs b/ui/lib/core/addon/components/list-view.hbs
index 16eede94a7..11b75bccd4 100644
--- a/ui/lib/core/addon/components/list-view.hbs
+++ b/ui/lib/core/addon/components/list-view.hbs
@@ -2,8 +2,7 @@
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
-
-{{#if (or (and @items.meta @items.meta.total) @items.length)}}
+{{#if (or (and @items.meta @items.meta.filteredTotal) @items.length)}}
{{#each @items as |item|}}
{{yield (hash item=item)}}
diff --git a/ui/lib/core/app/components/filter-input-explicit.js b/ui/lib/core/app/components/filter-input-explicit.js
index 1327ecdafc..70fb36fd1b 100644
--- a/ui/lib/core/app/components/filter-input-explicit.js
+++ b/ui/lib/core/app/components/filter-input-explicit.js
@@ -3,4 +3,25 @@
* SPDX-License-Identifier: BUSL-1.1
*/
+/**
+ * @module FilterInputExplicit
+ *
+ * @description FilterInputExplicit component is a child component to show filter input.
+ * It also handles the filtering actions of roles.
+ *
+ * @example
+ *
+ *
+ * @param {string} query - value of queryParam, such as pageFilter
+ * @param {string} placeholder - placeholder for the input field
+ * @param {function} handleSearch - callback function to handle search
+ * @param {function} handleInput - callback function to handle input
+ * @param {function} handleKeyDown - callback function to handle keydown
+ */
export { default } from 'core/components/filter-input-explicit';
diff --git a/ui/mirage/handlers/base.js b/ui/mirage/handlers/base.js
index f057dea4bb..99e5eea7db 100644
--- a/ui/mirage/handlers/base.js
+++ b/ui/mirage/handlers/base.js
@@ -94,4 +94,12 @@ export default function (server) {
},
};
});
+
+ server.get('sys/internal/ui/namespaces', function () {
+ return {
+ data: {
+ keys: ['ns1/', 'ns2/', 'ns3/', 'ns4/', 'ns5/', 'ns6/', 'ns7/', 'ns8/', 'ns9/', 'ns10/'],
+ },
+ };
+ });
}
diff --git a/ui/tests/acceptance/access/namespaces/index-test.js b/ui/tests/acceptance/access/namespaces/index-test.js
index ae361e9505..9ddca0bcf3 100644
--- a/ui/tests/acceptance/access/namespaces/index-test.js
+++ b/ui/tests/acceptance/access/namespaces/index-test.js
@@ -3,16 +3,20 @@
* SPDX-License-Identifier: BUSL-1.1
*/
-import { currentRouteName, visit } from '@ember/test-helpers';
+import { currentRouteName, visit, click, fillIn, currentURL } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { login } from 'vault/tests/helpers/auth/auth-helpers';
+import { GENERAL } from 'vault/tests/helpers/general-selectors';
module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
+ const searchInput = GENERAL.filterInputExplicit;
+ const searchButton = GENERAL.filterInputExplicitSearch;
+
hooks.beforeEach(function () {
return login();
});
@@ -33,7 +37,99 @@ module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
const store = this.owner.lookup('service:store');
// Default page size is 15
assert.strictEqual(store.peekAll('namespace').length, 15, 'Store has 15 namespaces records');
- assert.dom('.list-item-row').exists({ count: 15 });
+ assert.dom('.list-item-row').exists({ count: 15 }, 'Should display 15 namespaces');
assert.dom('.hds-pagination').exists();
});
+
+ test('it should show button to create new namespace', async function (assert) {
+ await visit('/vault/access/namespaces');
+ const createNamespaceButton = 'nav.toolbar-actions a.toolbar-link';
+ assert
+ .dom(createNamespaceButton)
+ .hasText('Create namespace', 'Create namespace button is rendered correctly');
+ assert
+ .dom(createNamespaceButton)
+ .hasAttribute(
+ 'href',
+ '/ui/vault/access/namespaces/create',
+ 'Create namespace button has the correct href attribute'
+ );
+ });
+
+ test('it should filter namespaces based on search input', async function (assert) {
+ await visit('/vault/access/namespaces');
+
+ // Enter search text
+ await fillIn(searchInput, 'ns4');
+ assert.dom(searchInput).hasValue('ns4', 'Search input contains the entered text');
+
+ // Click the search button
+ await click(searchButton);
+
+ // Verify the filtered results
+ assert.dom('.list-item-row').exists({ count: 1 }, 'Filtered results are displayed correctly');
+ assert.dom('.list-item-row').hasText('ns4', 'Correct namespace is displayed in the filtered results');
+
+ // Verify the URL query param is updated
+ assert.strictEqual(
+ currentURL(),
+ '/vault/access/namespaces?page=1&pageFilter=ns4',
+ 'URL query param is updated to reflect the search field as pageFilter'
+ );
+
+ // Clear the search input
+ await fillIn(searchInput, '');
+ await click(searchButton);
+ assert.dom(searchInput).hasValue('', 'Search input is cleared');
+ assert
+ .dom('.list-item-row')
+ .exists({ count: 15 }, 'All namespaces are displayed after clearing the search input');
+ assert.strictEqual(
+ currentURL(),
+ '/vault/access/namespaces?page=1',
+ 'URL query param is updated to remove pageFilter'
+ );
+ });
+
+ test('it should show options menu for each namespace', async function (assert) {
+ await visit('/vault/access/namespaces');
+ assert.dom(GENERAL.menuTrigger).exists();
+ await click(GENERAL.menuTrigger);
+ assert.dom('.hds-dropdown-list-item').exists({ count: 2 }, 'Should display 2 options in the menu.');
+
+ // Verify that the user can switch to the namespace
+ const switchNamespaceButton = '.hds-dropdown-list-item:nth-of-type(1)';
+ assert
+ .dom(switchNamespaceButton)
+ .hasText('Switch to namespace', 'Allow users to switch to different namespace');
+ assert
+ .dom(`${switchNamespaceButton} a`)
+ .hasAttribute(
+ 'href',
+ 'http://localhost:7357/ui/vault/dashboard?namespace=ns1',
+ 'Switch namespace button has the correct href attribute'
+ );
+
+ // Verify that the user can delete the namespace
+ const deleteNamespaceButton = '.hds-dropdown-list-item:nth-of-type(2)';
+ assert.dom(deleteNamespaceButton).hasText('Delete', 'Allow users to delete the namespace');
+ });
+
+ test('it should hide the switch to namespace option for unaccessible namespaces', async function (assert) {
+ await visit('/vault/access/namespaces');
+
+ // Search for a namespace that is not accessible
+ await fillIn(searchInput, 'ns12');
+ await click(searchButton);
+
+ assert.dom(GENERAL.menuTrigger).exists();
+ await click(GENERAL.menuTrigger);
+
+ // Verify that only the delete option is available for the unaccessible namespace
+ assert.dom('.hds-dropdown-list-item').exists({ count: 1 }, 'Should display 1 option in the menu.');
+
+ // Verify that the user can delete the namespace
+ const deleteNamespaceButton = '.hds-dropdown-list-item:nth-of-type(1)';
+ assert.dom(deleteNamespaceButton).hasText('Delete', 'Allow users to delete the namespace');
+ });
});
diff --git a/ui/tests/acceptance/enterprise-namespaces-test.js b/ui/tests/acceptance/enterprise-namespaces-test.js
index f6f047e0e4..28d523d676 100644
--- a/ui/tests/acceptance/enterprise-namespaces-test.js
+++ b/ui/tests/acceptance/enterprise-namespaces-test.js
@@ -294,4 +294,39 @@ module('Acceptance | Enterprise | namespaces', function (hooks) {
'correctly sanitizes namespace'
);
});
+
+ test('it should allow the user to delete a namespace', async function (assert) {
+ // Test Setup
+ const namespaces = ['test-delete-me'];
+ await createNamespaces(namespaces);
+
+ await visit('/vault/access/namespaces');
+
+ const searchInput = GENERAL.filterInputExplicit;
+ const searchButton = GENERAL.filterInputExplicitSearch;
+
+ await fillIn(searchInput, 'test-delete-me');
+ await click(searchButton);
+
+ assert.dom(GENERAL.menuTrigger).exists();
+ await click(GENERAL.menuTrigger);
+
+ // Verify that the user can delete the namespace
+ const deleteNamespaceButton = '.hds-dropdown-list-item:nth-of-type(1)';
+ assert.dom(deleteNamespaceButton).hasText('Delete', 'Allow users to delete the namespace');
+ await click(`${deleteNamespaceButton} button`);
+
+ assert.dom(GENERAL.confirmButton).hasText('Confirm', 'Allow users to delete the namespace');
+ await click(GENERAL.confirmButton);
+
+ assert.strictEqual(
+ currentURL(),
+ '/vault/access/namespaces?page=1&pageFilter=test-delete-me',
+ 'Should remain on the manage namespaces page after deletion'
+ );
+
+ assert
+ .dom('.list-item-row')
+ .exists({ count: 0 }, 'Namespace should be deleted and not displayed in the list');
+ });
});