mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +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
	 Chelsea Shaw
					Chelsea Shaw