mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
UI: Allow navigate to list from View Secret card (#22502)
This commit is contained in:
3
changelog/22502.txt
Normal file
3
changelog/22502.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
ui: KV View Secret card will link to list view if input ends in "/"
|
||||||
|
```
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
* @param {string} backend - Passed to SearchSelect query method to fetch dropdown options
|
* @param {string} backend - Passed to SearchSelect query method to fetch dropdown options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TODO: kv engine cleanup remove secrets related logic
|
||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
@@ -32,18 +33,38 @@ export default class GetCredentialsCard extends Component {
|
|||||||
@tracked role = '';
|
@tracked role = '';
|
||||||
@tracked secret = '';
|
@tracked secret = '';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.secret = this.args?.initialValue || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
get buttonText() {
|
||||||
|
if (this.args.type === 'secret') {
|
||||||
|
if (this.secret.endsWith('/')) {
|
||||||
|
return 'View list';
|
||||||
|
}
|
||||||
|
return 'View secret';
|
||||||
|
}
|
||||||
|
return 'Get credentials';
|
||||||
|
}
|
||||||
|
|
||||||
get buttonDisabled() {
|
get buttonDisabled() {
|
||||||
return !this.role && !this.secret;
|
return !this.role && !this.secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
transitionToCredential() {
|
transitionToCredential(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
const role = this.role;
|
const role = this.role;
|
||||||
const secret = this.secret;
|
const secret = this.secret;
|
||||||
if (role) {
|
if (role) {
|
||||||
this.router.transitionTo('vault.cluster.secrets.backend.credentials', role);
|
this.router.transitionTo('vault.cluster.secrets.backend.credentials', role);
|
||||||
}
|
}
|
||||||
if (secret) {
|
if (secret) {
|
||||||
|
if (secret.endsWith('/')) {
|
||||||
|
this.router.transitionTo('vault.cluster.secrets.backend.list', secret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.router.transitionTo('vault.cluster.secrets.backend.show', secret);
|
this.router.transitionTo('vault.cluster.secrets.backend.show', secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
SPDX-License-Identifier: BUSL-1.1
|
SPDX-License-Identifier: BUSL-1.1
|
||||||
~}}
|
~}}
|
||||||
|
|
||||||
<form class="selectable-card is-rounded no-flex data-test-get-credentials-card">
|
<form {{on "submit" this.transitionToCredential}} class="selectable-card is-rounded no-flex data-test-get-credentials-card">
|
||||||
<div class="is-flex-between is-fullwidth card-details">
|
<div class="is-flex-between is-fullwidth card-details">
|
||||||
<h3 class="title is-5">{{@title}}</h3>
|
<h3 class="title is-5">{{@title}}</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
@id="search-input-{{@type}}"
|
@id="search-input-{{@type}}"
|
||||||
@onChange={{this.handleInput}}
|
@onChange={{this.handleInput}}
|
||||||
@placeholder={{@placeholder}}
|
@placeholder={{@placeholder}}
|
||||||
|
@initialValue={{@initialValue}}
|
||||||
data-test-search-roles
|
data-test-search-roles
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
@@ -30,13 +31,7 @@
|
|||||||
data-test-search-roles
|
data-test-search-roles
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<button
|
<button type="submit" class="button is-secondary" disabled={{this.buttonDisabled}} data-test-get-credentials>
|
||||||
type="button"
|
{{this.buttonText}}
|
||||||
class="button is-secondary"
|
|
||||||
disabled={{this.buttonDisabled}}
|
|
||||||
{{on "click" this.transitionToCredential}}
|
|
||||||
data-test-get-credentials
|
|
||||||
>
|
|
||||||
{{@title}}
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
@renderInputSearch={{true}}
|
@renderInputSearch={{true}}
|
||||||
@title="View secret"
|
@title="View secret"
|
||||||
@searchLabel="Secret path"
|
@searchLabel="Secret path"
|
||||||
@subText="Type the path of the secret you want to read"
|
@subText="Type the path of the secret you want to view. Include a trailing slash to navigate to the list view."
|
||||||
@placeholder="secret/"
|
@placeholder="secret/"
|
||||||
@backend="kv"
|
|
||||||
@type="secret"
|
@type="secret"
|
||||||
|
@initialValue={{this.baseKey.id}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ export default class inputSelect extends Component {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@tracked searchInput = '';
|
@tracked searchInput = '';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.searchInput = this.args?.initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
inputChanged() {
|
inputChanged() {
|
||||||
this.args.onChange(this.searchInput);
|
this.args.onChange(this.searchInput);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ module('Integration | Component | get-credentials-card', function (hooks) {
|
|||||||
test('it shows a disabled button when no item is selected', async function (assert) {
|
test('it shows a disabled button when no item is selected', async function (assert) {
|
||||||
await render(hbs`<GetCredentialsCard @title={{this.title}} @searchLabel={{this.searchLabel}}/>`);
|
await render(hbs`<GetCredentialsCard @title={{this.title}} @searchLabel={{this.searchLabel}}/>`);
|
||||||
assert.dom('[data-test-get-credentials]').isDisabled();
|
assert.dom('[data-test-get-credentials]').isDisabled();
|
||||||
|
assert.dom('[data-test-get-credentials]').hasText('Get credentials', 'Button has default text');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it shows button that can be clicked to credentials route when an item is selected', async function (assert) {
|
test('it shows button that can be clicked to credentials route when an item is selected', async function (assert) {
|
||||||
@@ -89,6 +90,7 @@ module('Integration | Component | get-credentials-card', function (hooks) {
|
|||||||
);
|
);
|
||||||
await typeIn('[data-test-search-roles] input', 'test');
|
await typeIn('[data-test-search-roles] input', 'test');
|
||||||
assert.dom('[data-test-get-credentials]').isEnabled('submit button enables after typing input text');
|
assert.dom('[data-test-get-credentials]').isEnabled('submit button enables after typing input text');
|
||||||
|
assert.dom('[data-test-get-credentials]').hasText('View secret', 'Button has view secret CTA');
|
||||||
await click('[data-test-get-credentials]');
|
await click('[data-test-get-credentials]');
|
||||||
assert.propEqual(
|
assert.propEqual(
|
||||||
this.router.transitionTo.lastCall.args,
|
this.router.transitionTo.lastCall.args,
|
||||||
@@ -96,4 +98,44 @@ module('Integration | Component | get-credentials-card', function (hooks) {
|
|||||||
'transitionTo is called with correct route and secret name'
|
'transitionTo is called with correct route and secret name'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it prefills input if initialValue has value', async function (assert) {
|
||||||
|
await render(
|
||||||
|
hbs`<GetCredentialsCard @title={{this.title}} @renderInputSearch={{true}} @placeholder="secret/" @backend="kv" @type="secret" @initialValue="hello/"/>`
|
||||||
|
);
|
||||||
|
assert
|
||||||
|
.dom('[data-test-component="search-select"]')
|
||||||
|
.doesNotExist('does not render search select component');
|
||||||
|
assert.dom('[data-test-search-roles] input').hasValue('hello/', 'pre-fills search input');
|
||||||
|
assert.dom('[data-test-get-credentials]').isEnabled('submit button is enabled at render');
|
||||||
|
assert.dom('[data-test-get-credentials]').hasText('View list', 'Button has list CTA');
|
||||||
|
await typeIn('[data-test-search-roles] input', 'test');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-get-credentials]')
|
||||||
|
.hasText('View secret', 'Button has view secret CTA after input');
|
||||||
|
await click('[data-test-get-credentials]');
|
||||||
|
assert.propEqual(
|
||||||
|
this.router.transitionTo.lastCall.args,
|
||||||
|
['vault.cluster.secrets.backend.show', 'hello/test'],
|
||||||
|
'transitionTo is called with correct route and secret name'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it goes to list route if input ends in / and type=secret', async function (assert) {
|
||||||
|
await render(
|
||||||
|
hbs`<GetCredentialsCard @title={{this.title}} @renderInputSearch={{true}} @placeholder="secret/" @backend="kv" @type="secret" />`
|
||||||
|
);
|
||||||
|
assert
|
||||||
|
.dom('[data-test-component="search-select"]')
|
||||||
|
.doesNotExist('does not render search select component');
|
||||||
|
await typeIn('[data-test-search-roles] input', 'test/');
|
||||||
|
assert.dom('[data-test-get-credentials]').hasText('View list', 'submit button has list CTA');
|
||||||
|
assert.dom('[data-test-get-credentials]').isEnabled('submit button is enabled at render');
|
||||||
|
await click('[data-test-get-credentials]');
|
||||||
|
assert.propEqual(
|
||||||
|
this.router.transitionTo.lastCall.args,
|
||||||
|
['vault.cluster.secrets.backend.list', 'test/'],
|
||||||
|
'transitionTo is called with correct route and secret name'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user