UI: upgrade HDS to 4.12.0 (#28525)

* update hds to latest version

* yield dropdown Interactive text instead of use @text arg, results after running codemod

* remaining dropdown changes

* address sidebar nav IconButton deprecation, fix secret tests

* revert

* explicitly select popupmenu

* more test changes

* fix pki toggle button

* remove tracked prop in oidc client controller

* aaand more test updates

* change to tilde

* tilde yarn lock changes

* small cleanup items
This commit is contained in:
claire bontempo
2024-10-04 13:07:48 -07:00
committed by GitHub
parent bae00721d2
commit 05f32b69ee
67 changed files with 282 additions and 419 deletions

View File

@@ -18,9 +18,11 @@
/>
</:logo>
<:actions>
<Hds::SideNav::Header::IconButton
<Hds::Button
@isIconOnly={{true}}
@size="large"
@icon="terminal-screen"
@ariaLabel="Console toggle"
@text="Console toggle"
data-test-console-toggle
{{on "click" (fn (mut this.console.isOpen) (not this.console.isOpen))}}
/>

View File

@@ -12,7 +12,7 @@
as |Dropdown|
>
<Dropdown.Trigger data-test-user-menu-trigger>
<Hds::SideNav::Header::IconButton @icon="user" @ariaLabel="User menu" />
<Hds::Button @isIconOnly={{true}} @size="large" @icon="user" @text="User menu" />
</Dropdown.Trigger>
<Dropdown.Content>
<div class="popup-menu-content" data-test-user-menu-content>

View File

@@ -5,22 +5,7 @@
import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OidcClientController extends Controller {
@service router;
@tracked isEditRoute;
constructor() {
super(...arguments);
this.router.on(
'routeDidChange',
({ targetName }) => (this.isEditRoute = targetName.includes('edit') ? true : false)
);
}
get showHeader() {
// hide header when rendering the edit form
return !this.isEditRoute;
}
}

View File

@@ -5,21 +5,7 @@
import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OidcKeyController extends Controller {
@service router;
@tracked isEditRoute;
constructor() {
super(...arguments);
this.router.on('routeDidChange', ({ targetName }) => {
return (this.isEditRoute = targetName.includes('edit') ? true : false);
});
}
get showHeader() {
// hide header when rendering the edit form
return !this.isEditRoute;
}
}

View File

@@ -5,21 +5,7 @@
import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OidcProviderController extends Controller {
@service router;
@tracked isEditRoute;
constructor() {
super(...arguments);
this.router.on('routeDidChange', ({ targetName }) => {
return (this.isEditRoute = targetName.includes('edit') ? true : false);
});
}
get showHeader() {
// hide header when rendering the edit form
return !this.isEditRoute;
}
}

View File

@@ -55,7 +55,8 @@
&:hover {
background-color: $ui-gray-050;
}
div {
div,
span {
margin-left: -$spacing-4;
font-size: $size-7;
font-weight: $font-weight-semibold;

View File

@@ -195,8 +195,3 @@ label {
cursor: not-allowed;
}
}
// TODO remove when HDS has released fix
.hds-form-masked-input .hds-form-masked-input__toggle-button {
margin-right: $spacing-12;
}

View File

@@ -79,20 +79,17 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="View {{singularize @itemType}}"
@route="vault.cluster.access.method.item.show"
@models={{array @methodModel.id @itemType list.item.id}}
/>
>View {{singularize @itemType}}</dd.Interactive>
<dd.Interactive
@text="Edit {{singularize @itemType}}"
@route="vault.cluster.access.method.item.edit"
@models={{array @methodModel.id @itemType list.item.id}}
/>
<dd.Interactive
@text="Delete {{singularize @itemType}}"
@color="critical"
{{on "click" (fn (mut this.itemToDelete) list.item)}}
/>
>Edit {{singularize @itemType}}</dd.Interactive>
<dd.Interactive @color="critical" {{on "click" (fn (mut this.itemToDelete) list.item)}}>
Delete
{{singularize @itemType}}
</dd.Interactive>
</Hds::Dropdown>
</Item.menu>
{{#if (eq list.item this.itemToDelete)}}

View File

@@ -12,10 +12,9 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.identity.aliases.show"
@models={{array (pluralize @item.parentType) @item.id "details"}}
/>
>Details</dd.Interactive>
{{#if @item.updatePath.isPending}}
<dd.Generic class="has-text-center">
<LoadingDropdownOption />
@@ -23,18 +22,16 @@
{{else}}
{{#if @item.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.identity.aliases.edit"
@models={{array (pluralize @item.parentType) @item.id}}
/>
>Edit</dd.Interactive>
{{/if}}
{{#if @item.canDelete}}
<dd.Interactive
@text="Remove"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
data-test-popup-menu="delete"
/>
>Remove</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -11,7 +11,7 @@
@hasChevron={{false}}
data-test-popup-menu-trigger
/>
<dd.Interactive @text="Remove" @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}} />
<dd.Interactive @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}}>Remove</dd.Interactive>
</Hds::Dropdown>
</div>

View File

@@ -6,7 +6,7 @@
<div class="has-text-right">
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon @icon="more-horizontal" @text="Metadata options" @hasChevron={{false}} data-test-popup-menu-trigger />
<dd.Interactive @text="Remove" @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}} />
<dd.Interactive @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}}>Remove</dd.Interactive>
</Hds::Dropdown>
</div>

View File

@@ -11,13 +11,12 @@
@hasChevron={{false}}
data-test-popup-menu-trigger
/>
<dd.Interactive @text="View policy" @route="vault.cluster.policy.show" @models={{array "acl" @policyName}} />
<dd.Interactive @text="Edit policy" @route="vault.cluster.policy.edit" @models={{array "acl" @policyName}} />
<dd.Interactive
@text="Remove from {{@model.identityType}}"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
/>
<dd.Interactive @route="vault.cluster.policy.show" @models={{array "acl" @policyName}}>View policy</dd.Interactive>
<dd.Interactive @route="vault.cluster.policy.edit" @models={{array "acl" @policyName}}>Edit policy</dd.Interactive>
<dd.Interactive @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}}>
Remove from
{{@model.identityType}}
</dd.Interactive>
</Hds::Dropdown>
</div>

View File

