mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 02:57:59 +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,
|
description: null,
|
||||||
default_lease_ttl: null,
|
default_lease_ttl: null,
|
||||||
max_lease_ttl: null,
|
max_lease_ttl: null,
|
||||||
force_no_cache: null,
|
|
||||||
showConfig: false,
|
showConfig: false,
|
||||||
local: false,
|
local: false,
|
||||||
sealWrap: false,
|
sealWrap: false,
|
||||||
@@ -50,7 +49,6 @@ export default Ember.Controller.extend({
|
|||||||
description: null,
|
description: null,
|
||||||
default_lease_ttl: null,
|
default_lease_ttl: null,
|
||||||
max_lease_ttl: null,
|
max_lease_ttl: null,
|
||||||
force_no_cache: null,
|
|
||||||
local: false,
|
local: false,
|
||||||
showConfig: false,
|
showConfig: false,
|
||||||
sealWrap: false,
|
sealWrap: false,
|
||||||
@@ -82,7 +80,6 @@ export default Ember.Controller.extend({
|
|||||||
selectedType: type,
|
selectedType: type,
|
||||||
description,
|
description,
|
||||||
default_lease_ttl,
|
default_lease_ttl,
|
||||||
force_no_cache,
|
|
||||||
local,
|
local,
|
||||||
max_lease_ttl,
|
max_lease_ttl,
|
||||||
sealWrap,
|
sealWrap,
|
||||||
@@ -92,7 +89,6 @@ export default Ember.Controller.extend({
|
|||||||
'selectedType',
|
'selectedType',
|
||||||
'description',
|
'description',
|
||||||
'default_lease_ttl',
|
'default_lease_ttl',
|
||||||
'force_no_cache',
|
|
||||||
'local',
|
'local',
|
||||||
'max_lease_ttl',
|
'max_lease_ttl',
|
||||||
'sealWrap',
|
'sealWrap',
|
||||||
@@ -112,9 +108,8 @@ export default Ember.Controller.extend({
|
|||||||
|
|
||||||
if (this.get('showConfig')) {
|
if (this.get('showConfig')) {
|
||||||
attrs.config = {
|
attrs.config = {
|
||||||
default_lease_ttl,
|
defaultLeaseTtl: default_lease_ttl,
|
||||||
max_lease_ttl,
|
maxLeaseTtl: max_lease_ttl,
|
||||||
force_no_cache,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ import attr from 'ember-data/attr';
|
|||||||
import Fragment from 'ember-data-model-fragments/fragment';
|
import Fragment from 'ember-data-model-fragments/fragment';
|
||||||
|
|
||||||
export default Fragment.extend({
|
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 { queryRecord } from 'ember-computed-query';
|
||||||
import { fragment } from 'ember-data-model-fragments/attributes';
|
import { fragment } from 'ember-data-model-fragments/attributes';
|
||||||
|
|
||||||
|
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||||||
|
|
||||||
const { attr } = DS;
|
const { attr } = DS;
|
||||||
const { computed } = Ember;
|
const { computed } = Ember;
|
||||||
|
|
||||||
@@ -16,11 +18,26 @@ export default DS.Model.extend({
|
|||||||
name: attr('string'),
|
name: attr('string'),
|
||||||
type: attr('string'),
|
type: attr('string'),
|
||||||
description: attr('string'),
|
description: attr('string'),
|
||||||
config: attr('object'),
|
config: fragment('mount-config', { defaultValue: {} }),
|
||||||
options: fragment('mount-options'),
|
options: fragment('mount-options', { defaultValue: {} }),
|
||||||
local: attr('boolean'),
|
local: attr('boolean'),
|
||||||
sealWrap: 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() {
|
shouldIncludeInList: computed('type', function() {
|
||||||
return !LIST_EXCLUDED_BACKENDS.includes(this.get('type'));
|
return !LIST_EXCLUDED_BACKENDS.includes(this.get('type'));
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ Router.map(function() {
|
|||||||
this.route('backends', { path: '/' });
|
this.route('backends', { path: '/' });
|
||||||
this.route('backend', { path: '/:backend' }, function() {
|
this.route('backend', { path: '/:backend' }, function() {
|
||||||
this.route('index', { path: '/' });
|
this.route('index', { path: '/' });
|
||||||
|
this.route('configuration');
|
||||||
// because globs / params can't be empty,
|
// because globs / params can't be empty,
|
||||||
// we have to special-case ids of '' with thier own routes
|
// we have to special-case ids of '' with thier own routes
|
||||||
this.route('list-root', { path: '/list/' });
|
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 {
|
.popup-menu-trigger {
|
||||||
width: 3rem;
|
min-width: auto;
|
||||||
height: 2rem;
|
|
||||||
}
|
}
|
||||||
.popup-menu-trigger.is-active {
|
.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 {
|
&.tool-tip-trigger {
|
||||||
color: $black;
|
color: $black;
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</li>
|
</li>
|
||||||
<li class="{{if (is-active-route (array 'vault.cluster.policies' 'vault.cluster.policy')) 'is-active'}}">
|
<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
|
Policies
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<ul>
|
<ul>
|
||||||
|
{{yield}}
|
||||||
{{#each secretPath as |path index|}}
|
{{#each secretPath as |path index|}}
|
||||||
<li class="{{if (is-active-route path.path path.model isExact=true) 'is-active'}}">
|
<li class="{{if (is-active-route path.path path.model isExact=true) 'is-active'}}">
|
||||||
<span class="sep">/</span>
|
<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|}}
|
{{#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
|
{{i-con
|
||||||
glyph="more"
|
glyph="more"
|
||||||
class="has-text-black auto-width"
|
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|}}
|
{{#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="box is-sideless has-background-grey-lighter has-short-padding is-marginless">
|
||||||
<div class="level">
|
<div class="level">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
@@ -90,17 +17,15 @@
|
|||||||
mode=(if (eq tab 'certs') 'secrets-cert' 'secrets')
|
mode=(if (eq tab 'certs') 'secrets-cert' 'secrets')
|
||||||
}}
|
}}
|
||||||
{{#if filterFocused}}
|
{{#if filterFocused}}
|
||||||
|
|
||||||
|
|
||||||
{{#if filterMatchesKey}}
|
{{#if filterMatchesKey}}
|
||||||
{{#unless filterIsFolder}}
|
{{#unless filterIsFolder}}
|
||||||
<p class="help has-text-grey is-size-8">
|
<p class="input-hint">
|
||||||
<kbd>Enter</kbd> to view {{filter}}
|
<kbd>Enter</kbd> to view {{filter}}
|
||||||
</p>
|
</p>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if firstPartialMatch}}
|
{{#if firstPartialMatch}}
|
||||||
<p class="help has-text-grey is-size-8">
|
<p class="input-hint">
|
||||||
<kbd>Tab</kbd> to autocomplete
|
<kbd>Tab</kbd> to autocomplete
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -18,11 +18,8 @@
|
|||||||
{{#linked-block
|
{{#linked-block
|
||||||
"vault.cluster.secrets.backend.list-root"
|
"vault.cluster.secrets.backend.list-root"
|
||||||
backend.id
|
backend.id
|
||||||
class=(concat
|
class="box is-sideless is-marginless has-pointer"
|
||||||
'box is-sideless is-marginless has-pointer '
|
data-test-secret-backend-row=backend.id
|
||||||
(if (get this (concat backend.accessor '-open')) 'has-background-white-bis')
|
|
||||||
)
|
|
||||||
data-test-secret-backend-link=backend.id
|
|
||||||
}}
|
}}
|
||||||
<div class="level is-mobile">
|
<div class="level is-mobile">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
@@ -53,25 +50,35 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="level-right is-flex is-paddingless is-marginless">
|
<div class="level-right is-flex is-paddingless is-marginless">
|
||||||
<div class="level-item">
|
<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)}}>
|
{{#popup-menu name="engine-menu"}}
|
||||||
{{i-con glyph="more" size=16 aria-label=(concat backend.path ' details')}}
|
<nav class="menu">
|
||||||
</button>
|
<ul class="menu-list">
|
||||||
</div>
|
<li class="action">
|
||||||
</div>
|
<a href="{{href-to 'vault.cluster.secrets.backend.configuration' backend.id}}">
|
||||||
</div>
|
View Configuration
|
||||||
{{#if (get this (concat backend.accessor '-open'))}}
|
</a>
|
||||||
{{partial "partials/backend-details"}}
|
</li>
|
||||||
|
{{#if item.updatePath.isPending}}
|
||||||
|
<li class="action">
|
||||||
|
<button disabled=true type="button" class="link button is-loading is-transparent"></button>
|
||||||
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{{/popup-menu}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{/linked-block}}
|
{{/linked-block}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each unsupportedBackends as |backend|}}
|
{{#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}}
|
data-test-secret-backend-row={{backend.id}}
|
||||||
>
|
>
|
||||||
<div class="level is-mobile">
|
<div class="level is-mobile">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
<div>
|
<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}}
|
{{i-con glyph="folder" size=14 class="has-text-grey-light"}} {{backend.path}}
|
||||||
</div>
|
</div>
|
||||||
<span class="tag">
|
<span class="tag">
|
||||||
@@ -90,14 +97,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="level-right is-flex is-paddingless is-marginless">
|
<div class="level-right is-flex is-paddingless is-marginless">
|
||||||
<div class="level-item">
|
<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)}}>
|
{{#popup-menu name="engine-menu"}}
|
||||||
{{i-con glyph="more" size=16 aria-label=(concat backend.path ' details')}}
|
<nav class="menu">
|
||||||
</button>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if (get this (concat backend.accessor '-open'))}}
|
|
||||||
{{partial "partials/backend-details"}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|||||||
@@ -42,11 +42,12 @@ export const expandAttributeMeta = function(modelClass, attributeNames, namePref
|
|||||||
let attributeMap = map || new Map();
|
let attributeMap = map || new Map();
|
||||||
modelClass.eachAttribute((name, meta) => {
|
modelClass.eachAttribute((name, meta) => {
|
||||||
let fieldName = namePrefix ? namePrefix + name : name;
|
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
|
// pass the fragment and all fields that start with
|
||||||
// the fragment name down to get extracted from the Fragment
|
// the fragment name down to get extracted from the Fragment
|
||||||
expandAttributeMeta(
|
expandAttributeMeta(
|
||||||
Ember.get(modelClass, fieldName),
|
maybeFragment,
|
||||||
fields.filter(f => f.startsWith(fieldName)),
|
fields.filter(f => f.startsWith(fieldName)),
|
||||||
fieldName + '.',
|
fieldName + '.',
|
||||||
attributeMap
|
attributeMap
|
||||||
@@ -60,13 +61,15 @@ export const expandAttributeMeta = function(modelClass, attributeNames, namePref
|
|||||||
// so we'll replace each key in `fields` with the expanded meta
|
// so we'll replace each key in `fields` with the expanded meta
|
||||||
fields = fields.map(field => {
|
fields = fields.map(field => {
|
||||||
let meta = attributeMap.get(field);
|
let meta = attributeMap.get(field);
|
||||||
const { type, options } = meta;
|
if (meta) {
|
||||||
|
var { type, options } = meta;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
// using field name here because it is the full path,
|
// 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 on the attribute meta will be relative to the fragment it's on
|
||||||
name: field,
|
name: field,
|
||||||
type,
|
type: type,
|
||||||
options,
|
options: options,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return fields;
|
return fields;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test } from 'qunit';
|
import { test } from 'qunit';
|
||||||
import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance';
|
import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance';
|
||||||
|
import backendListPage from 'vault/tests/pages/secrets/backends';
|
||||||
|
|
||||||
moduleForAcceptance('Acceptance | settings', {
|
moduleForAcceptance('Acceptance | settings', {
|
||||||
beforeEach() {
|
beforeEach() {
|
||||||
@@ -36,14 +37,19 @@ test('settings', function(assert) {
|
|||||||
find('[data-test-flash-message]').text().trim(),
|
find('[data-test-flash-message]').text().trim(),
|
||||||
`Successfully mounted '${type}' at '${path}'!`
|
`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(() => {
|
andThen(() => {
|
||||||
assert.ok(
|
assert.ok(
|
||||||
find('[data-test-secret-backend-details="default-ttl"]').text().match(/100/),
|
currentURL(),
|
||||||
'displays the input ttl'
|
'/vault/secrets/${path}/configuration',
|
||||||
|
'navigates to the config page'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { test } from 'qunit';
|
import { test } from 'qunit';
|
||||||
import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance';
|
import moduleForAcceptance from 'vault/tests/helpers/module-for-acceptance';
|
||||||
import page from 'vault/tests/pages/settings/mount-secret-backend';
|
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', {
|
moduleForAcceptance('Acceptance | settings/mount-secret-backend', {
|
||||||
beforeEach() {
|
beforeEach() {
|
||||||
@@ -30,13 +30,9 @@ test('it sets the ttl corrects when mounting', function(assert) {
|
|||||||
.maxTTLUnit('h')
|
.maxTTLUnit('h')
|
||||||
.submit();
|
.submit();
|
||||||
|
|
||||||
listPage.visit();
|
configPage.visit({backend: path});
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
listPage.links().findByPath(path).toggleDetails();
|
assert.equal(configPage.defaultTTL, defaultTTLSeconds, 'shows the proper TTL');
|
||||||
});
|
assert.equal(configPage.maxTTL, maxTTLSeconds, 'shows the proper max TTL');
|
||||||
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');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
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({
|
export default create({
|
||||||
visit: visitable('/vault/secrets'),
|
visit: visitable('/vault/secrets'),
|
||||||
links: collection({
|
rows: collection({
|
||||||
itemScope: '[data-test-secret-backend-link]',
|
itemScope: '[data-test-secret-backend-row]',
|
||||||
item: {
|
item: {
|
||||||
path: text('[data-test-secret-path]'),
|
path: text('[data-test-secret-path]'),
|
||||||
toggleDetails: clickable('[data-test-secret-backend-detail]'),
|
menu: clickable('[data-test-popup-menu-trigger]'),
|
||||||
defaultTTL: text('[data-test-secret-backend-details="default-ttl"]'),
|
|
||||||
maxTTL: text('[data-test-secret-backend-details="max-ttl"]'),
|
|
||||||
},
|
},
|
||||||
findByPath(path) {
|
findByPath(path) {
|
||||||
return this.toArray().findBy('path', path + '/');
|
return this.toArray().findBy('path', path + '/');
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
configLink: clickable('[data-test-engine-config]'),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user