mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	UI - make engine list more consistent with the auth method list (#4598)
* remove expanding behavior from engines list and add a configuration route * use page header component, secret tab component for the template on the secret engine configuration route * move abstraction to secret-list-header and remove secret-tabs * add attrs to secret engine model and adjust mount controller code to support that * fix top level nav so that we can use the back button properly * fix tests
This commit is contained in:
		
							
								
								
									
										5
									
								
								ui/app/components/page-header-level-left.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ui/app/components/page-header-level-left.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Component.extend({ | ||||
|   tagName: '', | ||||
| }); | ||||
							
								
								
									
										5
									
								
								ui/app/components/page-header-level-right.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ui/app/components/page-header-level-right.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Component.extend({ | ||||
|   tagName: '', | ||||
| }); | ||||
							
								
								
									
										5
									
								
								ui/app/components/page-header-top.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ui/app/components/page-header-top.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Component.extend({ | ||||
|   tagName: '', | ||||
| }); | ||||
							
								
								
									
										6
									
								
								ui/app/components/page-header.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ui/app/components/page-header.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Component.extend({ | ||||
|   tagName: '', | ||||
|   hasLevel: true, | ||||
| }); | ||||
							
								
								
									
										14
									
								
								ui/app/components/secret-list-header.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ui/app/components/secret-list-header.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Component.extend({ | ||||
|   tagName: '', | ||||
|  | ||||
|   // api | ||||
|   isCertTab: false, | ||||
|   isConfigure: false, | ||||
|   baseKey: null, | ||||
|   backendCrumb: null, | ||||
|   model: null, | ||||
|  | ||||
|  | ||||
| }); | ||||
| @@ -30,7 +30,6 @@ export default Ember.Controller.extend({ | ||||
|   description: null, | ||||
|   default_lease_ttl: null, | ||||
|   max_lease_ttl: null, | ||||
|   force_no_cache: null, | ||||
|   showConfig: false, | ||||
|   local: false, | ||||
|   sealWrap: false, | ||||
| @@ -50,7 +49,6 @@ export default Ember.Controller.extend({ | ||||
|       description: null, | ||||
|       default_lease_ttl: null, | ||||
|       max_lease_ttl: null, | ||||
|       force_no_cache: null, | ||||
|       local: false, | ||||
|       showConfig: false, | ||||
|       sealWrap: false, | ||||
| @@ -82,7 +80,6 @@ export default Ember.Controller.extend({ | ||||
|         selectedType: type, | ||||
|         description, | ||||
|         default_lease_ttl, | ||||
|         force_no_cache, | ||||
|         local, | ||||
|         max_lease_ttl, | ||||
|         sealWrap, | ||||
| @@ -92,7 +89,6 @@ export default Ember.Controller.extend({ | ||||
|         'selectedType', | ||||
|         'description', | ||||
|         'default_lease_ttl', | ||||
|         'force_no_cache', | ||||
|         'local', | ||||
|         'max_lease_ttl', | ||||
|         'sealWrap', | ||||
| @@ -112,9 +108,8 @@ export default Ember.Controller.extend({ | ||||
|  | ||||
|       if (this.get('showConfig')) { | ||||
|         attrs.config = { | ||||
|           default_lease_ttl, | ||||
|           max_lease_ttl, | ||||
|           force_no_cache, | ||||
|           defaultLeaseTtl: default_lease_ttl, | ||||
|           maxLeaseTtl: max_lease_ttl, | ||||
|         }; | ||||
|       } | ||||
|  | ||||
|   | ||||
| @@ -2,5 +2,7 @@ import attr from 'ember-data/attr'; | ||||
| import Fragment from 'ember-data-model-fragments/fragment'; | ||||
|  | ||||
| export default Fragment.extend({ | ||||
|   version: attr('number'), | ||||
|   version: attr('number', { | ||||
|     label: 'Version', | ||||
|   }), | ||||
| }); | ||||
|   | ||||
| @@ -3,6 +3,8 @@ import DS from 'ember-data'; | ||||
| import { queryRecord } from 'ember-computed-query'; | ||||
| import { fragment } from 'ember-data-model-fragments/attributes'; | ||||
|  | ||||
| import { expandAttributeMeta } from 'vault/utils/field-to-attrs'; | ||||
|  | ||||
| const { attr } = DS; | ||||
| const { computed } = Ember; | ||||
|  | ||||
| @@ -16,11 +18,26 @@ export default DS.Model.extend({ | ||||
|   name: attr('string'), | ||||
|   type: attr('string'), | ||||
|   description: attr('string'), | ||||
|   config: attr('object'), | ||||
|   options: fragment('mount-options'), | ||||
|   config: fragment('mount-config', { defaultValue: {} }), | ||||
|   options: fragment('mount-options', { defaultValue: {} }), | ||||
|   local: attr('boolean'), | ||||
|   sealWrap: attr('boolean'), | ||||
|  | ||||
|   formFields: [ | ||||
|     'type', | ||||
|     'path', | ||||
|     'description', | ||||
|     'accessor', | ||||
|     'local', | ||||
|     'sealWrap', | ||||
|     'config.{defaultLeaseTtl,maxLeaseTtl}', | ||||
|     'options.{version}', | ||||
|   ], | ||||
|  | ||||
|   attrs: computed('formFields', function() { | ||||
|     return expandAttributeMeta(this, this.get('formFields')); | ||||
|   }), | ||||
|  | ||||
|   shouldIncludeInList: computed('type', function() { | ||||
|     return !LIST_EXCLUDED_BACKENDS.includes(this.get('type')); | ||||
|   }), | ||||
|   | ||||
| @@ -68,6 +68,7 @@ Router.map(function() { | ||||
|         this.route('backends', { path: '/' }); | ||||
|         this.route('backend', { path: '/:backend' }, function() { | ||||
|           this.route('index', { path: '/' }); | ||||
|           this.route('configuration'); | ||||
|           // because globs / params can't be empty, | ||||
|           // we have to special-case ids of '' with thier own routes | ||||
|           this.route('list-root', { path: '/list/' }); | ||||
|   | ||||
| @@ -0,0 +1,7 @@ | ||||
| import Ember from 'ember'; | ||||
|  | ||||
| export default Ember.Route.extend({ | ||||
|   model() { | ||||
|     return this.modelFor('vault.cluster.secrets.backend'); | ||||
|   }, | ||||
| }); | ||||
| @@ -20,8 +20,7 @@ | ||||
|   } | ||||
| } | ||||
| .popup-menu-trigger { | ||||
|   width: 3rem; | ||||
|   height: 2rem; | ||||
|   min-width: auto; | ||||
| } | ||||
| .popup-menu-trigger.is-active { | ||||
|   &, | ||||
|   | ||||
| @@ -146,7 +146,6 @@ $button-box-shadow-standard: 0 3px 1px 0 rgba($black, 0.12); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &.is-more-icon, | ||||
|   &.tool-tip-trigger { | ||||
|     color: $black; | ||||
|     min-width: auto; | ||||
|   | ||||
| @@ -40,7 +40,7 @@ | ||||
|           {{/if}} | ||||
|         </li> | ||||
|         <li class="{{if (is-active-route (array 'vault.cluster.policies' 'vault.cluster.policy')) 'is-active'}}"> | ||||
|           <a href="{{href-to "vault.cluster.policies" activeClusterName current-when='vault.cluster.policies vault.cluster.policy'}}"> | ||||
|           <a href="{{href-to "vault.cluster.policies" "acl" current-when='vault.cluster.policies vault.cluster.policy'}}"> | ||||
|             Policies | ||||
|           </a> | ||||
|         </li> | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| <ul> | ||||
|   {{yield}} | ||||
|   {{#each secretPath as |path index|}} | ||||
|     <li class="{{if (is-active-route path.path path.model isExact=true) 'is-active'}}"> | ||||
|       <span class="sep">/</span> | ||||
|   | ||||
							
								
								
									
										1
									
								
								ui/app/templates/components/page-header-level-left.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ui/app/templates/components/page-header-level-left.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| {{yield}} | ||||
							
								
								
									
										1
									
								
								ui/app/templates/components/page-header-level-right.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ui/app/templates/components/page-header-level-right.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| {{yield}} | ||||
							
								
								
									
										15
									
								
								ui/app/templates/components/page-header.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ui/app/templates/components/page-header.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| <header class="page-header"> | ||||
|   {{#if hasLevel}} | ||||
|     {{yield (hash top=(component 'page-header-top'))}} | ||||
|     <div class="level"> | ||||
|       <div class="level-left"> | ||||
|         {{yield (hash levelLeft=(component 'page-header-level-left'))}} | ||||
|       </div> | ||||
|       <div class="level-right field is-grouped"> | ||||
|         {{yield (hash levelRight=(component 'page-header-level-right'))}} | ||||
|       </div> | ||||
|     </div> | ||||
|   {{else}} | ||||
|     {{yield (hash top=(component 'page-header-top'))}} | ||||
|   {{/if}} | ||||
| </header> | ||||
| @@ -1,5 +1,5 @@ | ||||
| {{#basic-dropdown class="popup-menu" horizontalPosition="auto-right" verticalPosition="below" onOpen=onOpen as |d|}} | ||||
|   {{#d.trigger tagName="button" class=(concat "popup-menu-trigger button is-transparent " (if d.isOpen "is-active")) data-test-popup-menu-trigger=true}} | ||||
|   {{#d.trigger tagName="button" class=(concat "popup-menu-trigger button is-ghost " (if d.isOpen "is-active")) data-test-popup-menu-trigger=true}} | ||||
|     {{i-con | ||||
|       glyph="more" | ||||
|       class="has-text-black auto-width" | ||||
|   | ||||
							
								
								
									
										108
									
								
								ui/app/templates/components/secret-list-header.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								ui/app/templates/components/secret-list-header.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| {{#with (options-for-backend model.type) as |options|}} | ||||
|   {{#page-header as |p|}} | ||||
|     {{#p.top}} | ||||
|       {{#key-value-header | ||||
|         baseKey=baseKey | ||||
|         path="vault.cluster.secrets.backend.list" | ||||
|         root=backendCrumb | ||||
|       }} | ||||
|         <li> | ||||
|           <span class="sep">/</span> | ||||
|           <a href={{href-to "vault.cluster.secrets"}}> | ||||
|             secrets | ||||
|           </a> | ||||
|         </li> | ||||
|       {{/key-value-header}} | ||||
|     {{/p.top}} | ||||
|     {{#p.levelLeft}} | ||||
|       <h1 class="title is-3"> | ||||
|         {{model.id}} | ||||
|         <span class="tag is-outlined is-inverted has-text-grey-dark is-font-mono"> | ||||
|           {{or options.displayName (capitalize model.type)}} | ||||
|         </span> | ||||
|         {{#if (eq model.options.version 2)}} | ||||
|           <span class="has-text-grey-dark has-text-weight-normal is-size-6"> | ||||
|             Version 2 | ||||
|           </span> | ||||
|         {{/if}} | ||||
|       </h1> | ||||
|     {{/p.levelLeft}} | ||||
|     {{#p.levelRight}} | ||||
|        {{#unless (or isCertTab isConfigure)}} | ||||
|           <div class="control"> | ||||
|             {{#secret-link | ||||
|               mode="create" | ||||
|               secret=(or baseKey.id '') | ||||
|               queryParams=(query-params initialKey='') | ||||
|               class="button has-icon-right is-ghost is-compact" | ||||
|               data-test-secret-create=true | ||||
|             }} | ||||
|               {{options.create}} | ||||
|               {{i-con glyph="chevron-right" size=11}} | ||||
|             {{/secret-link}} | ||||
|           </div> | ||||
|         {{/unless}} | ||||
|       {{#if (or (eq model.type "aws") (eq model.type "ssh") (eq model.type "pki"))}} | ||||
|         <div class="control"> | ||||
|           <a href={{href-to | ||||
|               "vault.cluster.settings.configure-secret-backend" | ||||
|               model.id | ||||
|             }} | ||||
|             class="button has-icon-right is-ghost is-compact" | ||||
|             data-test-secret-backend-configure=true | ||||
|             > | ||||
|               Configure {{i-con glyph="chevron-right" size=11}} | ||||
|           </a> | ||||
|         </div> | ||||
|       {{/if}} | ||||
|     {{/p.levelRight}} | ||||
|   {{/page-header}} | ||||
|   {{#if options.tabs}} | ||||
|     <div class="box is-bottomless is-marginless is-fullwidth is-paddingless"> | ||||
|       <nav class="tabs sub-nav"> | ||||
|         <ul> | ||||
|           {{#each options.tabs as |oTab|}} | ||||
|             {{#if oTab.tab}} | ||||
|               {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab=oTab.tab) tagName="li" activeClass="is-active" data-test-tab=oTab.label}} | ||||
|                 {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab=oTab.tab)}} | ||||
|                   {{oTab.label}} | ||||
|                 {{/link-to}} | ||||
|               {{/link-to}} | ||||
|             {{else}} | ||||
|               {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab='') tagName="li" activeClass="is-active" data-test-tab=oTab.label}} | ||||
|                 {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab='')}} | ||||
|                   {{oTab.label}} | ||||
|                 {{/link-to}} | ||||
|               {{/link-to}} | ||||
|             {{/if}} | ||||
|           {{/each}} | ||||
|           {{#link-to 'vault.cluster.secrets.backend.configuration' tagName="li" activeClass="is-active"}} | ||||
|             {{#link-to 'vault.cluster.secrets.backend.configuration' }} | ||||
|               Configuration | ||||
|             {{/link-to}} | ||||
|           {{/link-to}} | ||||
|         </ul> | ||||
|       </nav> | ||||
|     </div> | ||||
|   {{else}} | ||||
|     {{!-- if there are no tabs in the options, we'll hardcode them here --}} | ||||
|     <div class="box is-bottomless is-marginless is-fullwidth is-paddingless"> | ||||
|       <nav class="tabs sub-nav"> | ||||
|         <ul> | ||||
|           {{#if (contains model.type (supported-secret-backends))}} | ||||
|             {{#link-to 'vault.cluster.secrets.backend.list-root' tagName="li" activeClass="is-active" current-when="vault.cluster.secrets.backend.list-root vault.cluster.secrets.backend.list"}} | ||||
|               {{#link-to 'vault.cluster.secrets.backend.list-root'}} | ||||
|                 {{capitalize (pluralize options.item)}} | ||||
|               {{/link-to}} | ||||
|             {{/link-to}} | ||||
|           {{/if}} | ||||
|           {{#link-to 'vault.cluster.secrets.backend.configuration' tagName="li" activeClass="is-active"}} | ||||
|             {{#link-to 'vault.cluster.secrets.backend.configuration' }} | ||||
|               Configuration | ||||
|             {{/link-to}} | ||||
|           {{/link-to}} | ||||
|         </ul> | ||||
|       </nav> | ||||
|     </div> | ||||
|   {{/if}} | ||||
| {{/with}} | ||||
| @@ -0,0 +1,19 @@ | ||||
| {{secret-list-header model=model isConfigure=true backendCrumb=(hash label=model.id text=model.id path="vault.cluster.secrets.backend.list-root" model=model.id)}} | ||||
|  | ||||
| <div class="box is-fullwidth is-sideless is-paddingless is-marginless"> | ||||
|   {{#each model.attrs as |attr|}} | ||||
|     {{#if (eq attr.type "object")}} | ||||
|       {{info-table-row | ||||
|         alwaysRender=true | ||||
|         label=(or attr.options.label (to-label attr.name))  | ||||
|         value=(stringify (get model attr.name)) | ||||
|       }} | ||||
|     {{else}} | ||||
|       {{info-table-row | ||||
|         alwaysRender=(not-eq attr.name 'options.version') | ||||
|         label=(or attr.options.label (to-label attr.name)) | ||||
|         value=(get model attr.name) | ||||
|       }} | ||||
|     {{/if}} | ||||
|   {{/each}} | ||||
| </div> | ||||
| @@ -1,79 +1,6 @@ | ||||
| {{secret-list-header isCertTab=(eq tab "certs") model=backendModel baseKey=baseKey backendCrumb=backendCrumb}} | ||||
|  | ||||
| {{#with (options-for-backend backendType tab) as |options|}} | ||||
|   <header class="page-header"> | ||||
|     {{key-value-header | ||||
|       baseKey=baseKey | ||||
|       path="vault.cluster.secrets.backend.list" | ||||
|       root=backendCrumb | ||||
|     }} | ||||
|     <div class="level"> | ||||
|       <div class="level-left"> | ||||
|         <h1 class="title is-3"> | ||||
|           {{backend}} | ||||
|           <span class="tag is-outlined is-inverted has-text-grey-dark is-font-mono"> | ||||
|             {{or options.displayName (capitalize backendType)}} | ||||
|           </span> | ||||
|           {{#if (eq backendModel.options.version 2)}} | ||||
|             <span class="has-text-grey-dark has-text-weight-normal is-size-6"> | ||||
|               Version 2 | ||||
|             </span> | ||||
|           {{/if}} | ||||
|         </h1> | ||||
|       </div> | ||||
|       <div class="level-right field is-grouped"> | ||||
|         {{#if (not-eq tab "certs")}} | ||||
|           <div class="control"> | ||||
|             {{#secret-link | ||||
|               mode="create" | ||||
|               secret=(or baseKey.id '') | ||||
|               queryParams=(query-params initialKey='') | ||||
|               class="button has-icon-right is-ghost is-compact" | ||||
|               data-test-secret-create=true | ||||
|             }} | ||||
|               {{options.create}} | ||||
|               {{i-con glyph="chevron-right" size=11}} | ||||
|             {{/secret-link}} | ||||
|           </div> | ||||
|         {{/if}} | ||||
|         {{#if (or (eq backendType "aws") (eq backendType "ssh") (eq backendType "pki"))}} | ||||
|           <div class="control"> | ||||
|             <a href={{href-to | ||||
|               "vault.cluster.settings.configure-secret-backend" | ||||
|               backend | ||||
|               }} | ||||
|               class="button has-icon-right is-ghost is-compact" | ||||
|               data-test-secret-backend-configure=true | ||||
|               > | ||||
|               Configure | ||||
|               {{i-con glyph="chevron-right" size=11}} | ||||
|             </a> | ||||
|           </div> | ||||
|         {{/if}} | ||||
|       </div> | ||||
|     </div> | ||||
|   </header> | ||||
|   {{#if options.tabs}} | ||||
|     <div class="box is-bottomless is-marginless is-fullwidth is-paddingless"> | ||||
|       <nav class="tabs sub-nav"> | ||||
|         <ul> | ||||
|           {{#each options.tabs as |oTab|}} | ||||
|             {{#if oTab.tab}} | ||||
|               {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab=oTab.tab) tagName="li" activeClass="is-active" data-test-tab=oTab.label}} | ||||
|                 {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab=oTab.tab)}} | ||||
|                   {{oTab.label}} | ||||
|                 {{/link-to}} | ||||
|               {{/link-to}} | ||||
|             {{else}} | ||||
|               {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab='') tagName="li" activeClass="is-active" data-test-tab=oTab.label}} | ||||
|                 {{#link-to 'vault.cluster.secrets.backend.list-root' (query-params tab='')}} | ||||
|                   {{oTab.label}} | ||||
|                 {{/link-to}} | ||||
|               {{/link-to}} | ||||
|             {{/if}} | ||||
|           {{/each}} | ||||
|         </ul> | ||||
|       </nav> | ||||
|     </div> | ||||
|   {{/if}} | ||||
|   <div class="box is-sideless has-background-grey-lighter has-short-padding is-marginless"> | ||||
|     <div class="level"> | ||||
|       <div class="level-left"> | ||||
| @@ -90,17 +17,15 @@ | ||||
|            mode=(if (eq tab 'certs') 'secrets-cert' 'secrets') | ||||
|          }} | ||||
|          {{#if filterFocused}} | ||||
|              | ||||
|              | ||||
|           {{#if filterMatchesKey}} | ||||
|             {{#unless filterIsFolder}} | ||||
|               <p class="help has-text-grey is-size-8"> | ||||
|               <p class="input-hint"> | ||||
|                 <kbd>Enter</kbd> to view {{filter}} | ||||
|               </p> | ||||
|             {{/unless}} | ||||
|           {{/if}} | ||||
|           {{#if firstPartialMatch}} | ||||
|             <p class="help has-text-grey is-size-8"> | ||||
|             <p class="input-hint"> | ||||
|               <kbd>Tab</kbd> to autocomplete | ||||
|             </p> | ||||
|           {{/if}} | ||||
|   | ||||
| @@ -18,11 +18,8 @@ | ||||
|   {{#linked-block | ||||
|     "vault.cluster.secrets.backend.list-root" | ||||
|     backend.id | ||||
|     class=(concat | ||||
|       'box is-sideless is-marginless has-pointer ' | ||||
|       (if (get this (concat backend.accessor '-open')) 'has-background-white-bis') | ||||
|     ) | ||||
|     data-test-secret-backend-link=backend.id | ||||
|     class="box is-sideless is-marginless has-pointer" | ||||
|     data-test-secret-backend-row=backend.id | ||||
|   }} | ||||
|     <div class="level is-mobile"> | ||||
|       <div class="level-left"> | ||||
| @@ -53,25 +50,35 @@ | ||||
|       </div> | ||||
|       <div class="level-right is-flex is-paddingless is-marginless"> | ||||
|         <div class="level-item"> | ||||
|           <button class="button is-more-icon is-ghost" data-test-secret-backend-detail=true type="button" {{action (toggle (concat backend.accessor '-open') this)}}> | ||||
|             {{i-con glyph="more" size=16 aria-label=(concat backend.path ' details')}} | ||||
|           </button> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     {{#if (get this (concat backend.accessor '-open'))}} | ||||
|       {{partial "partials/backend-details"}} | ||||
|           {{#popup-menu name="engine-menu"}} | ||||
|              <nav class="menu"> | ||||
|                <ul class="menu-list"> | ||||
|                  <li class="action"> | ||||
|                    <a href="{{href-to 'vault.cluster.secrets.backend.configuration' backend.id}}"> | ||||
|                      View Configuration | ||||
|                    </a> | ||||
|                   </li> | ||||
|                  {{#if item.updatePath.isPending}} | ||||
|                    <li class="action"> | ||||
|                      <button disabled=true type="button" class="link button is-loading is-transparent"></button> | ||||
|                     </li> | ||||
|                  {{/if}} | ||||
|               </ul> | ||||
|             </nav> | ||||
|           {{/popup-menu}} | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   {{/linked-block}} | ||||
| {{/each}} | ||||
| {{#each unsupportedBackends as |backend|}} | ||||
|   <div class="box is-sideless is-marginless has-background-transition {{if (get this (concat backend.accessor '-open')) 'has-background-white-bis'}}" | ||||
|   <div class="box is-sideless is-marginless" | ||||
|        data-test-secret-backend-row={{backend.id}} | ||||
|     > | ||||
|     <div class="level is-mobile"> | ||||
|       <div class="level-left"> | ||||
|         <div> | ||||
|           <div class="has-text-weight-semibold"> | ||||
|           <div data-test-secret-path class="has-text-weight-semibold"> | ||||
|             {{i-con glyph="folder" size=14 class="has-text-grey-light"}} {{backend.path}} | ||||
|           </div> | ||||
|           <span class="tag"> | ||||
| @@ -90,14 +97,19 @@ | ||||
|       </div> | ||||
|       <div class="level-right is-flex is-paddingless is-marginless"> | ||||
|         <div class="level-item"> | ||||
|           <button class="button is-more-icon is-ghost" data-test-secret-backend-detail=true type="button" {{action (toggle (concat backend.accessor '-open') this)}}> | ||||
|             {{i-con glyph="more" size=16 aria-label=(concat backend.path ' details')}} | ||||
|           </button> | ||||
|           {{#popup-menu name="engine-menu"}} | ||||
|              <nav class="menu"> | ||||
|                <ul class="menu-list"> | ||||
|                  <li class="action"> | ||||
|                    <a href="{{href-to 'vault.cluster.secrets.backend.configuration' backend.id}}" data-test-engine-config> | ||||
|                      View Configuration | ||||
|                    </a> | ||||
|                  </li> | ||||
|                </ul> | ||||
|             </nav> | ||||
|           {{/popup-menu}} | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     {{#if (get this (concat backend.accessor '-open'))}} | ||||
|       {{partial "partials/backend-details"}} | ||||
|     {{/if}} | ||||
|   </div> | ||||
| {{/each}} | ||||
|   | ||||
| @@ -42,11 +42,12 @@ export const expandAttributeMeta = function(modelClass, attributeNames, namePref | ||||
|   let attributeMap = map || new Map(); | ||||
|   modelClass.eachAttribute((name, meta) => { | ||||
|     let fieldName = namePrefix ? namePrefix + name : name; | ||||
|     if (meta.isFragment) { | ||||
|     let maybeFragment = Ember.get(modelClass, fieldName); | ||||
|     if (meta.isFragment && maybeFragment) { | ||||
|       // pass the fragment and all fields that start with | ||||
|       // the fragment name down to get extracted from the Fragment | ||||
|       expandAttributeMeta( | ||||
|         Ember.get(modelClass, fieldName), | ||||
|         maybeFragment, | ||||
|         fields.filter(f => f.startsWith(fieldName)), | ||||
|         fieldName + '.', | ||||
|         attributeMap | ||||
| @@ -60,13 +61,15 @@ export const expandAttributeMeta = function(modelClass, attributeNames, namePref | ||||
|   // so we'll replace each key in `fields` with the expanded meta | ||||
|   fields = fields.map(field => { | ||||
|     let meta = attributeMap.get(field); | ||||
|     const { type, options } = meta; | ||||
|     if (meta) { | ||||
|       var { type, options } = meta; | ||||
|     } | ||||
|     return { | ||||
|       // using field name here because it is the full path, | ||||
|       // name on the attribute meta will be relative to the fragment it's on | ||||
|       name: field, | ||||
|       type, | ||||
|       options, | ||||
|       type: type, | ||||
|       options: options, | ||||
|     }; | ||||
|   }); | ||||
|   return fields; | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { test } from 'qunit'; | ||||
| import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance'; | ||||
| import backendListPage from 'vault/tests/pages/secrets/backends'; | ||||
|  | ||||
| moduleForAcceptance('Acceptance | settings', { | ||||
|   beforeEach() { | ||||
| @@ -36,14 +37,19 @@ test('settings', function(assert) { | ||||
|       find('[data-test-flash-message]').text().trim(), | ||||
|       `Successfully mounted '${type}' at '${path}'!` | ||||
|     ); | ||||
|     let row = backendListPage.rows().findByPath(path); | ||||
|     row.menu(); | ||||
|   }); | ||||
|  | ||||
|   andThen(() => { | ||||
|     backendListPage.configLink(); | ||||
|   }); | ||||
|  | ||||
|   //show mount details | ||||
|   click(`[data-test-secret-backend-row="${path}"] [data-test-secret-backend-detail]`); | ||||
|   andThen(() => { | ||||
|     assert.ok( | ||||
|       find('[data-test-secret-backend-details="default-ttl"]').text().match(/100/), | ||||
|       'displays the input ttl' | ||||
|       currentURL(), | ||||
|       '/vault/secrets/${path}/configuration', | ||||
|       'navigates to the config page' | ||||
|     ); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { test } from 'qunit'; | ||||
| import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance'; | ||||
| import page from 'vault/tests/pages/settings/mount-secret-backend'; | ||||
| import listPage from 'vault/tests/pages/secrets/backends'; | ||||
| import configPage from 'vault/tests/pages/secrets/backend/configuration'; | ||||
|  | ||||
| moduleForAcceptance('Acceptance | settings/mount-secret-backend', { | ||||
|   beforeEach() { | ||||
| @@ -30,13 +30,9 @@ test('it sets the ttl corrects when mounting', function(assert) { | ||||
|     .maxTTLUnit('h') | ||||
|     .submit(); | ||||
|  | ||||
|   listPage.visit(); | ||||
|   configPage.visit({backend: path}); | ||||
|   andThen(() => { | ||||
|     listPage.links().findByPath(path).toggleDetails(); | ||||
|   }); | ||||
|   andThen(() => { | ||||
|     const details = listPage.links().findByPath(path); | ||||
|     assert.equal(details.defaultTTL, defaultTTLSeconds, 'shows the proper TTL'); | ||||
|     assert.equal(details.maxTTL, maxTTLSeconds, 'shows the proper max TTL'); | ||||
|     assert.equal(configPage.defaultTTL, defaultTTLSeconds, 'shows the proper TTL'); | ||||
|     assert.equal(configPage.maxTTL, maxTTLSeconds, 'shows the proper max TTL'); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
							
								
								
									
										7
									
								
								ui/tests/pages/secrets/backend/configuration.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ui/tests/pages/secrets/backend/configuration.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| import { create, visitable, text } from 'ember-cli-page-object'; | ||||
|  | ||||
| export default create({ | ||||
|   visit: visitable('/vault/secrets/:backend/configuration'), | ||||
|   defaultTTL: text('[data-test-row-value="Default Lease TTL"]'), | ||||
|   maxTTL: text('[data-test-row-value="Max Lease TTL"]'), | ||||
| }); | ||||
| @@ -1,17 +1,16 @@ | ||||
| import { create, visitable, collection, text, clickable } from 'ember-cli-page-object'; | ||||
| import { create, visitable, collection, clickable, text } from 'ember-cli-page-object'; | ||||
|  | ||||
| export default create({ | ||||
|   visit: visitable('/vault/secrets'), | ||||
|   links: collection({ | ||||
|     itemScope: '[data-test-secret-backend-link]', | ||||
|   rows: collection({ | ||||
|     itemScope: '[data-test-secret-backend-row]', | ||||
|     item: { | ||||
|       path: text('[data-test-secret-path]'), | ||||
|       toggleDetails: clickable('[data-test-secret-backend-detail]'), | ||||
|       defaultTTL: text('[data-test-secret-backend-details="default-ttl"]'), | ||||
|       maxTTL: text('[data-test-secret-backend-details="max-ttl"]'), | ||||
|       menu: clickable('[data-test-popup-menu-trigger]'), | ||||
|     }, | ||||
|     findByPath(path) { | ||||
|       return this.toArray().findBy('path', path + '/'); | ||||
|     }, | ||||
|   }), | ||||
|   configLink: clickable('[data-test-engine-config]'), | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Matthew Irish
					Matthew Irish