UI: Replace popup-menu on list items (#25588)

This commit is contained in:
Chelsea Shaw
2024-02-22 17:11:48 -06:00
committed by GitHub
parent 2b46f5e523
commit 263584d7b4
25 changed files with 288 additions and 275 deletions

3
changelog/25588.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
ui: replace popup menu on list items (namespaces, auth items, KMIP, K8S, LDAP)
```

View File

@@ -7,6 +7,7 @@ import { service } from '@ember/service';
import Component from '@glimmer/component'; import Component from '@glimmer/component';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { getOwner } from '@ember/application'; import { getOwner } from '@ember/application';
import { tracked } from '@glimmer/tracking';
/** /**
* @module GeneratedItemList * @module GeneratedItemList
@@ -26,6 +27,7 @@ import { getOwner } from '@ember/application';
export default class GeneratedItemList extends Component { export default class GeneratedItemList extends Component {
@service router; @service router;
@service store; @service store;
@tracked showConfirmModal = false;
get model() { get model() {
return this.args.model || null; return this.args.model || null;

View File

@@ -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);
}
}

View File

@@ -72,21 +72,36 @@
<Icon @name="folder" class="has-text-grey-light" />{{list.item.id}} <Icon @name="folder" class="has-text-grey-light" />{{list.item.id}}
</Item.content> </Item.content>
<Item.menu> <Item.menu>
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<LinkTo @route="vault.cluster.access.method.item.show" @model={{list.item.id}} class="is-block"> <dd.ToggleIcon
View @icon="more-horizontal"
{{singularize this.itemType}} @text="Overflow options"
</LinkTo> @hasChevron={{false}}
</li> data-test-popup-menu-trigger
<li class="action"> />
<LinkTo @route="vault.cluster.access.method.item.edit" @model={{list.item.id}} class="is-block"> <dd.Interactive
Edit @text="View {{singularize this.itemType}}"
{{singularize this.itemType}} @route="vault.cluster.access.method.item.show"
</LinkTo> @model={{list.item.id}}
</li> />
<ConfirmAction <dd.Interactive
@isInDropdown={{true}} @text="Edit {{singularize this.itemType}}"
@onConfirmAction={{action @route="vault.cluster.access.method.item.edit"
@model={{list.item.id}}
/>
<dd.Interactive
@text="Delete {{singularize this.itemType}}"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
/>
</Hds::Dropdown>
</Item.menu>
{{#if this.showConfirmModal}}
<ConfirmModal
@color="critical"
@onClose={{fn (mut this.showConfirmModal) false}}
@onConfirm={{action
(perform (perform
Item.callMethod Item.callMethod
"destroyRecord" "destroyRecord"
@@ -98,9 +113,8 @@
}} }}
@confirmTitle="Delete {{singularize this.itemType}}?" @confirmTitle="Delete {{singularize this.itemType}}?"
@confirmMessage="Are you sure you want to delete {{singularize this.itemType}} {{list.item.id}}?" @confirmMessage="Are you sure you want to delete {{singularize this.itemType}} {{list.item.id}}?"
@buttonText="Delete {{singularize this.itemType}}"
/> />
</Item.menu> {{/if}}
</ListItem> </ListItem>
{{/if}} {{/if}}
</ListView> </ListView>

View File

@@ -35,31 +35,37 @@
{{list.item.id}} {{list.item.id}}
</Item.content> </Item.content>
<Item.menu> <Item.menu>
{{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}} <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
{{#if (includes targetNamespace this.accessibleNamespaces)}} <dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
<li class="action"> {{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
<NamespaceLink @targetNamespace={{targetNamespace}} @unparsed={{true}} @class="is-block"> {{#if (includes targetNamespace this.accessibleNamespaces)}}
Switch to Namespace <dd.Generic>
</NamespaceLink> <NamespaceLink @targetNamespace={{targetNamespace}} @unparsed={{true}} @class="ns-dropdown-item">
</li> Switch to Namespace
{{/if}} </NamespaceLink>
{{/let}} </dd.Generic>
<ConfirmAction {{/if}}
@isInDropdown={{true}} {{/let}}
@buttonText="Delete" <dd.Interactive @text="Delete" @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}} />
@confirmTitle="Delete this namespace?" </Hds::Dropdown>
@confirmMessage="Any engines or mounts in this namespace will also be removed." {{#if this.showConfirmModal}}
@onConfirmAction={{action <ConfirmModal
(perform @color="critical"
Item.callMethod @onClose={{fn (mut this.showConfirmModal) false}}
"destroyRecord" @onConfirm={{action
list.item (perform
(concat "Successfully deleted namespace: " list.item.id) Item.callMethod
"There was an error deleting this namespace: " "destroyRecord"
(action "refreshNamespaceList") list.item
) (concat "Successfully deleted namespace: " list.item.id)
}} "There was an error deleting this namespace: "
/> (action "refreshNamespaceList")
)
}}
@confirmTitle="Delete this namespace?"
@confirmMessage="Any engines or mounts in this namespace will also be removed."
/>
{{/if}}
</Item.menu> </Item.menu>
</ListItem> </ListItem>
{{/if}} {{/if}}

View File

@@ -3,14 +3,4 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
~}} ~}}
{{#if this.hasMenu}} {{yield this.item}}
<PopupMenu>
<nav class="menu">
<ul class="menu-list">
{{yield}}
</ul>
</nav>
</PopupMenu>
{{else}}
{{yield this.item}}
{{/if}}

View File

@@ -63,22 +63,33 @@
<Icon @name="file-text" class="has-text-grey-light" />{{list.item.id}} <Icon @name="file-text" class="has-text-grey-light" />{{list.item.id}}
</Item.content> </Item.content>
<Item.menu> <Item.menu>
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<LinkTo @route="credentials.show" @models={{array this.scope this.role list.item.id}} class="is-block"> <dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
View credentials <dd.Interactive
</LinkTo> @text="View credentials"
</li> @route="credentials.show"
{{#if list.item.deletePath.isPending}} @models={{array this.scope this.role list.item.id}}
<li class="action"> />
<LoadingDropdownOption /> {{#if list.item.deletePath.isPending}}
</li> <dd.Generic>
{{else if list.item.deletePath.canDelete}} <LoadingDropdownOption />
<ConfirmAction </dd.Generic>
@isInDropdown={{true}} {{else if list.item.deletePath.canDelete}}
@buttonText="Revoke credentials" <dd.Interactive
@text="Revoke credentials"
@color="critical"
{{on "click" (fn (mut this.showConfirmModal) true)}}
data-test-confirm-action-trigger
/>
{{/if}}
</Hds::Dropdown>
{{#if this.showConfirmModal}}
<ConfirmModal
@color="critical"
@onClose={{fn (mut this.showConfirmModal) false}}
@confirmTitle="Revoke this?" @confirmTitle="Revoke this?"
@confirmMessage="Any client using these credentials will no longer be able to." @confirmMessage="Any client using these credentials will no longer be able to."
@onConfirmAction={{action @onConfirm={{action
(perform (perform
Item.callMethod Item.callMethod
"destroyRecord" "destroyRecord"

View File

@@ -35,7 +35,7 @@
@onError={{(fn @onError={{(fn
(set-flash-message "Clipboard copy failed. Please make sure the browser Clipboard API is allowed." "danger") (set-flash-message "Clipboard copy failed. Please make sure the browser Clipboard API is allowed." "danger")
)}} )}}
class="toolbar-link is-flex-center" class="toolbar-button"
data-test-copy-button data-test-copy-button
/> />
</ToolbarActions> </ToolbarActions>

View File

@@ -69,44 +69,44 @@
<Icon @name="user" class="has-text-grey-light" />{{list.item.id}} <Icon @name="user" class="has-text-grey-light" />{{list.item.id}}
</Item.content> </Item.content>
<Item.menu> <Item.menu>
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<LinkTo @route="credentials" @models={{array this.scope list.item.id}} class="is-block"> <dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
View credentials <dd.Interactive @text="View credentials" @route="credentials" @models={{array this.scope list.item.id}} />
</LinkTo> <dd.Interactive @text="View role" @route="role" @models={{array this.scope list.item.id}} />
</li> {{#if list.item.updatePath.isPending}}
<li class="action"> <dd.Generic>
<LinkTo @route="role" @models={{array this.scope list.item.id}} class="is-block"> <LoadingDropdownOption />
View role </dd.Generic>
</LinkTo> {{else}}
</li> {{#if list.item.updatePath.canUpdate}}
{{#if list.item.updatePath.isPending}} <dd.Interactive @text="Edit role" @route="role.edit" @models={{array this.scope list.item.id}} />
<li class="action"> {{/if}}
<LoadingDropdownOption /> {{#if list.item.updatePath.canDelete}}
</li> <dd.Interactive
{{else}} @text="Delete role"
{{#if list.item.updatePath.canUpdate}} @color="critical"
<LinkTo @route="role.edit" @models={{array this.scope list.item.id}} class="is-block"> {{on "click" (fn (mut this.showConfirmModal) true)}}
Edit role data-test-confirm-action-trigger
</LinkTo> />
{{/if}} {{/if}}
{{#if list.item.updatePath.canDelete}}
<ConfirmAction
@isInDropdown={{true}}
@buttonText="Delete role"
@confirmMessage="Are you sure you want to delete {{list.item.id}}?"
@onConfirmAction={{action
(perform
Item.callMethod
"destroyRecord"
list.item
(concat "Successfully deleted role " list.item.id)
(concat "There was an error deleting the role " list.item.id)
(action "refresh")
)
}}
data-test-scope-delete
/>
{{/if}} {{/if}}
</Hds::Dropdown>
{{#if this.showConfirmModal}}
<ConfirmModal
@color="critical"
@confirmMessage="Are you sure you want to delete {{list.item.id}}?"
@onConfirm={{action
(perform
Item.callMethod
"destroyRecord"
list.item
(concat "Successfully deleted role " list.item.id)
(concat "There was an error deleting the role " list.item.id)
(action "refresh")
)
}}
@onClose={{fn (mut this.showConfirmModal) false}}
/>
{{/if}} {{/if}}
</Item.menu> </Item.menu>
</ListItem> </ListItem>

View File

@@ -58,22 +58,29 @@
<Icon @name="folder" class="has-text-grey-light" />{{list.item.id}} <Icon @name="folder" class="has-text-grey-light" />{{list.item.id}}
</Item.content> </Item.content>
<Item.menu> <Item.menu>
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<LinkTo @route="scope" @model={{list.item.id}} class="is-block"> <dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
View scope <dd.Interactive @text="View scope" @route="scope" @model={{list.item.id}} />
</LinkTo> {{#if list.item.updatePath.isPending}}
</li> <dd.Generic>
{{#if list.item.updatePath.isPending}} <LoadingDropdownOption />
<li class="action"> </dd.Generic>
<LoadingDropdownOption /> {{else if list.item.updatePath.canDelete}}
</li> <dd.Interactive
{{else if list.item.updatePath.canDelete}} @text="Delete scope"
<ConfirmAction @color="critical"
@isInDropdown={{true}} {{on "click" (fn (mut this.showConfirmModal) true)}}
@buttonText="Delete scope" data-test-confirm-action-trigger
/>
{{/if}}
</Hds::Dropdown>
{{#if this.showConfirmModal}}
<ConfirmModal
@color="critical"
@confirmTitle="Delete scope {{list.item.id}}?" @confirmTitle="Delete scope {{list.item.id}}?"
@confirmMessage="This will permanently delete this scope and all roles and credentials contained within" @confirmMessage="This will permanently delete this scope and all roles and credentials contained within"
@onConfirmAction={{action @onClose={{fn (mut this.showConfirmModal) false}}
@onConfirm={{action
(perform (perform
Item.callMethod Item.callMethod
"destroyRecord" "destroyRecord"

View File

@@ -37,43 +37,40 @@
<span data-test-role={{role.name}}>{{role.name}}</span> <span data-test-role={{role.name}}>{{role.name}}</span>
</Item.content> </Item.content>
<Item.menu> <Item.menu>
{{#if role.rolesPath.isLoading}} {{#if (or role.canRead role.canEdit role.canDelete)}}
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} /> <dd.ToggleIcon
</li> @icon="more-horizontal"
{{else}} @text="More options"
<li class="action"> @hasChevron={{false}}
<LinkTo data-test-popup-menu-trigger
class="has-text-black has-text-weight-semibold" />
data-test-details {{#if role.canRead}}
@route="roles.role.details" <dd.Interactive @text="Details" @route="roles.role.details" @model={{role}} data-test-details />
@model={{role}} {{/if}}
@disabled={{eq role.canRead false}} {{#if role.canEdit}}
> <dd.Interactive @text="Edit" data-test-edit @route="roles.role.edit" @model={{role}} />
Details {{/if}}
</LinkTo> {{#if role.canDelete}}
</li> <dd.Interactive
<li class="action"> @text="Delete"
<LinkTo data-test-delete
class="has-text-black has-text-weight-semibold" @color="critical"
data-test-edit {{on "click" (fn (mut this.roleToDelete) role)}}
@route="roles.role.edit" />
@model={{role}} {{/if}}
@disabled={{not role.canEdit}} </Hds::Dropdown>
>
Edit
</LinkTo>
</li>
<ConfirmAction
data-test-delete
@isInDropdown={{true}}
@buttonText="Delete"
@confirmMessage="Deleting this role means that youll need to recreate it in order to generate credentials again."
@onConfirmAction={{fn this.onDelete role}}
/>
{{/if}} {{/if}}
</Item.menu> </Item.menu>
</ListItem> </ListItem>
{{/each}} {{/each}}
{{#if this.roleToDelete}}
<ConfirmModal
@color="critical"
@confirmMessage="Deleting this role means that youll need to recreate it in order to generate credentials again."
@onConfirm={{fn this.onDelete this.roleToDelete}}
@onClose={{fn (mut this.roleToDelete) null}}
/>
{{/if}}
</div> </div>
{{/if}} {{/if}}

View File

@@ -8,6 +8,7 @@ import { service } from '@ember/service';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { getOwner } from '@ember/application'; import { getOwner } from '@ember/application';
import errorMessage from 'vault/utils/error-message'; import errorMessage from 'vault/utils/error-message';
import { tracked } from '@glimmer/tracking';
/** /**
* @module Roles * @module Roles
@@ -20,6 +21,7 @@ import errorMessage from 'vault/utils/error-message';
*/ */
export default class RolesPageComponent extends Component { export default class RolesPageComponent extends Component {
@service flashMessages; @service flashMessages;
@tracked roleToDelete = null;
get mountPoint() { get mountPoint() {
return getOwner(this).mountPoint; return getOwner(this).mountPoint;
@@ -35,6 +37,8 @@ export default class RolesPageComponent extends Component {
} catch (error) { } catch (error) {
const message = errorMessage(error, 'Error deleting role. Please try again or contact support'); const message = errorMessage(error, 'Error deleting role. Please try again or contact support');
this.flashMessages.danger(message); this.flashMessages.danger(message);
} finally {
this.roleToDelete = null;
} }
} }
} }

View File

@@ -49,46 +49,40 @@
<span data-test-library={{library.name}}>{{library.name}}</span> <span data-test-library={{library.name}}>{{library.name}}</span>
</Item.content> </Item.content>
<Item.menu> <Item.menu>
{{#if library.libraryPath.isLoading}} {{#if (or library.canRead library.canEdit library.canDelete)}}
<li class="action"> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} /> <dd.ToggleIcon
</li> @icon="more-horizontal"
{{else}} @text="More options"
<li class="action"> @hasChevron={{false}}
<LinkTo data-test-popup-menu-trigger
class="has-text-black has-text-weight-semibold"
data-test-edit
@route="libraries.library.edit"
@model={{library}}
@disabled={{not library.canEdit}}
>
Edit
</LinkTo>
</li>
<li class="action">
<LinkTo
class="has-text-black has-text-weight-semibold"
data-test-details
@route="libraries.library.details"
@model={{library}}
@disabled={{not library.canRead}}
>
Details
</LinkTo>
</li>
{{#if library.canDelete}}
<ConfirmAction
data-test-delete
@id={{library.id}}
@isInDropdown={{true}}
@buttonText="Delete"
@confirmMessage="This library and associated accounts will be permanently deleted. You will not be able to recover it."
@onConfirmAction={{fn this.onDelete library}}
/> />
{{/if}} {{#if library.canEdit}}
<dd.Interactive @text="Edit" data-test-edit @route="libraries.library.edit" @model={{library}} />
{{/if}}
{{#if library.canRead}}
<dd.Interactive @text="Details" data-test-details @route="libraries.library.details" @model={{library}} />
{{/if}}
{{#if library.canDelete}}
<dd.Interactive
@text="Delete"
data-test-delete
@color="critical"
{{on "click" (fn (mut this.libraryToDelete) library)}}
/>
{{/if}}
</Hds::Dropdown>
{{/if}} {{/if}}
</Item.menu> </Item.menu>
</ListItem> </ListItem>
{{/each}} {{/each}}
{{#if this.libraryToDelete}}
<ConfirmModal
@color="critical"
@confirmMessage="This library and associated accounts will be permanently deleted. You will not be able to recover it."
@onConfirm={{fn this.onDelete this.libraryToDelete}}
@onClose={{fn (mut this.libraryToDelete) false}}
/>
{{/if}}
</div> </div>
{{/if}} {{/if}}

View File

@@ -26,6 +26,7 @@ export default class LdapLibrariesPageComponent extends Component<Args> {
@service declare readonly flashMessages: FlashMessageService; @service declare readonly flashMessages: FlashMessageService;
@tracked filterValue = ''; @tracked filterValue = '';
@tracked libraryToDelete: LdapLibraryModel | null = null;
get mountPoint(): string { get mountPoint(): string {
const owner = getOwner(this) as EngineOwner; const owner = getOwner(this) as EngineOwner;

View File

@@ -50,70 +50,63 @@
<Hds::Badge @text={{role.type}} data-test-role-type-badge={{role.name}} /> <Hds::Badge @text={{role.type}} data-test-role-type-badge={{role.name}} />
</Item.content> </Item.content>
<Item.menu> <Item.menu>
{{#if role.rolePath.isLoading}} <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<li class="action"> <dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} /> {{#if role.canEdit}}
</li> <dd.Interactive @text="Edit" data-test-edit @route="roles.role.edit" @models={{array role.type role.name}} />
{{else}} {{/if}}
<li class="action"> {{#if role.canReadCreds}}
<LinkTo <dd.Interactive
class="has-text-black has-text-weight-semibold" @text="Get credentials"
data-test-edit
@route="roles.role.edit"
@models={{array role.type role.name}}
@disabled={{not role.canEdit}}
>
Edit
</LinkTo>
</li>
<li class="action">
<LinkTo
class="has-text-black has-text-weight-semibold"
data-test-get-creds data-test-get-creds
@route="roles.role.credentials" @route="roles.role.credentials"
@models={{array role.type role.name}} @models={{array role.type role.name}}
@disabled={{not role.canReadCreds}} />
> {{/if}}
Get credentials
</LinkTo>
</li>
{{#if role.canRotateStaticCreds}} {{#if role.canRotateStaticCreds}}
<ConfirmAction <dd.Interactive
@text="Rotate credentials"
data-test-rotate-creds data-test-rotate-creds
@isInDropdown={{true}} @color="critical"
@id={{concat "rotate-" role.id}} {{on "click" (fn (mut this.credsToRotate) role)}}
@buttonText="Rotate credentials"
@confirmMessage="When manually rotating credentials, the rotation period will start over."
@modalColor="warning"
@onConfirmAction={{fn this.onRotate role}}
/> />
{{/if}} {{/if}}
<li class="action"> <dd.Interactive
<LinkTo @text="Details"
class="has-text-black has-text-weight-semibold" data-test-details
data-test-details @route="roles.role.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 }}
{{! 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}}
@models={{array role.type role.name}} />
@disabled={{not role.canRead}}
>
Details
</LinkTo>
</li>
{{#if role.canDelete}} {{#if role.canDelete}}
<ConfirmAction <dd.Interactive
@text="Delete"
data-test-delete data-test-delete
@isInDropdown={{true}} @color="critical"
@buttonText="Delete" {{on "click" (fn (mut this.roleToDelete) role)}}
@confirmMessage="Deleting this role means that youll need to recreate it in order to generate credentials again."
@onConfirmAction={{fn this.onDelete role}}
/> />
{{/if}} {{/if}}
{{/if}} </Hds::Dropdown>
</Item.menu> </Item.menu>
</ListItem> </ListItem>
{{/each}} {{/each}}
{{#if this.credsToRotate}}
<ConfirmModal
@confirmMessage="When manually rotating credentials, the rotation period will start over."
@onConfirm={{fn this.onRotate this.credsToRotate}}
@onClose={{fn (mut this.credsToRotate) null}}
/>
{{/if}}
{{#if this.roleToDelete}}
<ConfirmModal
@color="critical"
@confirmMessage="Deleting this role means that youll need to recreate it in order to generate credentials again."
@onConfirm={{fn this.onDelete this.roleToDelete}}
@onClose={{fn (mut this.roleToDelete) null}}
/>
{{/if}}
<Hds::Pagination::Numbered <Hds::Pagination::Numbered
@currentPage={{@roles.meta.currentPage}} @currentPage={{@roles.meta.currentPage}}
@currentPageSize={{@roles.meta.pageSize}} @currentPageSize={{@roles.meta.pageSize}}

View File

@@ -15,6 +15,7 @@ import type FlashMessageService from 'vault/services/flash-messages';
import type { Breadcrumb, EngineOwner } from 'vault/vault/app-types'; import type { Breadcrumb, EngineOwner } from 'vault/vault/app-types';
import type RouterService from '@ember/routing/router-service'; import type RouterService from '@ember/routing/router-service';
import type StoreService from 'vault/services/store'; import type StoreService from 'vault/services/store';
import { tracked } from '@glimmer/tracking';
interface Args { interface Args {
roles: Array<LdapRoleModel>; roles: Array<LdapRoleModel>;
@@ -28,6 +29,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
@service declare readonly flashMessages: FlashMessageService; @service declare readonly flashMessages: FlashMessageService;
@service declare readonly router: RouterService; @service declare readonly router: RouterService;
@service declare readonly store: StoreService; @service declare readonly store: StoreService;
@tracked credsToRotate: LdapRoleModel | null = null;
@tracked roleToDelete: LdapRoleModel | null = null;
get mountPoint(): string { get mountPoint(): string {
const owner = getOwner(this) as EngineOwner; const owner = getOwner(this) as EngineOwner;
@@ -51,6 +54,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
this.flashMessages.success(message); this.flashMessages.success(message);
} catch (error) { } catch (error) {
this.flashMessages.danger(`Error rotating credentials \n ${errorMessage(error)}`); this.flashMessages.danger(`Error rotating credentials \n ${errorMessage(error)}`);
} finally {
this.credsToRotate = null;
} }
} }
@@ -64,6 +69,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
this.flashMessages.success(message); this.flashMessages.success(message);
} catch (error) { } catch (error) {
this.flashMessages.danger(`Error deleting role \n ${errorMessage(error)}`); this.flashMessages.danger(`Error deleting role \n ${errorMessage(error)}`);
} finally {
this.roleToDelete = null;
} }
} }
} }

View File

@@ -67,7 +67,7 @@
</code> </code>
</Item.content> </Item.content>
<Item.menu @hasMenu={{false}}> <Item.menu>
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
<dd.ToggleIcon <dd.ToggleIcon
@icon="more-horizontal" @icon="more-horizontal"

View File

@@ -31,7 +31,7 @@ export default class SyncSecretsDestinationsPageComponent extends Component<Args
@service declare readonly store: StoreService; @service declare readonly store: StoreService;
@service declare readonly flashMessages: FlashMessageService; @service declare readonly flashMessages: FlashMessageService;
@tracked destinationToDelete = null; @tracked destinationToDelete: SyncDestinationModel | null = null;
// for some reason there isn't a full page refresh happening when transitioning on filter change // for some reason there isn't a full page refresh happening when transitioning on filter change
// when the transition happens it causes the FilterInput component to lose focus since it can only focus on didInsert // when the transition happens it causes the FilterInput component to lose focus since it can only focus on didInsert
// to work around this, verify that a transition from this route was completed and then focus the input // to work around this, verify that a transition from this route was completed and then focus the input

View File

@@ -33,7 +33,7 @@
</div> </div>
</Item.content> </Item.content>
<Item.menu @hasMenu={{false}}> <Item.menu>
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" @width="210px" as |dd|> <Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" @width="210px" as |dd|>
<dd.ToggleIcon <dd.ToggleIcon
@icon="more-horizontal" @icon="more-horizontal"

View File

@@ -27,7 +27,7 @@ export default class SyncSecretsDestinationsPageComponent extends Component<Args
@service declare readonly store: StoreService; @service declare readonly store: StoreService;
@service declare readonly flashMessages: FlashMessageService; @service declare readonly flashMessages: FlashMessageService;
@tracked secretToUnsync = null; @tracked secretToUnsync: SyncAssociationModel | null = null;
get mountPoint(): string { get mountPoint(): string {
const owner = getOwner(this) as EngineOwner; const owner = getOwner(this) as EngineOwner;

View File

@@ -13,7 +13,6 @@ import rolesPage from 'vault/tests/pages/secrets/backend/kmip/roles';
import credentialsPage from 'vault/tests/pages/secrets/backend/kmip/credentials'; import credentialsPage from 'vault/tests/pages/secrets/backend/kmip/credentials';
import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend'; import mountSecrets from 'vault/tests/pages/settings/mount-secret-backend';
import { allEngines } from 'vault/helpers/mountable-secret-engines'; import { allEngines } from 'vault/helpers/mountable-secret-engines';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
const getRandomPort = () => { const getRandomPort = () => {
@@ -316,12 +315,6 @@ module('Acceptance | Enterprise | KMIP secrets', function (hooks) {
}); });
test('it can revoke a credential from the list', async function (assert) { 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(); const { path, scope, role } = await generateCreds();
await credentialsPage.visit({ backend: path, scope, role }); await credentialsPage.visit({ backend: path, scope, role });
// revoke the credentials // revoke the credentials

View File

@@ -10,7 +10,6 @@ import kubernetesScenario from 'vault/mirage/scenarios/kubernetes';
import kubernetesHandlers from 'vault/mirage/handlers/kubernetes'; import kubernetesHandlers from 'vault/mirage/handlers/kubernetes';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { fillIn, visit, currentURL, click, currentRouteName } from '@ember/test-helpers'; import { fillIn, visit, currentURL, click, currentRouteName } from '@ember/test-helpers';
import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | kubernetes | roles', function (hooks) { module('Acceptance | kubernetes | roles', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@@ -55,12 +54,6 @@ module('Acceptance | kubernetes | roles', function (hooks) {
}); });
test('it should have functional list item menu', async function (assert) { test('it should have functional list item menu', async function (assert) {
// Popup menu causes flakiness
setRunOptions({
rules: {
'color-contrast': { enabled: false },
},
});
assert.expect(3); assert.expect(3);
await this.visitRoles(); await this.visitRoles();
for (const action of ['details', 'edit', 'delete']) { for (const action of ['details', 'edit', 'delete']) {

View File

@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { click } from '@ember/test-helpers'; import { click } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap'; import { isURL, visitURL } from 'vault/tests/helpers/ldap';
import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | ldap | libraries', function (hooks) { module('Acceptance | ldap | libraries', function (hooks) {
setupApplicationTest(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) { 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); assert.expect(2);
for (const action of ['edit', 'details']) { for (const action of ['edit', 'details']) {

View File

@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { click, fillIn } from '@ember/test-helpers'; import { click, fillIn } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap'; import { isURL, visitURL } from 'vault/tests/helpers/ldap';
import { setRunOptions } from 'ember-a11y-testing/test-support';
module('Acceptance | ldap | roles', function (hooks) { module('Acceptance | ldap | roles', function (hooks) {
setupApplicationTest(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) { 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); assert.expect(3);
for (const action of ['edit', 'get-creds', 'details']) { for (const action of ['edit', 'get-creds', 'details']) {

View File

@@ -9,6 +9,7 @@ import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support';
import { render, click } from '@ember/test-helpers'; import { render, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile'; import hbs from 'htmlbars-inline-precompile';
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
module('Integration | Component | kubernetes | Page::Roles', function (hooks) { module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
@@ -17,6 +18,7 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.store = this.owner.lookup('service:store'); this.store = this.owner.lookup('service:store');
this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub(['read', 'update', 'delete']));
this.store.pushPayload('secret-engine', { this.store.pushPayload('secret-engine', {
modelName: 'secret-engine', modelName: 'secret-engine',
data: { data: {
@@ -88,11 +90,6 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
}); });
test('it should render roles list', async function (assert) { test('it should render roles list', async function (assert) {
this.server.post('/sys/capabilities-self', () => ({
data: {
'kubernetes/role': ['root'],
},
}));
await this.renderComponent(); await this.renderComponent();
assert.dom('[data-test-list-item-content] svg').hasClass('flight-icon-user', 'List item icon renders'); assert.dom('[data-test-list-item-content] svg').hasClass('flight-icon-user', 'List item icon renders');
assert assert