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