From 263584d7b410ce36cde4d896900cfef8c2a82126 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
Date: Thu, 22 Feb 2024 17:11:48 -0600
Subject: [PATCH] UI: Replace popup-menu on list items (#25588)
---
changelog/25588.txt | 3 +
ui/app/components/generated-item-list.js | 2 +
ui/app/styles/components/popup-menu.scss | 15 +++
.../components/generated-item-list.hbs | 48 ++++++----
.../vault/cluster/access/namespaces/index.hbs | 56 +++++++-----
.../components/list-item/popup-menu.hbs | 12 +--
.../addon/templates/credentials/index.hbs | 39 +++++---
.../kmip/addon/templates/credentials/show.hbs | 2 +-
ui/lib/kmip/addon/templates/scope/roles.hbs | 74 +++++++--------
ui/lib/kmip/addon/templates/scopes/index.hbs | 35 ++++---
.../addon/components/page/roles.hbs | 65 +++++++------
.../kubernetes/addon/components/page/roles.js | 4 +
.../ldap/addon/components/page/libraries.hbs | 66 ++++++--------
.../ldap/addon/components/page/libraries.ts | 1 +
ui/lib/ldap/addon/components/page/roles.hbs | 91 +++++++++----------
ui/lib/ldap/addon/components/page/roles.ts | 7 ++
.../components/secrets/page/destinations.hbs | 2 +-
.../components/secrets/page/destinations.ts | 2 +-
.../page/destinations/destination/secrets.hbs | 2 +-
.../page/destinations/destination/secrets.ts | 2 +-
ui/tests/acceptance/enterprise-kmip-test.js | 7 --
.../secrets/backend/kubernetes/roles-test.js | 7 --
.../secrets/backend/ldap/libraries-test.js | 7 --
.../secrets/backend/ldap/roles-test.js | 7 --
.../components/kubernetes/page/roles-test.js | 7 +-
25 files changed, 288 insertions(+), 275 deletions(-)
create mode 100644 changelog/25588.txt
diff --git a/changelog/25588.txt b/changelog/25588.txt
new file mode 100644
index 0000000000..95a45130cd
--- /dev/null
+++ b/changelog/25588.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: replace popup menu on list items (namespaces, auth items, KMIP, K8S, LDAP)
+```
\ No newline at end of file
diff --git a/ui/app/components/generated-item-list.js b/ui/app/components/generated-item-list.js
index 58586c5d0a..6339b1e5cd 100644
--- a/ui/app/components/generated-item-list.js
+++ b/ui/app/components/generated-item-list.js
@@ -7,6 +7,7 @@ import { service } from '@ember/service';
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { getOwner } from '@ember/application';
+import { tracked } from '@glimmer/tracking';
/**
* @module GeneratedItemList
@@ -26,6 +27,7 @@ import { getOwner } from '@ember/application';
export default class GeneratedItemList extends Component {
@service router;
@service store;
+ @tracked showConfirmModal = false;
get model() {
return this.args.model || null;
diff --git a/ui/app/styles/components/popup-menu.scss b/ui/app/styles/components/popup-menu.scss
index 94071a2fae..0084da2693 100644
--- a/ui/app/styles/components/popup-menu.scss
+++ b/ui/app/styles/components/popup-menu.scss
@@ -176,3 +176,18 @@
}
}
}
+
+// Match HDS styling for namespace ink
+a.ns-dropdown-item {
+ color: var(--token-color-foreground-primary);
+ display: flex;
+ align-items: flex-start;
+ padding: 7px 9px 7px 0px;
+ border: 1px solid transparent;
+ outline-style: solid;
+ outline-color: transparent;
+ text-decoration: none;
+ &:hover {
+ color: var(--token-color-foreground-action-hover);
+ }
+}
diff --git a/ui/app/templates/components/generated-item-list.hbs b/ui/app/templates/components/generated-item-list.hbs
index 1ded6a6856..7a5c6d5f81 100644
--- a/ui/app/templates/components/generated-item-list.hbs
+++ b/ui/app/templates/components/generated-item-list.hbs
@@ -72,21 +72,36 @@
{{list.item.id}}
-
-
- View
- {{singularize this.itemType}}
-
-
-
-
- Edit
- {{singularize this.itemType}}
-
-
-
+
+
+
+
+
+
+
+ {{#if this.showConfirmModal}}
+
-
+ {{/if}}
{{/if}}
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/access/namespaces/index.hbs b/ui/app/templates/vault/cluster/access/namespaces/index.hbs
index 942371d369..d68832f9ca 100644
--- a/ui/app/templates/vault/cluster/access/namespaces/index.hbs
+++ b/ui/app/templates/vault/cluster/access/namespaces/index.hbs
@@ -35,31 +35,37 @@
{{list.item.id}}
- {{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
- {{#if (includes targetNamespace this.accessibleNamespaces)}}
-
-
- Switch to Namespace
-
-
- {{/if}}
- {{/let}}
-
+
+
+ {{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
+ {{#if (includes targetNamespace this.accessibleNamespaces)}}
+
+
+ Switch to Namespace
+
+
+ {{/if}}
+ {{/let}}
+
+
+ {{#if this.showConfirmModal}}
+
+ {{/if}}
{{/if}}
diff --git a/ui/lib/core/addon/templates/components/list-item/popup-menu.hbs b/ui/lib/core/addon/templates/components/list-item/popup-menu.hbs
index 91188fa508..23f7a85c13 100644
--- a/ui/lib/core/addon/templates/components/list-item/popup-menu.hbs
+++ b/ui/lib/core/addon/templates/components/list-item/popup-menu.hbs
@@ -3,14 +3,4 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-{{#if this.hasMenu}}
-
-
-
-{{else}}
- {{yield this.item}}
-{{/if}}
\ No newline at end of file
+{{yield this.item}}
\ No newline at end of file
diff --git a/ui/lib/kmip/addon/templates/credentials/index.hbs b/ui/lib/kmip/addon/templates/credentials/index.hbs
index ebcf3b8733..00f57aa795 100644
--- a/ui/lib/kmip/addon/templates/credentials/index.hbs
+++ b/ui/lib/kmip/addon/templates/credentials/index.hbs
@@ -63,22 +63,33 @@
{{list.item.id}}
-
-
- View credentials
-
-
- {{#if list.item.deletePath.isPending}}
-
-
-
- {{else if list.item.deletePath.canDelete}}
-
+
+
+ {{#if list.item.deletePath.isPending}}
+
+
+
+ {{else if list.item.deletePath.canDelete}}
+
+ {{/if}}
+
+ {{#if this.showConfirmModal}}
+
diff --git a/ui/lib/kmip/addon/templates/scope/roles.hbs b/ui/lib/kmip/addon/templates/scope/roles.hbs
index 7328ccc621..24fefc62d6 100644
--- a/ui/lib/kmip/addon/templates/scope/roles.hbs
+++ b/ui/lib/kmip/addon/templates/scope/roles.hbs
@@ -69,44 +69,44 @@
{{list.item.id}}
-
-
- View credentials
-
-
-
-
- View role
-
-
- {{#if list.item.updatePath.isPending}}
-
-
-
- {{else}}
- {{#if list.item.updatePath.canUpdate}}
-
- Edit role
-
- {{/if}}
- {{#if list.item.updatePath.canDelete}}
-
+
+
+
+
+ {{#if list.item.updatePath.isPending}}
+
+
+
+ {{else}}
+ {{#if list.item.updatePath.canUpdate}}
+
+ {{/if}}
+ {{#if list.item.updatePath.canDelete}}
+
+ {{/if}}
{{/if}}
+
+ {{#if this.showConfirmModal}}
+
{{/if}}
diff --git a/ui/lib/kmip/addon/templates/scopes/index.hbs b/ui/lib/kmip/addon/templates/scopes/index.hbs
index bd6ca85b8f..2eccaa146b 100644
--- a/ui/lib/kmip/addon/templates/scopes/index.hbs
+++ b/ui/lib/kmip/addon/templates/scopes/index.hbs
@@ -58,22 +58,29 @@
{{list.item.id}}
-
-
- View scope
-
-
- {{#if list.item.updatePath.isPending}}
-
-
-
- {{else if list.item.updatePath.canDelete}}
-
+
+
+ {{#if list.item.updatePath.isPending}}
+
+
+
+ {{else if list.item.updatePath.canDelete}}
+
+ {{/if}}
+
+ {{#if this.showConfirmModal}}
+ {{role.name}}
- {{#if role.rolesPath.isLoading}}
-
-
-
- {{else}}
-
-
- Details
-
-
-
-
- Edit
-
-
-
+ {{#if (or role.canRead role.canEdit role.canDelete)}}
+
+
+ {{#if role.canRead}}
+
+ {{/if}}
+ {{#if role.canEdit}}
+
+ {{/if}}
+ {{#if role.canDelete}}
+
+ {{/if}}
+
{{/if}}
{{/each}}
+ {{#if this.roleToDelete}}
+
+ {{/if}}
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/kubernetes/addon/components/page/roles.js b/ui/lib/kubernetes/addon/components/page/roles.js
index d4034ec846..78eeda01a4 100644
--- a/ui/lib/kubernetes/addon/components/page/roles.js
+++ b/ui/lib/kubernetes/addon/components/page/roles.js
@@ -8,6 +8,7 @@ import { service } from '@ember/service';
import { action } from '@ember/object';
import { getOwner } from '@ember/application';
import errorMessage from 'vault/utils/error-message';
+import { tracked } from '@glimmer/tracking';
/**
* @module Roles
@@ -20,6 +21,7 @@ import errorMessage from 'vault/utils/error-message';
*/
export default class RolesPageComponent extends Component {
@service flashMessages;
+ @tracked roleToDelete = null;
get mountPoint() {
return getOwner(this).mountPoint;
@@ -35,6 +37,8 @@ export default class RolesPageComponent extends Component {
} catch (error) {
const message = errorMessage(error, 'Error deleting role. Please try again or contact support');
this.flashMessages.danger(message);
+ } finally {
+ this.roleToDelete = null;
}
}
}
diff --git a/ui/lib/ldap/addon/components/page/libraries.hbs b/ui/lib/ldap/addon/components/page/libraries.hbs
index 0c0e372d61..01f41696e8 100644
--- a/ui/lib/ldap/addon/components/page/libraries.hbs
+++ b/ui/lib/ldap/addon/components/page/libraries.hbs
@@ -49,46 +49,40 @@
{{library.name}}
- {{#if library.libraryPath.isLoading}}
-
-
-
- {{else}}
-
-
- Edit
-
-
-
-
- Details
-
-
- {{#if library.canDelete}}
-
+
- {{/if}}
+ {{#if library.canEdit}}
+
+ {{/if}}
+ {{#if library.canRead}}
+
+ {{/if}}
+ {{#if library.canDelete}}
+
+ {{/if}}
+
{{/if}}
{{/each}}
+ {{#if this.libraryToDelete}}
+
+ {{/if}}
{{/if}}
\ No newline at end of file
diff --git a/ui/lib/ldap/addon/components/page/libraries.ts b/ui/lib/ldap/addon/components/page/libraries.ts
index 2ee5805a68..3aac64170f 100644
--- a/ui/lib/ldap/addon/components/page/libraries.ts
+++ b/ui/lib/ldap/addon/components/page/libraries.ts
@@ -26,6 +26,7 @@ export default class LdapLibrariesPageComponent extends Component {
@service declare readonly flashMessages: FlashMessageService;
@tracked filterValue = '';
+ @tracked libraryToDelete: LdapLibraryModel | null = null;
get mountPoint(): string {
const owner = getOwner(this) as EngineOwner;
diff --git a/ui/lib/ldap/addon/components/page/roles.hbs b/ui/lib/ldap/addon/components/page/roles.hbs
index 305902038c..740c9d92e9 100644
--- a/ui/lib/ldap/addon/components/page/roles.hbs
+++ b/ui/lib/ldap/addon/components/page/roles.hbs
@@ -50,70 +50,63 @@
- {{#if role.rolePath.isLoading}}
-
-
-
- {{else}}
-
-
- Edit
-
-
-
-
+
+ {{#if role.canEdit}}
+
+ {{/if}}
+ {{#if role.canReadCreds}}
+
- Get credentials
-
-
+ />
+ {{/if}}
{{#if role.canRotateStaticCreds}}
-
{{/if}}
-
-
- Details
-
-
+
{{#if role.canDelete}}
-
{{/if}}
- {{/if}}
+
{{/each}}
+ {{#if this.credsToRotate}}
+
+ {{/if}}
+ {{#if this.roleToDelete}}
+
+ {{/if}}
+
;
@@ -28,6 +29,8 @@ export default class LdapRolesPageComponent extends Component {
@service declare readonly flashMessages: FlashMessageService;
@service declare readonly router: RouterService;
@service declare readonly store: StoreService;
+ @tracked credsToRotate: LdapRoleModel | null = null;
+ @tracked roleToDelete: LdapRoleModel | null = null;
get mountPoint(): string {
const owner = getOwner(this) as EngineOwner;
@@ -51,6 +54,8 @@ export default class LdapRolesPageComponent extends Component {
this.flashMessages.success(message);
} catch (error) {
this.flashMessages.danger(`Error rotating credentials \n ${errorMessage(error)}`);
+ } finally {
+ this.credsToRotate = null;
}
}
@@ -64,6 +69,8 @@ export default class LdapRolesPageComponent extends Component {
this.flashMessages.success(message);
} catch (error) {
this.flashMessages.danger(`Error deleting role \n ${errorMessage(error)}`);
+ } finally {
+ this.roleToDelete = null;
}
}
}
diff --git a/ui/lib/sync/addon/components/secrets/page/destinations.hbs b/ui/lib/sync/addon/components/secrets/page/destinations.hbs
index be25d891fe..4fc03ba633 100644
--- a/ui/lib/sync/addon/components/secrets/page/destinations.hbs
+++ b/ui/lib/sync/addon/components/secrets/page/destinations.hbs
@@ -67,7 +67,7 @@
-
+
-
+
{
@@ -316,12 +315,6 @@ module('Acceptance | Enterprise | KMIP secrets', function (hooks) {
});
test('it can revoke a credential from the list', async function (assert) {
- // Popup menu causes flakiness
- setRunOptions({
- rules: {
- 'color-contrast': { enabled: false },
- },
- });
const { path, scope, role } = await generateCreds();
await credentialsPage.visit({ backend: path, scope, role });
// revoke the credentials
diff --git a/ui/tests/acceptance/secrets/backend/kubernetes/roles-test.js b/ui/tests/acceptance/secrets/backend/kubernetes/roles-test.js
index e59e9c09ee..4a8dcdbdf6 100644
--- a/ui/tests/acceptance/secrets/backend/kubernetes/roles-test.js
+++ b/ui/tests/acceptance/secrets/backend/kubernetes/roles-test.js
@@ -10,7 +10,6 @@ import kubernetesScenario from 'vault/mirage/scenarios/kubernetes';
import kubernetesHandlers from 'vault/mirage/handlers/kubernetes';
import authPage from 'vault/tests/pages/auth';
import { fillIn, visit, currentURL, click, currentRouteName } from '@ember/test-helpers';
-import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | kubernetes | roles', function (hooks) {
setupApplicationTest(hooks);
@@ -55,12 +54,6 @@ module('Acceptance | kubernetes | roles', function (hooks) {
});
test('it should have functional list item menu', async function (assert) {
- // Popup menu causes flakiness
- setRunOptions({
- rules: {
- 'color-contrast': { enabled: false },
- },
- });
assert.expect(3);
await this.visitRoles();
for (const action of ['details', 'edit', 'delete']) {
diff --git a/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js b/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js
index fbac5363c0..d8bd65b009 100644
--- a/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js
+++ b/ui/tests/acceptance/secrets/backend/ldap/libraries-test.js
@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
import { click } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap';
-import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | ldap | libraries', function (hooks) {
setupApplicationTest(hooks);
@@ -38,12 +37,6 @@ module('Acceptance | ldap | libraries', function (hooks) {
});
test('it should transition to routes from list item action menu', async function (assert) {
- // Popup menu causes flakiness
- setRunOptions({
- rules: {
- 'color-contrast': { enabled: false },
- },
- });
assert.expect(2);
for (const action of ['edit', 'details']) {
diff --git a/ui/tests/acceptance/secrets/backend/ldap/roles-test.js b/ui/tests/acceptance/secrets/backend/ldap/roles-test.js
index 43ae2262df..5c0551e36d 100644
--- a/ui/tests/acceptance/secrets/backend/ldap/roles-test.js
+++ b/ui/tests/acceptance/secrets/backend/ldap/roles-test.js
@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
import { click, fillIn } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap';
-import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | ldap | roles', function (hooks) {
setupApplicationTest(hooks);
@@ -45,12 +44,6 @@ module('Acceptance | ldap | roles', function (hooks) {
});
test('it should transition to routes from list item action menu', async function (assert) {
- // Popup menu causes flakiness
- setRunOptions({
- rules: {
- 'color-contrast': { enabled: false },
- },
- });
assert.expect(3);
for (const action of ['edit', 'get-creds', 'details']) {
diff --git a/ui/tests/integration/components/kubernetes/page/roles-test.js b/ui/tests/integration/components/kubernetes/page/roles-test.js
index a1ce17a813..67e9a4b4ca 100644
--- a/ui/tests/integration/components/kubernetes/page/roles-test.js
+++ b/ui/tests/integration/components/kubernetes/page/roles-test.js
@@ -9,6 +9,7 @@ import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { render, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
+import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
setupRenderingTest(hooks);
@@ -17,6 +18,7 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
hooks.beforeEach(function () {
this.store = this.owner.lookup('service:store');
+ this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub(['read', 'update', 'delete']));
this.store.pushPayload('secret-engine', {
modelName: 'secret-engine',
data: {
@@ -88,11 +90,6 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
});
test('it should render roles list', async function (assert) {
- this.server.post('/sys/capabilities-self', () => ({
- data: {
- 'kubernetes/role': ['root'],
- },
- }));
await this.renderComponent();
assert.dom('[data-test-list-item-content] svg').hasClass('flight-icon-user', 'List item icon renders');
assert