@@ -27,17 +27,15 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.mfa.enforcements.enforcement"
@model={{@model.name}}
data-test-list-item-link="details"
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.mfa.enforcements.enforcement.edit"
@model={{@model.name}}
data-test-list-item-link="edit"
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -38,17 +38,15 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.mfa.methods.method"
@model={{@model.id}}
data-test-mfa-method-menu-link="details"
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.mfa.methods.method.edit"
@model={{@model.id}}
data-test-mfa-method-menu-link="edit"
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -34,19 +34,17 @@
/>
{{#if client.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.access.oidc.clients.client.details"
@model={{client.name}}
data-test-oidc-client-menu-link="details"
/>
>Details</dd.Interactive>
{{/if}}
{{#if client.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.oidc.clients.client.edit"
@model={{client.name}}
data-test-oidc-client-menu-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -34,19 +34,17 @@
/>
{{#if provider.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.access.oidc.providers.provider.details"
@model={{provider.name}}
data-test-oidc-provider-menu-link="details"
/>
>Details</dd.Interactive>
{{/if}}
{{#if provider.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.oidc.providers.provider.edit"
@model={{provider.name}}
data-test-oidc-provider-menu-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -12,13 +12,12 @@
<dd.Interactive
@href="/v1/sys/storage/raft/snapshot"
@isHrefExternal={{false}}
@text="Download"
{{on "click" (action "downloadViaServiceWorker")}}
/>
>Download</dd.Interactive>
{{else}}
<dd.Interactive @text="Download" {{on "click" (action "downloadSnapshot")}} />
<dd.Interactive {{on "click" (action "downloadSnapshot")}}>Download</dd.Interactive>
{{/if}}
<dd.Interactive @text="Restore" @route="vault.cluster.storage-restore" />
<dd.Interactive @route="vault.cluster.storage-restore">Restore</dd.Interactive>
</Hds::Dropdown>
</PH.Actions>
</Hds::PageHeader>

View File

@@ -36,11 +36,10 @@
</dd.Generic>
{{else if @item.canGenerate}}
<dd.Interactive
@text="Generate credentials"
@route="vault.cluster.secrets.backend.credentials"
@model={{@item.id}}
data-test-role-aws-link="generate"
/>
>Generate credentials</dd.Interactive>
{{/if}}
{{#if @item.updatePath.isPending}}
<dd.Generic class="has-text-center">
@@ -49,27 +48,24 @@
{{else}}
{{#if @item.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.secrets.backend.show"
@model={{@item.id}}
data-test-role-ssh-link="show"
/>
>Details</dd.Interactive>
{{/if}}
{{#if @item.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.secrets.backend.edit"
@model={{@item.id}}
data-test-role-ssh-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
{{#if @item.canDelete}}
<dd.Interactive
@text="Delete"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
data-test-aws-role-delete={{@item.id}}
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -34,46 +34,41 @@
data-test-popup-menu-trigger
/>
{{#if @item.canEdit}}
<dd.Interactive @text="Edit connection" @route="vault.cluster.secrets.backend.edit" @model={{@item.id}} />
<dd.Interactive @route="vault.cluster.secrets.backend.edit" @model={{@item.id}}>Edit connection</dd.Interactive>
{{/if}}
{{#if @item.canEditRole}}
<dd.Interactive @text="Edit Role" @route="vault.cluster.secrets.backend.edit" @model={{concat "role/" @item.id}} />
<dd.Interactive @route="vault.cluster.secrets.backend.edit" @model={{concat "role/" @item.id}}>Edit Role</dd.Interactive>
{{/if}}
{{#if @item.canReset}}
<dd.Interactive
@text="Reset connection"
@icon={{if (eq this.actionRunning "reset") "loading"}}
{{on "click" (fn this.resetConnection @item.id)}}
/>
>Reset connection</dd.Interactive>
{{/if}}
{{#if (and (eq @item.type "dynamic") @item.canGenerateCredentials)}}
<dd.Interactive
@text="Generate credentials"
@route="vault.cluster.secrets.backend.credentials"
@model={{@item.id}}
@query={{hash roleType=this.keyTypeValue}}
/>
>Generate credentials</dd.Interactive>
{{else if (and (eq @item.type "static") @item.canGetCredentials)}}
<dd.Interactive
@text="Get credentials"
@route="vault.cluster.secrets.backend.credentials"
@model={{@item.id}}
@query={{hash roleType=this.keyTypeValue}}
/>
>Get credentials</dd.Interactive>
{{/if}}
{{#if (and @item.canRotateRoleCredentials (eq this.keyTypeValue "static"))}}
<dd.Interactive
@text="Rotate credentials"
@icon={{if (eq this.actionRunning "rotateRole") "loading"}}
{{on "click" (fn this.rotateRoleCred @item.id)}}
/>
>Rotate credentials</dd.Interactive>
{{/if}}
{{#if @item.canRotateRoot}}
<dd.Interactive
@text="Rotate root credentials"
@icon={{if (eq this.actionRunning "rotateRoot") "loading"}}
{{on "click" (fn this.rotateRootCred @item.id)}}
/>
>Rotate root credentials</dd.Interactive>
{{/if}}
</Hds::Dropdown>
</div>

View File

@@ -21,6 +21,7 @@
@backend={{@backendModel.id}}
@queryParams={{secret-query-params @backendModel.type @item.type asQueryParams=true}}
class="has-text-black has-text-weight-semibold"
data-test-secret-item-link={{@item.id}}
>
{{#if (eq @backendModel.type "transit")}}
<Icon @name="key" class="has-text-grey-light" />
@@ -39,7 +40,7 @@
data-test-popup-menu-trigger
/>
{{#if @item.isFolder}}
<dd.Interactive @text="Contents" @route="vault.cluster.secrets.backend.list" @model={{@item.id}} />
<dd.Interactive @route="vault.cluster.secrets.backend.list" @model={{@item.id}}>Contents</dd.Interactive>
{{else}}
{{#if (or @item.versionPath.isLoading @item.secretPath.isLoading)}}
<dd.Generic class="has-text-center">
@@ -48,27 +49,24 @@
{{else}}
{{#if @item.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.secrets.backend.show"
@model={{@item.id}}
@query={{secret-query-params @backendModel.type @item.type asQueryParams=true}}
/>
>Details</dd.Interactive>
{{/if}}
{{#if @item.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.secrets.backend.edit"
@model={{@item.id}}
@query={{secret-query-params @backendModel.type @item.type asQueryParams=true}}
/>
>Edit</dd.Interactive>
{{/if}}
{{#if @item.canDelete}}
<dd.Interactive
@text="Delete"
@color="critical"
data-test-confirm-action-trigger
{{on "click" (fn (mut this.showConfirmModal) true)}}
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
{{/if}}

View File

@@ -50,11 +50,10 @@
</dd.Generic>
{{else if @item.canGenerate}}
<dd.Interactive
@text="Generate credentials"
@route="vault.cluster.secrets.backend.credentials"
@model={{@item.id}}
data-test-role-ssh-link="generate"
/>
>Generate credentials</dd.Interactive>
{{/if}}
{{else if (eq @item.keyType "ca")}}
{{#if @item.signPath.isPending}}
@@ -63,11 +62,10 @@
</dd.Generic>
{{else if @item.canGenerate}}
<dd.Interactive
@text="Sign Keys"
@route="vault.cluster.secrets.backend.sign"
@model={{@item.id}}
data-test-role-ssh-link="generate"
/>
>Sign Keys</dd.Interactive>
{{/if}}
{{/if}}
{{#if @loadingToggleZeroAddress}}
@@ -75,10 +73,9 @@
<LoadingDropdownOption />
</dd.Generic>
{{else if @item.canEditZeroAddress}}
<dd.Interactive
@text={{if @item.zeroAddress "Disable Zero Address" "Enable Zero Address"}}
{{on "click" @toggleZeroAddress}}
/>
<dd.Interactive {{on "click" @toggleZeroAddress}}>
{{if @item.zeroAddress "Disable Zero Address" "Enable Zero Address"}}
</dd.Interactive>
{{/if}}
{{#if @item.updatePath.isPending}}
<dd.Generic class="has-text-center">
@@ -87,27 +84,24 @@
{{else}}
{{#if @item.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.secrets.backend.show"
@model={{@item.id}}
data-test-role-ssh-link="show"
/>
>Details</dd.Interactive>
{{/if}}
{{#if @item.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.secrets.backend.edit"
@model={{@item.id}}
data-test-role-ssh-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
{{#if @item.canDelete}}
<dd.Interactive
@text="Delete"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
data-test-ssh-role-delete
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -33,10 +33,10 @@
data-test-popup-menu-trigger
/>
{{#if @item.updatePath.canRead}}
<dd.Interactive @text="Details" @route="vault.cluster.secrets.backend.show" @model={{@itemPath}} />
<dd.Interactive @route="vault.cluster.secrets.backend.show" @model={{@itemPath}}>Details</dd.Interactive>
{{/if}}
{{#if @item.updatePath.canUpdate}}
<dd.Interactive @text="Edit" @route="vault.cluster.secrets.backend.edit" @model={{@itemPath}} />
<dd.Interactive @route="vault.cluster.secrets.backend.edit" @model={{@itemPath}}>Edit</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -33,10 +33,10 @@
data-test-popup-menu-trigger
/>
{{#if @item.updatePath.canRead}}
<dd.Interactive @text="Details" @route="vault.cluster.secrets.backend.show" @model={{@item.id}} />
<dd.Interactive @route="vault.cluster.secrets.backend.show" @model={{@item.id}}>Details</dd.Interactive>
{{/if}}
{{#if @item.updatePath.canUpdate}}
<dd.Interactive @text="Edit" @route="vault.cluster.secrets.backend.edit" @model={{@item.id}} />
<dd.Interactive @route="vault.cluster.secrets.backend.edit" @model={{@item.id}}>Edit</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -15,7 +15,7 @@
<Hds::SideNav::Header::HomeLink @icon="vault" @route="vault" @ariaLabel="Vault dashboard" />
</:logo>
<:actions>
<Hds::SideNav::Header::IconButton @icon="home" @ariaLabel="Docs index" @route="docs" />
<Hds::Button @isIconOnly={{true}} @icon="home" @text="Docs index" @route="docs" />
</:actions>
</Hds::SideNav::Header>
</:header>

View File

@@ -41,10 +41,9 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.identity.show"
@models={{array item.id "details"}}
/>
>Details</dd.Interactive>
{{#if (or item.isReloading item.updatePath.isPending item.aliasPath.isPending)}}
<dd.Generic class="has-text-center">
<LoadingDropdownOption />
@@ -55,27 +54,28 @@
{{#if (or (eq this.identityType "entity") (and (eq item.type "external") (not item.alias)))}}
<dd.Interactive
data-test-popup-menu="create alias"
@text="Create alias"
@route="vault.cluster.access.identity.aliases.add"
@models={{array (pluralize this.identityType) item.id}}
/>
>Create alias</dd.Interactive>
{{/if}}
{{/if}}
{{#if item.canEdit}}
<dd.Interactive @text="Edit" @route="vault.cluster.access.identity.edit" @model={{item.id}} />
<dd.Interactive @route="vault.cluster.access.identity.edit" @model={{item.id}}>Edit</dd.Interactive>
{{#if item.disabled}}
<dd.Interactive @text="Enable" {{on "click" (action "toggleDisabled" item)}} />
<dd.Interactive {{on "click" (action "toggleDisabled" item)}}>Enable</dd.Interactive>
{{else if (eq this.identityType "entity")}}
<dd.Interactive @text="Disable" @color="critical" {{on "click" (fn (mut this.entityToDisable) item)}} />
<dd.Interactive
@color="critical"
{{on "click" (fn (mut this.entityToDisable) item)}}
>Disable</dd.Interactive>
{{/if}}
{{/if}}
{{#if item.canDelete}}
<dd.Interactive
@text="Delete"
@color="critical"
{{on "click" (fn (mut this.itemToDelete) item)}}
data-test-popup-menu="delete"
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -76,20 +76,19 @@
@hasChevron={{false}}
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="View configuration"
@route="vault.cluster.access.method.section"
@models={{array method.id "configuration"}}
/>
<dd.Interactive @route="vault.cluster.access.method.section" @models={{array method.id "configuration"}}>
View configuration
</dd.Interactive>
{{#if (or method.canEdit (and (eq method.methodType "aws") method.canEditAws))}}
<dd.Interactive
@text="Edit configuration"
@route="vault.cluster.settings.auth.configure"
@model={{method.id}}
/>
<dd.Interactive @route="vault.cluster.settings.auth.configure" @model={{method.id}}>
Edit configuration
</dd.Interactive>
{{/if}}
{{#if (and (not-eq method.methodType "token") method.canDisable)}}
<dd.Interactive @text="Disable" @color="critical" {{on "click" (fn (mut this.methodToDisable) method)}} />
<dd.Interactive
@color="critical"
{{on "click" (fn (mut this.methodToDisable) method)}}
>Disable</dd.Interactive>
{{/if}}
</Hds::Dropdown>
</div>

View File

@@ -93,11 +93,10 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route={{target.link}}
@models={{target.linkModels}}
data-test-target-link={{target.title}}
/>
>Details</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -46,7 +46,7 @@
</dd.Generic>
{{/if}}
{{/let}}
<dd.Interactive @text="Delete" @color="critical" {{on "click" (fn (mut this.nsToDelete) list.item)}} />
<dd.Interactive @color="critical" {{on "click" (fn (mut this.nsToDelete) list.item)}}>Delete</dd.Interactive>
</Hds::Dropdown>
{{#if (eq this.nsToDelete list.item)}}
<ConfirmModal

View File

@@ -46,19 +46,17 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.oidc.assignments.assignment.details"
@model={{model.name}}
@disabled={{eq model.canRead false}}
data-test-oidc-assignment-menu-link="details"
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.oidc.assignments.assignment.edit"
@model={{model.name}}
@disabled={{eq model.canEdit false}}
data-test-oidc-assignment-menu-link="edit"
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
~}}
{{#if this.showHeader}}
{{#if (not-eq this.router.currentRoute.localName "edit")}}
<PageHeader as |p|>
<p.top>
<Hds::Breadcrumb>

View File

@@ -21,7 +21,7 @@
<div class="level-left">
<div>
<Icon @name="key" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline">
<span class="has-text-weight-semibold is-underline" data-test-item>
{{model.name}}
</span>
</div>
@@ -36,19 +36,17 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.oidc.keys.key.details"
@model={{model.name}}
@disabled={{eq model.canRead false}}
data-test-oidc-key-menu-link="details"
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.oidc.keys.key.edit"
@model={{model.name}}
@disabled={{eq model.canEdit false}}
data-test-oidc-key-menu-link="edit"
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
~}}
{{#if this.showHeader}}
{{#if (not-eq this.router.currentRoute.localName "edit")}}
<PageHeader as |p|>
<p.top>
<Hds::Breadcrumb>

View File

@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
~}}
{{#if this.showHeader}}
{{#if (not-eq this.router.currentRoute.localName "edit")}}
<PageHeader as |p|>
<p.top>
<Hds::Breadcrumb>

View File

@@ -37,19 +37,17 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="vault.cluster.access.oidc.scopes.scope.details"
@model={{model.name}}
@disabled={{eq model.canRead false}}
data-test-oidc-scope-menu-link="details"
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="vault.cluster.access.oidc.scopes.scope.edit"
@model={{model.name}}
@disabled={{eq model.canEdit false}}
data-test-oidc-scope-menu-link="edit"
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -105,27 +105,24 @@
{{else}}
{{#if item.canRead}}
<dd.Interactive
@text="Details"
@route="vault.cluster.policy.show"
@models={{array this.policyType item.id}}
data-test-policy-link="show"
/>
>Details</dd.Interactive>
{{/if}}
{{#if item.canEdit}}
<dd.Interactive
@text="Edit"
@route="vault.cluster.policy.edit"
@models={{array this.policyType item.id}}
data-test-policy-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
{{#if (and item.canDelete (not-eq item.name "default"))}}
<dd.Interactive
@text="Delete"
@color="critical"
data-test-confirm-action-trigger
{{on "click" (fn (mut this.policyToDelete) item)}}
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -94,19 +94,15 @@
@hasChevron={{false}}
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="View configuration"
@route={{backend.backendConfigurationLink}}
@model={{backend.id}}
data-test-engine-config
/>
<dd.Interactive @route={{backend.backendConfigurationLink}} @model={{backend.id}} data-test-engine-config>
View configuration
</dd.Interactive>
{{#if (not-eq backend.type "cubbyhole")}}
<dd.Interactive
@text="Disable"
@color="critical"
{{on "click" (fn (mut this.engineToDisable) backend)}}
data-test-confirm-action-trigger
/>
>Disable</dd.Interactive>
{{/if}}
</Hds::Dropdown>
</div>

View File

@@ -113,10 +113,13 @@
data-test-popup-menu-trigger
/>
{{#if message.canEditCustomMessages}}
<dd.Interactive @text="Edit" @route="messages.message.edit" @model={{message.id}} />
<dd.Interactive @route="messages.message.edit" @model={{message.id}}>Edit</dd.Interactive>
{{/if}}
{{#if message.canDeleteCustomMessages}}
<dd.Interactive @text="Delete" @color="critical" {{on "click" (fn (mut this.messageToDelete) message)}} />
<dd.Interactive
@color="critical"
{{on "click" (fn (mut this.messageToDelete) message)}}
>Delete</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -7,13 +7,14 @@
{{! Hds component renders <li> and <button> elements }}
<Hds::Dropdown::ListItem::Interactive
data-test-confirm-action-trigger
@text={{@buttonText}}
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
...attributes
{{! remove class when dropdown/popup menus are replaced with Hds::Dropdown }}
class="hds-confirm-action-critical"
/>
>
{{@buttonText}}
</Hds::Dropdown::ListItem::Interactive>
{{else}}
<Hds::Button
data-test-confirm-action-trigger

View File

@@ -71,22 +71,17 @@
<Item.menu>
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
<dd.Interactive
@text="View credentials"
@route="credentials.show"
@models={{array this.scope this.role list.item.id}}
/>
<dd.Interactive @route="credentials.show" @models={{array this.scope this.role list.item.id}}>View credentials</dd.Interactive>
{{#if list.item.deletePath.isPending}}
<dd.Generic>
<LoadingDropdownOption />
</dd.Generic>
{{else if list.item.deletePath.canDelete}}
<dd.Interactive
@text="Revoke credentials"
@color="critical"
{{on "click" (fn (mut this.credToRevoke) list.item)}}
data-test-confirm-action-trigger
/>
>Revoke credentials</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{#if (eq this.credToRevoke list.item)}}

View File

@@ -71,23 +71,22 @@
<Item.menu>
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
<dd.Interactive @text="View credentials" @route="credentials" @models={{array this.scope list.item.id}} />
<dd.Interactive @text="View role" @route="role" @models={{array this.scope list.item.id}} />
<dd.Interactive @route="credentials" @models={{array this.scope list.item.id}}>View credentials</dd.Interactive>
<dd.Interactive @route="role" @models={{array this.scope list.item.id}}>View role</dd.Interactive>
{{#if list.item.updatePath.isPending}}
<dd.Generic>
<LoadingDropdownOption />
</dd.Generic>
{{else}}
{{#if list.item.updatePath.canUpdate}}
<dd.Interactive @text="Edit role" @route="role.edit" @models={{array this.scope list.item.id}} />
<dd.Interactive @route="role.edit" @models={{array this.scope list.item.id}}>Edit role</dd.Interactive>
{{/if}}
{{#if list.item.updatePath.canDelete}}
<dd.Interactive
@text="Delete role"
@color="critical"
{{on "click" (fn (mut this.roleToDelete) list.item)}}
data-test-confirm-action-trigger
/>
>Delete role</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -60,18 +60,17 @@
<Item.menu>
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
<dd.Interactive @text="View scope" @route="scope" @model={{list.item.id}} />
<dd.Interactive @route="scope" @model={{list.item.id}}>View scope</dd.Interactive>
{{#if list.item.updatePath.isPending}}
<dd.Generic>
<LoadingDropdownOption />
</dd.Generic>
{{else if list.item.updatePath.canDelete}}
<dd.Interactive
@text="Delete scope"
@color="critical"
{{on "click" (fn (mut this.scopeToDelete) list.item)}}
data-test-confirm-action-trigger
/>
>Delete scope</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{#if (eq this.scopeToDelete list.item)}}

View File

@@ -49,18 +49,17 @@
data-test-popup-menu-trigger
/>
{{#if role.canRead}}
<dd.Interactive @text="Details" @route="roles.role.details" @model={{role}} data-test-details />
<dd.Interactive @route="roles.role.details" @model={{role}} data-test-details>Details</dd.Interactive>
{{/if}}
{{#if role.canEdit}}
<dd.Interactive @text="Edit" data-test-edit @route="roles.role.edit" @model={{role}} />
<dd.Interactive data-test-edit @route="roles.role.edit" @model={{role}}>Edit</dd.Interactive>
{{/if}}
{{#if role.canDelete}}
<dd.Interactive
@text="Delete"
data-test-delete
@color="critical"
{{on "click" (fn (mut this.roleToDelete) role)}}
/>
>Delete</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -84,7 +84,7 @@
<div class="level-left">
<div>
<Icon @name={{if metadata.pathIsDirectory "folder" "file"}} class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline">
<span class="has-text-weight-semibold is-underline" data-test-path>
{{metadata.path}}
</span>
</div>
@@ -100,35 +100,25 @@
/>
{{#if metadata.pathIsDirectory}}
<dd.Interactive
@text="Content"
@route="list-directory"
@models={{array @backend metadata.fullSecretPath}}
/>
>Content</dd.Interactive>
{{else}}
<dd.Interactive
@text="Overview"
@route="secret.index"
@models={{array @backend metadata.fullSecretPath}}
/>
<dd.Interactive
@text="Secret data"
@route="secret.details"
@models={{array @backend metadata.fullSecretPath}}
/>
>Overview</dd.Interactive>
<dd.Interactive @route="secret.details" @models={{array @backend metadata.fullSecretPath}}>Secret data</dd.Interactive>
{{#if metadata.canReadMetadata}}
<dd.Interactive
@text="View version history"
@route="secret.metadata.versions"
@models={{array @backend metadata.fullSecretPath}}
/>
<dd.Interactive @route="secret.metadata.versions" @models={{array @backend metadata.fullSecretPath}}>
View version history</dd.Interactive>
{{/if}}
{{#if metadata.canDeleteMetadata}}
<dd.Interactive
@text="Permanently delete"
@color="critical"
{{on "click" (fn (mut this.metadataToDelete) metadata)}}
data-test-popup-metadata-delete
/>
>Permanently delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -98,19 +98,17 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="View version {{versionData.version}}"
@route="secret.details"
@models={{array @backend @path}}
@query={{hash version=versionData.version}}
/>
>View version {{versionData.version}}</dd.Interactive>
{{#if (and @metadata.canCreateVersionData (not versionData.destroyed) (not versionData.isSecretDeleted))}}
<dd.Interactive
@text="Create new version from {{versionData.version}}"
@route="secret.details.edit"
@models={{array @backend @path}}
@query={{hash version=versionData.version}}
data-test-create-new-version-from={{versionData.version}}
/>
>Create new version from {{versionData.version}}</dd.Interactive>
{{/if}}
</Hds::Dropdown>
</div>

View File

@@ -58,18 +58,21 @@
data-test-popup-menu-trigger
/>
{{#if library.canEdit}}
<dd.Interactive @text="Edit" data-test-edit @route="libraries.library.edit" @model={{library}} />
<dd.Interactive data-test-edit @route="libraries.library.edit" @model={{library}}>Edit</dd.Interactive>
{{/if}}
{{#if library.canRead}}
<dd.Interactive @text="Details" data-test-details @route="libraries.library.details" @model={{library}} />
<dd.Interactive
data-test-details
@route="libraries.library.details"
@model={{library}}
>Details</dd.Interactive>
{{/if}}
{{#if library.canDelete}}
<dd.Interactive
@text="Delete"
data-test-delete
@color="critical"
{{on "click" (fn (mut this.libraryToDelete) library)}}
/>
>Delete</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -53,38 +53,36 @@
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
{{#if role.canEdit}}
<dd.Interactive @text="Edit" data-test-edit @route="roles.role.edit" @models={{array role.type role.name}} />
<dd.Interactive
data-test-edit
@route="roles.role.edit"
@models={{array role.type role.name}}
>Edit</dd.Interactive>
{{/if}}
{{#if role.canReadCreds}}
<dd.Interactive
@text="Get credentials"
data-test-get-creds
@route="roles.role.credentials"
@models={{array role.type role.name}}
/>
<dd.Interactive data-test-get-creds @route="roles.role.credentials" @models={{array role.type role.name}}>
Get credentials
</dd.Interactive>
{{/if}}
{{#if role.canRotateStaticCreds}}
<dd.Interactive
@text="Rotate credentials"
data-test-rotate-creds
@color="critical"
{{on "click" (fn (mut this.credsToRotate) role)}}
/>
>Rotate credentials</dd.Interactive>
{{/if}}
<dd.Interactive
@text="Details"
data-test-details
@route="roles.role.details"
{{! this will force the roles.role model hook to fire since we may only have a partial model loaded in the list view }}
@models={{array role.type role.name}}
/>
>Details</dd.Interactive>
{{#if role.canDelete}}
<dd.Interactive
@text="Delete"
data-test-delete
@color="critical"
{{on "click" (fn (mut this.roleToDelete) role)}}
/>
>Delete</dd.Interactive>
{{/if}}
</Hds::Dropdown>
</Item.menu>

View File

@@ -108,12 +108,11 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="issuers.issuer.details"
@models={{array @backend pkiIssuer.id}}
data-test-pki-issuer-details
/>
<dd.Interactive @text="Edit" @route="issuers.issuer.edit" @models={{array @backend pkiIssuer.id}} />
>Details</dd.Interactive>
<dd.Interactive @route="issuers.issuer.edit" @models={{array @backend pkiIssuer.id}}>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -54,19 +54,17 @@
/>
{{#if @canRead}}
<dd.Interactive
@text="Details"
@route="keys.key.details"
@models={{array @backend pkiKey.keyId}}
data-test-key-menu-link="details"
/>
>Details</dd.Interactive>
{{/if}}
{{#if @canEdit}}
<dd.Interactive
@text="Edit"
@route="keys.key.edit"
@models={{array @backend pkiKey.keyId}}
data-test-key-menu-link="edit"
/>
>Edit</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -38,7 +38,10 @@
@hasChevron={{false}}
data-test-popup-menu-trigger
/>
<dd.Interactive @text="Details" @route="certificates.certificate.details" @model={{pkiCertificate.id}} />
<dd.Interactive
@route="certificates.certificate.details"
@model={{pkiCertificate.id}}
>Details</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -44,15 +44,13 @@
data-test-popup-menu-trigger
/>
<dd.Interactive
@text="Details"
@route="roles.role.details"
@models={{array this.model.parentModel.id pkiRole.id}}
/>
>Details</dd.Interactive>
<dd.Interactive
@text="Edit"
@route="roles.role.edit"
@models={{array this.model.parentModel.id pkiRole.id}}
/>
>Edit</dd.Interactive>
</Hds::Dropdown>
</div>
</div>

View File

@@ -38,18 +38,16 @@
/>
{{#if (eq this.replicationMode "performance")}}
<dd.Interactive
@text="Path filter config"
@route="mode.secondaries.config-show"
@models={{array this.replicationMode secondary}}
data-test-replication-path-filter-link={{true}}
/>
>Path filter config</dd.Interactive>
{{/if}}
{{#if this.model.canRevokeSecondary}}
<dd.Interactive
@text="Revoke"
@color="critical"
{{on "click" (fn (mut this.secondaryToRevoke) secondary)}}
/>
>Revoke</dd.Interactive>
{{/if}}
</Hds::Dropdown>
{{/if}}

View File

@@ -83,27 +83,24 @@
</dd.Generic>
{{else}}
<dd.Interactive
@text="Details"
data-test-details
@route="secrets.destinations.destination.details"
@models={{array destination.type destination.name}}
@disabled={{not destination.canRead}}
/>
>Details</dd.Interactive>
{{#if destination.canEdit}}
<dd.Interactive
@text="Edit"
data-test-edit
@route="secrets.destinations.destination.edit"
@models={{array destination.type destination.name}}
/>
>Edit</dd.Interactive>
{{/if}}
{{#if destination.canDelete}}
<dd.Interactive
data-test-delete
@text="Delete"
@color="critical"
{{on "click" (fn (mut this.destinationToDelete) destination)}}
/>
>Delete</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -53,26 +53,21 @@
<dd.Separator />
{{/if}}
{{#if association.canSync}}
<dd.Interactive
@text="Sync now"
data-test-association-action="sync"
{{on "click" (fn this.update association "set")}}
/>
<dd.Interactive data-test-association-action="sync" {{on "click" (fn this.update association "set")}}>
Sync now</dd.Interactive>
{{/if}}
<dd.Interactive
@text="View secret"
data-test-association-action="view"
@route="kvSecretOverview"
@isRouteExternal={{true}}
@models={{array association.mount association.secretName}}
/>
>View secret</dd.Interactive>
{{#if association.canUnsync}}
<dd.Interactive
data-test-association-action="unsync"
@color="critical"
@text="Unsync"
{{on "click" (fn (mut this.secretToUnsync) association)}}
/>
>Unsync</dd.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>

View File

@@ -142,15 +142,13 @@
<dd.Interactive
@route="secrets.destinations.destination.sync"
@models={{array data.type data.name}}
@text="Sync secrets"
data-test-overview-table-action="sync"
/>
>Sync secrets</dd.Interactive>
<dd.Interactive
@route="secrets.destinations.destination.secrets"
@models={{array data.type data.name}}
@text="View synced secrets"
data-test-overview-table-action="details"
/>
>View synced secrets</dd.Interactive>
</Hds::Dropdown>
</B.Td>
</B.Tr>

View File

@@ -234,7 +234,7 @@
},
"dependencies": {
"@babel/core": "^7.24.0",
"@hashicorp/design-system-components": "~4.7.0",
"@hashicorp/design-system-components": "~4.12.0",
"@hashicorp/ember-flight-icons": "^5.1.3",
"ember-auto-import": "^2.7.2",
"handlebars": "4.7.7",

View File

@@ -13,7 +13,7 @@ import { GENERAL } from 'vault/tests/helpers/general-selectors';
const SELECTORS = {
identityRow: (name) => `[data-test-identity-row="${name}"]`,
popupMenu: '[data-test-popup-menu-trigger]',
menuDelete: '[data-test-popup-menu="delete"]',
menuDelete: (name) => `[data-test-identity-row="${name}"] [data-test-popup-menu="delete"]`,
};
export const testCRUD = async (name, itemType, assert) => {
await page.visit({ item_type: itemType });
@@ -36,8 +36,8 @@ export const testCRUD = async (name, itemType, assert) => {
);
await click(`${SELECTORS.identityRow(name)} ${SELECTORS.popupMenu}`);
await waitUntil(() => find(SELECTORS.menuDelete));
await click(SELECTORS.menuDelete);
await waitUntil(() => find(SELECTORS.menuDelete(name)));
await click(SELECTORS.menuDelete(name));
await indexPage.confirmDelete();
await settled();
assert.dom(GENERAL.latestFlashContent).includesText('Successfully deleted');
@@ -57,7 +57,7 @@ export const testDeleteFromForm = async (name, itemType, assert) => {
await click('[data-test-tab-subnav="policies"]');
assert.dom('.list-item-row').exists({ count: 1 }, 'One item is under policies');
await click('[data-test-tab-subnav="metadata"]');
assert.dom('.info-table-row').hasText('hello goodbye', 'Metadata shows on tab');
assert.dom('.info-table-row').hasTextContaining('hello goodbye', 'Metadata shows on tab');
await showPage.edit();
assert.strictEqual(
currentRouteName(),

View File

@@ -95,7 +95,7 @@ module('Acceptance | auth backend list', function (hooks) {
const itemCount = type === 'token' ? 2 : 3;
await click(`[data-test-auth-backend-link="${path}"] [data-test-popup-menu-trigger]`);
assert
.dom('.hds-dropdown-list-item')
.dom(`[data-test-auth-backend-link="${path}"] .hds-dropdown-list-item`)
.exists({ count: itemCount }, `shows ${itemCount} dropdown items for ${type}`);
// all auth methods should be linkable

View File

@@ -214,10 +214,12 @@ module('Acceptance | mfa-method', function (hooks) {
'Route transitions to method on save'
);
await click('[data-test-tab="enforcements"]');
assert.dom('[data-test-list-item]').hasText('bar', 'Enforcement is listed in method view');
assert.dom('[data-test-list-item]').hasTextContaining('bar', 'Enforcement is listed in method view');
await click('[data-test-sidebar-nav-link="Multi-Factor Authentication"]');
await click('[data-test-tab="enforcements"]');
assert.dom('[data-test-list-item="bar"]').hasText('bar', 'Enforcement is listed in enforcements view');
assert
.dom('[data-test-list-item="bar"]')
.hasTextContaining('bar', 'Enforcement is listed in enforcements view');
await click('[data-test-list-item="bar"]');
await click('[data-test-tab="methods"]');
assert
@@ -242,7 +244,7 @@ module('Acceptance | mfa-method', function (hooks) {
'Route transitions to method on save'
);
await click('[data-test-tab="enforcements"]');
assert.dom('[data-test-list-item]').hasText(name, 'Enforcement is listed in method view');
assert.dom('[data-test-list-item]').hasTextContaining(name, 'Enforcement is listed in method view');
});
test('it should edit methods', async function (assert) {

View File

@@ -72,7 +72,7 @@ module('Acceptance | oidc-config clients', function (hooks) {
assert.dom('[data-test-tab="keys"]').hasClass('active', 'keys tab is active');
assert.strictEqual(currentRouteName(), 'vault.cluster.access.oidc.keys.index');
assert
.dom('[data-test-oidc-key-linked-block="default"]')
.dom('[data-test-oidc-key-linked-block="default"] [data-test-item]')
.hasText('default', 'index page lists default key');
// navigate to default key details from pop-up menu
@@ -132,7 +132,7 @@ module('Acceptance | oidc-config clients', function (hooks) {
// edit key and limit applications
await visit(OIDC_BASE_URL + '/keys');
await click('[data-test-oidc-key-linked-block="test-key"] [data-test-popup-menu-trigger]');
await click('[data-test-oidc-key-menu-link="edit"]');
await click('[data-test-oidc-key-linked-block="test-key"] [data-test-oidc-key-menu-link="edit"]');
assert.strictEqual(
currentRouteName(),
'vault.cluster.access.oidc.keys.key.edit',

View File

@@ -64,10 +64,11 @@ module('Acceptance | raft storage', function (hooks) {
return {};
});
const row = '[data-raft-row]:nth-child(2) [data-test-raft-actions]';
await visit('/vault/storage/raft');
assert.dom('[data-raft-row]').exists({ count: 2 }, '2 raft peers render in table');
await click('[data-raft-row]:nth-child(2) [data-test-raft-actions] button');
await click('[data-test-confirm-action-trigger]');
await click(`${row} button`);
await click(`${row} [data-test-confirm-action-trigger]`);
await click('[data-test-confirm-button]');
assert.dom('[data-raft-row]').exists({ count: 1 }, 'Raft peer successfully removed');
});

View File

@@ -3,69 +3,55 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import { currentRouteName, settled } from '@ember/test-helpers';
import { click, find, findAll, currentRouteName, visit } from '@ember/test-helpers';
import { clickTrigger } from 'ember-power-select/test-support/helpers';
import { create } from 'ember-cli-page-object';
import { module, test } from 'qunit';
import consoleClass from 'vault/tests/pages/components/console/ui-panel';
import { setupApplicationTest } from 'ember-qunit';
import { v4 as uuidv4 } from 'uuid';
import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend';
import backendsPage from 'vault/tests/pages/secrets/backends';
import authPage from 'vault/tests/pages/auth';
import ss from 'vault/tests/pages/components/search-select';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands';
import { login } from 'vault/tests/helpers/auth/auth-helpers';
const consoleComponent = create(consoleClass);
const searchSelect = create(ss);
const SELECTORS = {
backendLink: (path) =>
path ? `[data-test-secrets-backend-link="${path}"]` : '[data-test-secrets-backend-link]',
};
module('Acceptance | secret-engine list view', function (hooks) {
setupApplicationTest(hooks);
hooks.beforeEach(function () {
this.uid = uuidv4();
return authPage.login();
return login();
});
test('it allows you to disable an engine', async function (assert) {
// first mount an engine so we can disable it.
const enginePath = `alicloud-disable-${this.uid}`;
await mountSecrets.enable('alicloud', enginePath);
await settled();
assert.ok(backendsPage.rows.filterBy('path', `${enginePath}/`)[0], 'shows the mounted engine');
await backendsPage.visit();
await settled();
const row = backendsPage.rows.filterBy('path', `${enginePath}/`)[0];
await row.menu();
await settled();
await backendsPage.disableButton();
await settled();
await backendsPage.confirmDisable();
await settled();
await runCmd(mountEngineCmd('alicloud', enginePath));
await visit('/vault/secrets');
assert.dom(SELECTORS.backendLink(enginePath)).exists();
const row = SELECTORS.backendLink(enginePath);
await click(`${row} ${GENERAL.menuTrigger}`);
await click(`${row} ${GENERAL.confirmTrigger}`);
await click(GENERAL.confirmButton);
assert.strictEqual(
currentRouteName(),
'vault.cluster.secrets.backends',
'redirects to the backends page'
);
assert.strictEqual(
backendsPage.rows.filterBy('path', `${enginePath}/`).length,
0,
'does not show the disabled engine'
);
assert.dom(SELECTORS.backendLink(enginePath)).doesNotExist('does not show the disabled engine');
});
test('it adds disabled css styling to unsupported secret engines', async function (assert) {
assert.expect(2);
// first mount engine that is not supported
const enginePath = `nomad-${this.uid}`;
await runCmd(mountEngineCmd('nomad', enginePath));
await visit('/vault/secrets');
await mountSecrets.enable('nomad', enginePath);
await settled();
await backendsPage.visit();
await settled();
const rows = document.querySelectorAll('[data-test-secrets-backend-link]');
const rows = findAll(SELECTORS.backendLink());
const rowUnsupported = Array.from(rows).filter((row) => row.innerText.includes('nomad'));
const rowSupported = Array.from(rows).filter((row) => row.innerText.includes('cubbyhole'));
assert
@@ -77,7 +63,7 @@ module('Acceptance | secret-engine list view', function (hooks) {
assert.dom(rowSupported[0]).hasClass('linked-block', `linked-block class is added to supported engines.`);
// cleanup
await consoleComponent.runCommands([`delete sys/mounts/${enginePath}`]);
await runCmd(deleteEngineCmd(enginePath));
});
test('it filters by name and engine type', async function (assert) {
@@ -85,32 +71,31 @@ module('Acceptance | secret-engine list view', function (hooks) {
const enginePath1 = `aws-1-${this.uid}`;
const enginePath2 = `aws-2-${this.uid}`;
await mountSecrets.enable('aws', enginePath1);
await mountSecrets.enable('aws', enginePath2);
await backendsPage.visit();
await settled();
await await runCmd(mountEngineCmd('aws', enginePath1));
await await runCmd(mountEngineCmd('aws', enginePath2));
await visit('/vault/secrets');
// filter by type
await clickTrigger('#filter-by-engine-type');
await searchSelect.options.objectAt(0).click();
await click(GENERAL.searchSelect.option());
const rows = document.querySelectorAll('[data-test-secrets-backend-link]');
const rows = findAll(SELECTORS.backendLink());
const rowsAws = Array.from(rows).filter((row) => row.innerText.includes('aws'));
assert.strictEqual(rows.length, rowsAws.length, 'all rows returned are aws');
// filter by name
await clickTrigger('#filter-by-engine-name');
const firstItemToSelect = searchSelect.options.objectAt(0).text;
await searchSelect.options.objectAt(0).click();
const firstItemToSelect = find(GENERAL.searchSelect.option()).innerText;
await click(GENERAL.searchSelect.option());
const singleRow = document.querySelectorAll('[data-test-secrets-backend-link]');
assert.strictEqual(singleRow.length, 1, 'returns only one row');
assert.dom(singleRow[0]).includesText(firstItemToSelect, 'shows the filtered by name engine');
// clear filter by engine name
await searchSelect.deleteButtons.objectAt(1).click();
await click(`#filter-by-engine-name ${GENERAL.searchSelect.removeSelected}`);
const rowsAgain = document.querySelectorAll('[data-test-secrets-backend-link]');
assert.ok(rowsAgain.length > 1, 'filter has been removed');
// cleanup
await consoleComponent.runCommands([`delete sys/mounts/${enginePath1}`]);
await consoleComponent.runCommands([`delete sys/mounts/${enginePath2}`]);
await runCmd(deleteEngineCmd(enginePath1));
await runCmd(deleteEngineCmd(enginePath2));
});
});

View File

@@ -48,17 +48,17 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook
const backend = this.backend;
await visit(`/vault/secrets/${backend}/kv/list`);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'single secret exists on list');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'jk');
await click(FORM.cancelBtn);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'psych');
await click(PAGE.breadcrumbAtIdx(1));
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
});
test('cancel on new version rolls back model (a)', async function (assert) {
const backend = this.backend;
@@ -500,17 +500,17 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook
const backend = this.backend;
await visit(`/vault/secrets/${backend}/kv/list`);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'single secret exists on list');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'jk');
await click(FORM.cancelBtn);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'psych');
await click(PAGE.breadcrumbAtIdx(1));
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
});
test('cancel on new version rolls back model (dlr)', async function (assert) {
const backend = this.backend;
@@ -649,17 +649,17 @@ module('Acceptance | kv-v2 workflow | secret and version create', function (hook
const backend = this.backend;
await visit(`/vault/secrets/${backend}/kv/list`);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'single secret exists on list');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'jk');
await click(FORM.cancelBtn);
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
await click(PAGE.list.createSecret);
await fillIn(FORM.inputByAttr('path'), 'psych');
await click(PAGE.breadcrumbAtIdx(1));
assert.dom(PAGE.list.item()).exists({ count: 1 }, 'same amount of secrets');
assert.dom(PAGE.list.item('app/')).hasText('app/', 'expected list item');
assert.dom(`${PAGE.list.item('app/')} [data-test-path]`).hasText('app/', 'expected list item');
});
test('cancel on new version rolls back model (mm)', async function (assert) {
const backend = this.backend;

View File

@@ -20,6 +20,7 @@ import { runCmd } from 'vault/tests/helpers/commands';
import { PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import codemirror from 'vault/tests/helpers/codemirror';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { SECRET_ENGINE_SELECTORS as SS } from 'vault/tests/helpers/secret-engine/secret-engine-selectors';
const deleteEngine = async function (enginePath, assert) {
await logout.visit();
@@ -180,9 +181,8 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
assert.dom('[data-test-secret-link]').exists({ count: 2 });
// delete the items
await listPage.secrets.objectAt(0).menuToggle();
await settled();
await listPage.delete();
await click(SS.secretLinkMenu('1/2/3/4'));
await click(SS.secretLinkMenuDelete('1/2/3/4'));
await listPage.confirmDelete();
await settled();
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.list');
@@ -219,7 +219,7 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
'(',
')',
'"',
//"'",
// "'",
'!',
'#',
'$',
@@ -243,8 +243,8 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
await runCmd([...commands, 'refresh']);
for (const path of paths) {
await listPage.visit({ backend, id: path });
assert.ok(listPage.secrets.filterBy('text', '2')[0], `${path}: secret is displayed properly`);
await listPage.secrets.filterBy('text', '2')[0].click();
assert.dom(SS.secretLinkATag()).hasText('2', `${path}: secret is displayed properly`);
await click(SS.secretLink());
assert.strictEqual(
currentRouteName(),
'vault.cluster.secrets.backend.show',
@@ -301,8 +301,8 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
await listPage.create();
await editPage.createSecret(`${path}/2`, 'foo', 'bar');
await listPage.visit({ backend, id: path });
assert.ok(listPage.secrets.filterBy('text', '2')[0], `${path}: secret is displayed properly`);
await listPage.secrets.filterBy('text', '2')[0].click();
assert.dom(SS.secretLinkATag()).hasText('2', `${path}: secret is displayed properly`);
await click(SS.secretLink());
assert.strictEqual(
currentRouteName(),
'vault.cluster.secrets.backend.show',

View File

@@ -19,6 +19,11 @@ export const SECRET_ENGINE_SELECTORS = {
mountSubmit: '[data-test-mount-submit]',
secretHeader: '[data-test-secret-header]',
secretLink: (name: string) => (name ? `[data-test-secret-link="${name}"]` : '[data-test-secret-link]'),
secretLinkMenu: (name: string) => `[data-test-secret-link="${name}"] [data-test-popup-menu-trigger]`,
secretLinkMenuDelete: (name: string) =>
`[data-test-secret-link="${name}"] [data-test-confirm-action-trigger]`,
secretLinkATag: (name: string) =>
name ? `[data-test-secret-item-link="${name}"]` : '[data-test-secret-item-link]',
viewBackend: '[data-test-backend-view-link]',
warning: '[data-test-warning]',
aws: {

View File

@@ -70,6 +70,7 @@ module('Integration | Component | kv | Page::List', function (hooks) {
@failedDirectoryQuery={{this.failedDirectoryQuery}}
@breadcrumbs={{this.breadcrumbs}}
@meta={{this.model.meta}}
@currentRouteParams={{array this.backend}}
/>`,
{
owner: this.engine,

View File

@@ -110,7 +110,9 @@ module('Integration | Component | ldap | Page::Roles', function (hooks) {
assert.dom('[data-test-delete]').hasText('Delete', 'Details link renders in menu');
await click('[data-test-popup-menu-trigger]:last-of-type');
assert.dom('[data-test-rotate-creds]').doesNotExist('Rotate credentials link is hidden for dynamic type');
assert
.dom('[data-test-popup-menu-trigger]:last-of-type [data-test-rotate-creds]')
.doesNotExist('Rotate credentials link is hidden for dynamic type');
});
test('it should filter roles', async function (assert) {

View File

@@ -2029,7 +2029,7 @@ __metadata:
languageName: node
linkType: hard
"@embroider/addon-shim@npm:^1.0.0, @embroider/addon-shim@npm:^1.2.0, @embroider/addon-shim@npm:^1.6.0, @embroider/addon-shim@npm:^1.8.0, @embroider/addon-shim@npm:^1.8.3, @embroider/addon-shim@npm:^1.8.4, @embroider/addon-shim@npm:^1.8.6, @embroider/addon-shim@npm:^1.8.7, @embroider/addon-shim@npm:^1.8.9":
"@embroider/addon-shim@npm:^1.0.0, @embroider/addon-shim@npm:^1.2.0, @embroider/addon-shim@npm:^1.6.0, @embroider/addon-shim@npm:^1.8.0, @embroider/addon-shim@npm:^1.8.3, @embroider/addon-shim@npm:^1.8.6, @embroider/addon-shim@npm:^1.8.7, @embroider/addon-shim@npm:^1.8.9":
version: 1.8.9
resolution: "@embroider/addon-shim@npm:1.8.9"
dependencies:
@@ -2458,25 +2458,24 @@ __metadata:
languageName: node
linkType: hard
"@hashicorp/design-system-components@npm:~4.7.0":
version: 4.7.0
resolution: "@hashicorp/design-system-components@npm:4.7.0"
"@hashicorp/design-system-components@npm:~4.12.0":
version: 4.12.0
resolution: "@hashicorp/design-system-components@npm:4.12.0"
dependencies:
"@ember/render-modifiers": ^2.0.5
"@ember/string": ^3.1.1
"@ember/test-waiters": ^3.1.0
"@embroider/addon-shim": ^1.8.7
"@floating-ui/dom": ^1.6.3
"@hashicorp/design-system-tokens": ^2.1.0
"@hashicorp/ember-flight-icons": ^5.1.3
"@hashicorp/flight-icons": ^3.5.0
"@hashicorp/design-system-tokens": ^2.2.1
"@hashicorp/flight-icons": ^3.6.0
decorator-transforms: ^1.1.0
ember-a11y-refocus: ^4.1.0
ember-a11y-refocus: ^4.1.3
ember-cli-sass: ^11.0.1
ember-composable-helpers: ^5.0.0
ember-element-helper: ^0.8.5
ember-focus-trap: ^1.1.0
ember-keyboard: ^8.2.1
ember-get-config: ^2.1.1
ember-modifier: ^4.1.0
ember-power-select: ^8.2.0
ember-stargate: ^0.4.3
@@ -2487,14 +2486,14 @@ __metadata:
tippy.js: ^6.3.7
peerDependencies:
ember-source: ^3.28.0 || ^4.0.0 || ^5.3.0
checksum: 88cafa21f11d761a226d9b065af715d632b1ea38699aac8294d035a7f7ab5518263c894813d0d4dc23f11dea440aaf6e58408531c7bbb3d9b2455a9dc9a9ba5c
checksum: ed7c79a43e3b286b5a4d543064dc566159909bee7052700eebe160a93f99b64dfc41291cd4d81c5dd558b415fc9033bc8937b0d751b191283ce404c407d1388b
languageName: node
linkType: hard
"@hashicorp/design-system-tokens@npm:^2.1.0":
version: 2.2.0
resolution: "@hashicorp/design-system-tokens@npm:2.2.0"
checksum: 654978be98a94c1f478e472793b9c1b62762bb30f9e0a097c2e1effd4fb2b4619eeef347e39599aea4dd63c451e0f41e698d887827ca2496de83a9e1e1dd8525
"@hashicorp/design-system-tokens@npm:^2.2.1":
version: 2.2.1
resolution: "@hashicorp/design-system-tokens@npm:2.2.1"
checksum: 0e4348ab27b2da4725068b5dab83474ad496895d2b422708b2c08cfc39289830f3756a1b352aff6e6095f64e3476ac227034ab02c7d2e0cc49d13a81ef69f6f3
languageName: node
linkType: hard
@@ -2517,6 +2516,13 @@ __metadata:
languageName: node
linkType: hard
"@hashicorp/flight-icons@npm:^3.6.0":
version: 3.6.0
resolution: "@hashicorp/flight-icons@npm:3.6.0"
checksum: 5c09574c3e44b5662665271f4aaec8e9d50d0eecb858ba5e9d4d669baf0d98d0e875ce440d84ea7911bf81ff35a01440f79dd27cb78af706ca85341101d61073
languageName: node
linkType: hard
"@humanwhocodes/config-array@npm:^0.11.14":
version: 0.11.14
resolution: "@humanwhocodes/config-array@npm:0.11.14"
@@ -7445,13 +7451,13 @@ __metadata:
languageName: node
linkType: hard
"ember-a11y-refocus@npm:^4.1.0":
version: 4.1.1
resolution: "ember-a11y-refocus@npm:4.1.1"
"ember-a11y-refocus@npm:^4.1.3":
version: 4.1.4
resolution: "ember-a11y-refocus@npm:4.1.4"
dependencies:
ember-cli-babel: ^7.26.11
ember-cli-htmlbars: ^6.0.1
checksum: b9f861f1359e8c720bf844161da3eecbe2218149739211961d216b6fcaec5e78dfd51debe5ec2707ae0d31fdbbd9cf692349e3f0f5b47d1f12bd963c021494ac
checksum: c1a79f9b7792f3bac674e010b231561da4ca5fc2f3f6a9a6e2263908a6c781546e1baccdb84838f367ac9104e2c76b7f688a57f06f0bd6c194a6f1a71910e422
languageName: node
linkType: hard
@@ -8283,7 +8289,7 @@ __metadata:
languageName: node
linkType: hard
"ember-destroyable-polyfill@npm:^2.0.1, ember-destroyable-polyfill@npm:^2.0.3":
"ember-destroyable-polyfill@npm:^2.0.1":
version: 2.0.3
resolution: "ember-destroyable-polyfill@npm:2.0.3"
dependencies:
@@ -8425,23 +8431,6 @@ __metadata:
languageName: node
linkType: hard
"ember-keyboard@npm:^8.2.1":
version: 8.2.1
resolution: "ember-keyboard@npm:8.2.1"
dependencies:
"@embroider/addon-shim": ^1.8.4
ember-destroyable-polyfill: ^2.0.3
ember-modifier: ^2.1.2 || ^3.1.0 || ^4.0.0
ember-modifier-manager-polyfill: ^1.2.0
peerDependencies:
"@ember/test-helpers": ^2.6.0 || ^3.0.0
peerDependenciesMeta:
"@ember/test-helpers":
optional: true
checksum: cfb4120aaf3b1ff3aba8ba1619b0597c6738abde31d1e0719d8bbf69512fb9967fc76bc85557351ec42856bb9b6c47354634f22f0accab0e15743d9f0e3f2be4
languageName: node
linkType: hard
"ember-lifeline@npm:^7.0.0":
version: 7.0.0
resolution: "ember-lifeline@npm:7.0.0"
@@ -8497,7 +8486,20 @@ __metadata:
languageName: node
linkType: hard
"ember-modifier@npm:^2.1.2 || ^3.1.0 || ^4.0.0, ember-modifier@npm:^3.2.7 || ^4.0.0, ember-modifier@npm:^4.1.0":
"ember-modifier@npm:^3.2.0, ember-modifier@npm:^3.2.7":
version: 3.2.7
resolution: "ember-modifier@npm:3.2.7"
dependencies:
ember-cli-babel: ^7.26.6
ember-cli-normalize-entity-name: ^1.0.0
ember-cli-string-utils: ^1.1.0
ember-cli-typescript: ^5.0.0
ember-compatibility-helpers: ^1.2.5
checksum: 2e96d9ec3939de178a9ce704d5a9360fd73f0276ffa4a9cce9f100a4087fdc8fae4a8b28bf1be22b05a4d1c61e1bb1ab93ca60576810c6556bc4d9323864c66a
languageName: node
linkType: hard
"ember-modifier@npm:^3.2.7 || ^4.0.0, ember-modifier@npm:^4.1.0":
version: 4.2.0
resolution: "ember-modifier@npm:4.2.0"
dependencies:
@@ -8514,19 +8516,6 @@ __metadata:
languageName: node
linkType: hard
"ember-modifier@npm:^3.2.0, ember-modifier@npm:^3.2.7":
version: 3.2.7
resolution: "ember-modifier@npm:3.2.7"
dependencies:
ember-cli-babel: ^7.26.6
ember-cli-normalize-entity-name: ^1.0.0
ember-cli-string-utils: ^1.1.0
ember-cli-typescript: ^5.0.0
ember-compatibility-helpers: ^1.2.5
checksum: 2e96d9ec3939de178a9ce704d5a9360fd73f0276ffa4a9cce9f100a4087fdc8fae4a8b28bf1be22b05a4d1c61e1bb1ab93ca60576810c6556bc4d9323864c66a
languageName: node
linkType: hard
"ember-page-title@npm:^8.0.0":
version: 8.2.3
resolution: "ember-page-title@npm:8.2.3"
@@ -18776,7 +18765,7 @@ __metadata:
"@ember/test-waiters": ^3.1.0
"@glimmer/component": ^1.1.2
"@glimmer/tracking": ^1.1.2
"@hashicorp/design-system-components": ~4.7.0
"@hashicorp/design-system-components": ~4.12.0
"@hashicorp/ember-flight-icons": ^5.1.3
"@icholy/duration": ^5.1.0
"@lineal-viz/lineal": ^0.5.1