mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
UI: Replace popup-menu on list items (#25588)
This commit is contained in:
3
changelog/25588.txt
Normal file
3
changelog/25588.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: replace popup menu on list items (namespaces, auth items, KMIP, K8S, LDAP)
|
||||
```
|
||||
@@ -7,6 +7,7 @@ import { service } from '@ember/service';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* @module GeneratedItemList
|
||||
@@ -26,6 +27,7 @@ import { getOwner } from '@ember/application';
|
||||
export default class GeneratedItemList extends Component {
|
||||
@service router;
|
||||
@service store;
|
||||
@tracked showConfirmModal = false;
|
||||
|
||||
get model() {
|
||||
return this.args.model || null;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,21 +72,36 @@
|
||||
<Icon @name="folder" class="has-text-grey-light" />{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
<li class="action">
|
||||
<LinkTo @route="vault.cluster.access.method.item.show" @model={{list.item.id}} class="is-block">
|
||||
View
|
||||
{{singularize this.itemType}}
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="action">
|
||||
<LinkTo @route="vault.cluster.access.method.item.edit" @model={{list.item.id}} class="is-block">
|
||||
Edit
|
||||
{{singularize this.itemType}}
|
||||
</LinkTo>
|
||||
</li>
|
||||
<ConfirmAction
|
||||
@isInDropdown={{true}}
|
||||
@onConfirmAction={{action
|
||||
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
|
||||
<dd.ToggleIcon
|
||||
@icon="more-horizontal"
|
||||
@text="Overflow options"
|
||||
@hasChevron={{false}}
|
||||
data-test-popup-menu-trigger
|
||||
/>
|
||||
<dd.Interactive
|
||||
@text="View {{singularize this.itemType}}"
|
||||
@route="vault.cluster.access.method.item.show"
|
||||
@model={{list.item.id}}
|
||||
/>
|
||||
<dd.Interactive
|
||||
@text="Edit {{singularize this.itemType}}"
|
||||
@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
|
||||
Item.callMethod
|
||||
"destroyRecord"
|
||||
@@ -98,9 +113,8 @@
|
||||
}}
|
||||
@confirmTitle="Delete {{singularize this.itemType}}?"
|
||||
@confirmMessage="Are you sure you want to delete {{singularize this.itemType}} {{list.item.id}}?"
|
||||
@buttonText="Delete {{singularize this.itemType}}"
|
||||
/>
|
||||
</Item.menu>
|
||||
{{/if}}
|
||||
</ListItem>
|
||||
{{/if}}
|
||||
</ListView>
|
||||
@@ -35,31 +35,37 @@
|
||||
{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
|
||||
{{#if (includes targetNamespace this.accessibleNamespaces)}}
|
||||
<li class="action">
|
||||
<NamespaceLink @targetNamespace={{targetNamespace}} @unparsed={{true}} @class="is-block">
|
||||
Switch to Namespace
|
||||
</NamespaceLink>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
<ConfirmAction
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Delete"
|
||||
@confirmTitle="Delete this namespace?"
|
||||
@confirmMessage="Any engines or mounts in this namespace will also be removed."
|
||||
@onConfirmAction={{action
|
||||
(perform
|
||||
Item.callMethod
|
||||
"destroyRecord"
|
||||
list.item
|
||||
(concat "Successfully deleted namespace: " list.item.id)
|
||||
"There was an error deleting this namespace: "
|
||||
(action "refreshNamespaceList")
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
|
||||
<dd.ToggleIcon @icon="more-horizontal" @text="More options" @hasChevron={{false}} data-test-popup-menu-trigger />
|
||||
{{#let (concat this.currentNamespace (if this.currentNamespace "/") list.item.id) as |targetNamespace|}}
|
||||
{{#if (includes targetNamespace this.accessibleNamespaces)}}
|
||||
<dd.Generic>
|
||||
<NamespaceLink @targetNamespace={{targetNamespace}} @unparsed={{true}} @class="ns-dropdown-item">
|
||||
Switch to Namespace
|
||||
</NamespaceLink>
|
||||
</dd.Generic>
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
<dd.Interactive @text="Delete" @color="critical" {{on "click" (fn (mut this.showConfirmModal) true)}} />
|
||||
</Hds::Dropdown>
|
||||
{{#if this.showConfirmModal}}
|
||||
<ConfirmModal
|
||||
@color="critical"
|
||||
@onClose={{fn (mut this.showConfirmModal) false}}
|
||||
@onConfirm={{action
|
||||
(perform
|
||||
Item.callMethod
|
||||
"destroyRecord"
|
||||
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>
|
||||
</ListItem>
|
||||
{{/if}}
|
||||
|
||||
@@ -3,14 +3,4 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
{{#if this.hasMenu}}
|
||||
<PopupMenu>
|
||||
<nav class="menu">
|
||||
<ul class="menu-list">
|
||||
{{yield}}
|
||||
</ul>
|
||||
</nav>
|
||||
</PopupMenu>
|
||||
{{else}}
|
||||
{{yield this.item}}
|
||||
{{/if}}
|
||||
{{yield this.item}}
|
||||
@@ -63,22 +63,33 @@
|
||||
<Icon @name="file-text" class="has-text-grey-light" />{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
<li class="action">
|
||||
<LinkTo @route="credentials.show" @models={{array this.scope this.role list.item.id}} class="is-block">
|
||||
View credentials
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if list.item.deletePath.isPending}}
|
||||
<li class="action">
|
||||
<LoadingDropdownOption />
|
||||
</li>
|
||||
{{else if list.item.deletePath.canDelete}}
|
||||
<ConfirmAction
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Revoke credentials"
|
||||
<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}}
|
||||
/>
|
||||
{{#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.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?"
|
||||
@confirmMessage="Any client using these credentials will no longer be able to."
|
||||
@onConfirmAction={{action
|
||||
@onConfirm={{action
|
||||
(perform
|
||||
Item.callMethod
|
||||
"destroyRecord"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
@onError={{(fn
|
||||
(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
|
||||
/>
|
||||
</ToolbarActions>
|
||||
|
||||
@@ -69,44 +69,44 @@
|
||||
<Icon @name="user" class="has-text-grey-light" />{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
<li class="action">
|
||||
<LinkTo @route="credentials" @models={{array this.scope list.item.id}} class="is-block">
|
||||
View credentials
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="action">
|
||||
<LinkTo @route="role" @models={{array this.scope list.item.id}} class="is-block">
|
||||
View role
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if list.item.updatePath.isPending}}
|
||||
<li class="action">
|
||||
<LoadingDropdownOption />
|
||||
</li>
|
||||
{{else}}
|
||||
{{#if list.item.updatePath.canUpdate}}
|
||||
<LinkTo @route="role.edit" @models={{array this.scope list.item.id}} class="is-block">
|
||||
Edit role
|
||||
</LinkTo>
|
||||
{{/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
|
||||
/>
|
||||
<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}} />
|
||||
{{#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}} />
|
||||
{{/if}}
|
||||
{{#if list.item.updatePath.canDelete}}
|
||||
<dd.Interactive
|
||||
@text="Delete role"
|
||||
@color="critical"
|
||||
{{on "click" (fn (mut this.showConfirmModal) true)}}
|
||||
data-test-confirm-action-trigger
|
||||
/>
|
||||
{{/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}}
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
|
||||
@@ -58,22 +58,29 @@
|
||||
<Icon @name="folder" class="has-text-grey-light" />{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
<li class="action">
|
||||
<LinkTo @route="scope" @model={{list.item.id}} class="is-block">
|
||||
View scope
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{#if list.item.updatePath.isPending}}
|
||||
<li class="action">
|
||||
<LoadingDropdownOption />
|
||||
</li>
|
||||
{{else if list.item.updatePath.canDelete}}
|
||||
<ConfirmAction
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Delete scope"
|
||||
<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}} />
|
||||
{{#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.showConfirmModal) true)}}
|
||||
data-test-confirm-action-trigger
|
||||
/>
|
||||
{{/if}}
|
||||
</Hds::Dropdown>
|
||||
{{#if this.showConfirmModal}}
|
||||
<ConfirmModal
|
||||
@color="critical"
|
||||
@confirmTitle="Delete scope {{list.item.id}}?"
|
||||
@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
|
||||
Item.callMethod
|
||||
"destroyRecord"
|
||||
|
||||
@@ -37,43 +37,40 @@
|
||||
<span data-test-role={{role.name}}>{{role.name}}</span>
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#if role.rolesPath.isLoading}}
|
||||
<li class="action">
|
||||
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} />
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="action">
|
||||
<LinkTo
|
||||
class="has-text-black has-text-weight-semibold"
|
||||
data-test-details
|
||||
@route="roles.role.details"
|
||||
@model={{role}}
|
||||
@disabled={{eq role.canRead false}}
|
||||
>
|
||||
Details
|
||||
</LinkTo>
|
||||
</li>
|
||||
<li class="action">
|
||||
<LinkTo
|
||||
class="has-text-black has-text-weight-semibold"
|
||||
data-test-edit
|
||||
@route="roles.role.edit"
|
||||
@model={{role}}
|
||||
@disabled={{not role.canEdit}}
|
||||
>
|
||||
Edit
|
||||
</LinkTo>
|
||||
</li>
|
||||
<ConfirmAction
|
||||
data-test-delete
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Delete"
|
||||
@confirmMessage="Deleting this role means that you’ll need to recreate it in order to generate credentials again."
|
||||
@onConfirmAction={{fn this.onDelete role}}
|
||||
/>
|
||||
{{#if (or role.canRead role.canEdit role.canDelete)}}
|
||||
<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.canRead}}
|
||||
<dd.Interactive @text="Details" @route="roles.role.details" @model={{role}} data-test-details />
|
||||
{{/if}}
|
||||
{{#if role.canEdit}}
|
||||
<dd.Interactive @text="Edit" data-test-edit @route="roles.role.edit" @model={{role}} />
|
||||
{{/if}}
|
||||
{{#if role.canDelete}}
|
||||
<dd.Interactive
|
||||
@text="Delete"
|
||||
data-test-delete
|
||||
@color="critical"
|
||||
{{on "click" (fn (mut this.roleToDelete) role)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Hds::Dropdown>
|
||||
{{/if}}
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
{{/each}}
|
||||
{{#if this.roleToDelete}}
|
||||
<ConfirmModal
|
||||
@color="critical"
|
||||
@confirmMessage="Deleting this role means that you’ll need to recreate it in order to generate credentials again."
|
||||
@onConfirm={{fn this.onDelete this.roleToDelete}}
|
||||
@onClose={{fn (mut this.roleToDelete) null}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -8,6 +8,7 @@ import { service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
import errorMessage from 'vault/utils/error-message';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* @module Roles
|
||||
@@ -20,6 +21,7 @@ import errorMessage from 'vault/utils/error-message';
|
||||
*/
|
||||
export default class RolesPageComponent extends Component {
|
||||
@service flashMessages;
|
||||
@tracked roleToDelete = null;
|
||||
|
||||
get mountPoint() {
|
||||
return getOwner(this).mountPoint;
|
||||
@@ -35,6 +37,8 @@ export default class RolesPageComponent extends Component {
|
||||
} catch (error) {
|
||||
const message = errorMessage(error, 'Error deleting role. Please try again or contact support');
|
||||
this.flashMessages.danger(message);
|
||||
} finally {
|
||||
this.roleToDelete = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,46 +49,40 @@
|
||||
<span data-test-library={{library.name}}>{{library.name}}</span>
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#if library.libraryPath.isLoading}}
|
||||
<li class="action">
|
||||
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} />
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="action">
|
||||
<LinkTo
|
||||
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 (or library.canRead library.canEdit library.canDelete)}}
|
||||
<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}}
|
||||
{{#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}}
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
{{/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>
|
||||
{{/if}}
|
||||
@@ -26,6 +26,7 @@ export default class LdapLibrariesPageComponent extends Component<Args> {
|
||||
@service declare readonly flashMessages: FlashMessageService;
|
||||
|
||||
@tracked filterValue = '';
|
||||
@tracked libraryToDelete: LdapLibraryModel | null = null;
|
||||
|
||||
get mountPoint(): string {
|
||||
const owner = getOwner(this) as EngineOwner;
|
||||
|
||||
@@ -50,70 +50,63 @@
|
||||
<Hds::Badge @text={{role.type}} data-test-role-type-badge={{role.name}} />
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#if role.rolePath.isLoading}}
|
||||
<li class="action">
|
||||
<Hds::Button disabled @color="tertiary" @icon="loading" @text="loading" @isIconOnly={{true}} />
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="action">
|
||||
<LinkTo
|
||||
class="has-text-black has-text-weight-semibold"
|
||||
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"
|
||||
<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}} />
|
||||
{{/if}}
|
||||
{{#if role.canReadCreds}}
|
||||
<dd.Interactive
|
||||
@text="Get credentials"
|
||||
data-test-get-creds
|
||||
@route="roles.role.credentials"
|
||||
@models={{array role.type role.name}}
|
||||
@disabled={{not role.canReadCreds}}
|
||||
>
|
||||
Get credentials
|
||||
</LinkTo>
|
||||
</li>
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if role.canRotateStaticCreds}}
|
||||
<ConfirmAction
|
||||
<dd.Interactive
|
||||
@text="Rotate credentials"
|
||||
data-test-rotate-creds
|
||||
@isInDropdown={{true}}
|
||||
@id={{concat "rotate-" role.id}}
|
||||
@buttonText="Rotate credentials"
|
||||
@confirmMessage="When manually rotating credentials, the rotation period will start over."
|
||||
@modalColor="warning"
|
||||
@onConfirmAction={{fn this.onRotate role}}
|
||||
@color="critical"
|
||||
{{on "click" (fn (mut this.credsToRotate) role)}}
|
||||
/>
|
||||
{{/if}}
|
||||
<li class="action">
|
||||
<LinkTo
|
||||
class="has-text-black has-text-weight-semibold"
|
||||
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}}
|
||||
@disabled={{not role.canRead}}
|
||||
>
|
||||
Details
|
||||
</LinkTo>
|
||||
</li>
|
||||
<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}}
|
||||
/>
|
||||
{{#if role.canDelete}}
|
||||
<ConfirmAction
|
||||
<dd.Interactive
|
||||
@text="Delete"
|
||||
data-test-delete
|
||||
@isInDropdown={{true}}
|
||||
@buttonText="Delete"
|
||||
@confirmMessage="Deleting this role means that you’ll need to recreate it in order to generate credentials again."
|
||||
@onConfirmAction={{fn this.onDelete role}}
|
||||
@color="critical"
|
||||
{{on "click" (fn (mut this.roleToDelete) role)}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</Hds::Dropdown>
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
{{/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 you’ll 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
|
||||
@currentPage={{@roles.meta.currentPage}}
|
||||
@currentPageSize={{@roles.meta.pageSize}}
|
||||
|
||||
@@ -15,6 +15,7 @@ import type FlashMessageService from 'vault/services/flash-messages';
|
||||
import type { Breadcrumb, EngineOwner } from 'vault/vault/app-types';
|
||||
import type RouterService from '@ember/routing/router-service';
|
||||
import type StoreService from 'vault/services/store';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
interface Args {
|
||||
roles: Array<LdapRoleModel>;
|
||||
@@ -28,6 +29,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
|
||||
@service declare readonly flashMessages: FlashMessageService;
|
||||
@service declare readonly router: RouterService;
|
||||
@service declare readonly store: StoreService;
|
||||
@tracked credsToRotate: LdapRoleModel | null = null;
|
||||
@tracked roleToDelete: LdapRoleModel | null = null;
|
||||
|
||||
get mountPoint(): string {
|
||||
const owner = getOwner(this) as EngineOwner;
|
||||
@@ -51,6 +54,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
|
||||
this.flashMessages.success(message);
|
||||
} catch (error) {
|
||||
this.flashMessages.danger(`Error rotating credentials \n ${errorMessage(error)}`);
|
||||
} finally {
|
||||
this.credsToRotate = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +69,8 @@ export default class LdapRolesPageComponent extends Component<Args> {
|
||||
this.flashMessages.success(message);
|
||||
} catch (error) {
|
||||
this.flashMessages.danger(`Error deleting role \n ${errorMessage(error)}`);
|
||||
} finally {
|
||||
this.roleToDelete = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
</code>
|
||||
</Item.content>
|
||||
|
||||
<Item.menu @hasMenu={{false}}>
|
||||
<Item.menu>
|
||||
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" as |dd|>
|
||||
<dd.ToggleIcon
|
||||
@icon="more-horizontal"
|
||||
|
||||
@@ -31,7 +31,7 @@ export default class SyncSecretsDestinationsPageComponent extends Component<Args
|
||||
@service declare readonly store: StoreService;
|
||||
@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
|
||||
// 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
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</Item.content>
|
||||
|
||||
<Item.menu @hasMenu={{false}}>
|
||||
<Item.menu>
|
||||
<Hds::Dropdown @isInline={{true}} @listPosition="bottom-right" @width="210px" as |dd|>
|
||||
<dd.ToggleIcon
|
||||
@icon="more-horizontal"
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class SyncSecretsDestinationsPageComponent extends Component<Args
|
||||
@service declare readonly store: StoreService;
|
||||
@service declare readonly flashMessages: FlashMessageService;
|
||||
|
||||
@tracked secretToUnsync = null;
|
||||
@tracked secretToUnsync: SyncAssociationModel | null = null;
|
||||
|
||||
get mountPoint(): string {
|
||||
const owner = getOwner(this) as EngineOwner;
|
||||
|
||||
@@ -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 mountSecrets from 'vault/tests/pages/settings/mount-secret-backend';
|
||||
import { allEngines } from 'vault/helpers/mountable-secret-engines';
|
||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
|
||||
import { runCmd } from 'vault/tests/helpers/commands';
|
||||
|
||||
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) {
|
||||
// Popup menu causes flakiness
|
||||
setRunOptions({
|
||||
rules: {
|
||||
'color-contrast': { enabled: false },
|
||||
},
|
||||
});
|
||||
const { path, scope, role } = await generateCreds();
|
||||
await credentialsPage.visit({ backend: path, scope, role });
|
||||
// revoke the credentials
|
||||
|
||||
@@ -10,7 +10,6 @@ import kubernetesScenario from 'vault/mirage/scenarios/kubernetes';
|
||||
import kubernetesHandlers from 'vault/mirage/handlers/kubernetes';
|
||||
import authPage from 'vault/tests/pages/auth';
|
||||
import { fillIn, visit, currentURL, click, currentRouteName } from '@ember/test-helpers';
|
||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
|
||||
|
||||
module('Acceptance | kubernetes | roles', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -55,12 +54,6 @@ module('Acceptance | kubernetes | roles', function (hooks) {
|
||||
});
|
||||
|
||||
test('it should have functional list item menu', async function (assert) {
|
||||
// Popup menu causes flakiness
|
||||
setRunOptions({
|
||||
rules: {
|
||||
'color-contrast': { enabled: false },
|
||||
},
|
||||
});
|
||||
assert.expect(3);
|
||||
await this.visitRoles();
|
||||
for (const action of ['details', 'edit', 'delete']) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
|
||||
import authPage from 'vault/tests/pages/auth';
|
||||
import { click } from '@ember/test-helpers';
|
||||
import { isURL, visitURL } from 'vault/tests/helpers/ldap';
|
||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
|
||||
|
||||
module('Acceptance | ldap | libraries', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -38,12 +37,6 @@ module('Acceptance | ldap | libraries', function (hooks) {
|
||||
});
|
||||
|
||||
test('it should transition to routes from list item action menu', async function (assert) {
|
||||
// Popup menu causes flakiness
|
||||
setRunOptions({
|
||||
rules: {
|
||||
'color-contrast': { enabled: false },
|
||||
},
|
||||
});
|
||||
assert.expect(2);
|
||||
|
||||
for (const action of ['edit', 'details']) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
|
||||
import authPage from 'vault/tests/pages/auth';
|
||||
import { click, fillIn } from '@ember/test-helpers';
|
||||
import { isURL, visitURL } from 'vault/tests/helpers/ldap';
|
||||
import { setRunOptions } from 'ember-a11y-testing/test-support';
|
||||
|
||||
module('Acceptance | ldap | roles', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -45,12 +44,6 @@ module('Acceptance | ldap | roles', function (hooks) {
|
||||
});
|
||||
|
||||
test('it should transition to routes from list item action menu', async function (assert) {
|
||||
// Popup menu causes flakiness
|
||||
setRunOptions({
|
||||
rules: {
|
||||
'color-contrast': { enabled: false },
|
||||
},
|
||||
});
|
||||
assert.expect(3);
|
||||
|
||||
for (const action of ['edit', 'get-creds', 'details']) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { setupEngine } from 'ember-engines/test-support';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { render, click } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
|
||||
|
||||
module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
@@ -17,6 +18,7 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.server.post('/sys/capabilities-self', allowAllCapabilitiesStub(['read', 'update', 'delete']));
|
||||
this.store.pushPayload('secret-engine', {
|
||||
modelName: 'secret-engine',
|
||||
data: {
|
||||
@@ -88,11 +90,6 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
|
||||
});
|
||||
|
||||
test('it should render roles list', async function (assert) {
|
||||
this.server.post('/sys/capabilities-self', () => ({
|
||||
data: {
|
||||
'kubernetes/role': ['root'],
|
||||
},
|
||||
}));
|
||||
await this.renderComponent();
|
||||
assert.dom('[data-test-list-item-content] svg').hasClass('flight-icon-user', 'List item icon renders');
|
||||
assert
|
||||
|
||||
Reference in New Issue
Block a user