UI - add kmip engine (#6936)
* add kmip engine * adjust where kmip engine is mounted and sketch out routes * add secret mount path service to share params to engines * move list-controller and list-route mixins to core addon and adjust imports * properly link kmip secrets from the secrets list page * tweak routes and add list controllers * stub out some models and adapters * fix mixin exports * move a bunch of components into the core addon * use new empty yield in list-view in the namespace template * scopes list using list-view and list-item components * simplify and flatten routes, templates for all of the list pages * role show route and template and scope create template * add ember-router-helpers * add more packages to the dependencies of the core addon * add field-group-show component for listing fields from a model * move more components to the shared addon * make configure and configuration routes work and save a generated model * save and list scopes * role create, list, read * list credentials properly * move allowed attributes to field group * show allowed operations on role details page * add kmip logo to mount secrets engine list page * add role edit page * show all model attributes on role show page * enable role edit * fix newFields error by creating open api role model on the role list route * only show selected fields on role edit page * do not send scope and backend attrs to api * move path-or-array to core addon * move string-list component to core addon * remove extra top border when there is only one field group * add icons for all of the list pages * update kmip config model so defaultValue doesn't error * generate credentials * credential create and show * only show kmip when feature is enabled * fix saving of TTL fields generated from Open API * move masked-input and list-pagination components to core addon * add param on edit form to allow for calling onSave after render happens * polish credential show page and redirect there after generating credentials * add externalLink for kmip engine * add kmip-breadcrumb component * use kmip-breadcrumb component * add linkPrefix param to linked-block component to allow for routing programmatically inside an engine * redirect to the right place when enabling kmip * fix linting * review feedback * update signature for path-help usage * fix ttl field expansion test * remove role filed from role form, fix generate redirect * remove field-group-show because it's in the core addon * remove bottom rule from show pages * fix Max TTL displayAttrs for ssh role * update edit-form to take fields or attrs * fix linting * remove listenAddrs and set default val on ttl if a val is passed in
This commit is contained in:
parent
7c4eca5fb3
commit
f0d7dc9a6d
|
@ -218,7 +218,7 @@ func pathRoles(b *backend) *framework.Path {
|
|||
The maximum allowed lease duration
|
||||
`,
|
||||
DisplayAttrs: &framework.DisplayAttributes{
|
||||
Value: "Max TTL",
|
||||
Name: "Max TTL",
|
||||
},
|
||||
},
|
||||
"allowed_critical_options": &framework.FieldSchema{
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import ApplicationAdapter from '../application';
|
||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
|
||||
export default ApplicationAdapter.extend({
|
||||
namespace: 'v1',
|
||||
pathForType(type) {
|
||||
return type.replace('kmip/', '');
|
||||
},
|
||||
|
||||
_url(modelType, meta = {}, id) {
|
||||
let { backend, scope, role } = meta;
|
||||
let type = this.pathForType(modelType);
|
||||
let base;
|
||||
switch (type) {
|
||||
case 'scope':
|
||||
base = `${encodePath(backend)}/scope`;
|
||||
break;
|
||||
case 'role':
|
||||
base = `${encodePath(backend)}/scope/${encodePath(scope)}/role`;
|
||||
break;
|
||||
case 'credential':
|
||||
base = `${encodePath(backend)}/scope/${encodePath(scope)}/role/${encodePath(role)}/credential`;
|
||||
break;
|
||||
}
|
||||
if (id && type === 'credential') {
|
||||
return `/v1/${base}/lookup?serial_number=${encodePath(id)}`;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
return `/v1/${base}/${encodePath(id)}`;
|
||||
}
|
||||
return `/v1/${base}`;
|
||||
},
|
||||
|
||||
urlForQuery(query, modelType) {
|
||||
let base = this._url(modelType, query);
|
||||
return base + '?list=true';
|
||||
},
|
||||
|
||||
query(store, type, query) {
|
||||
return this.ajax(this.urlForQuery(query, type.modelName), 'GET');
|
||||
},
|
||||
|
||||
queryRecord(store, type, query) {
|
||||
let id = query.id;
|
||||
delete query.id;
|
||||
return this.ajax(this._url(type.modelName, query, id), 'GET').then(resp => {
|
||||
resp.id = id;
|
||||
resp = { ...resp, ...query };
|
||||
return resp;
|
||||
});
|
||||
},
|
||||
buildURL(modelName, id, snapshot, requestType, query) {
|
||||
if (requestType === 'createRecord') {
|
||||
return this._super(...arguments);
|
||||
}
|
||||
return this._super(`${modelName}`, id, snapshot, requestType, query);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
import BaseAdapter from './base';
|
||||
|
||||
export default BaseAdapter.extend({
|
||||
_url(id, modelName, snapshot) {
|
||||
let name = this.pathForType(modelName);
|
||||
// id here will be the mount path,
|
||||
// modelName will be config so we want to transpose the first two call args
|
||||
return this.buildURL(id, name, snapshot);
|
||||
},
|
||||
urlForFindRecord() {
|
||||
return this._url(...arguments);
|
||||
},
|
||||
urlForCreateRecord(modelName, snapshot) {
|
||||
return this._url(snapshot.id, modelName, snapshot);
|
||||
},
|
||||
urlForUpdateRecord() {
|
||||
return this._url(...arguments);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
import BaseAdapter from './base';
|
||||
|
||||
export default BaseAdapter.extend({
|
||||
createRecord(store, type, snapshot) {
|
||||
let url = this._url(type.modelName, {
|
||||
backend: snapshot.record.backend,
|
||||
scope: snapshot.record.scope,
|
||||
role: snapshot.record.role,
|
||||
});
|
||||
url = `${url}/generate`;
|
||||
return this.ajax(url, 'POST', { data: snapshot.serialize() }).then(model => {
|
||||
model.data.id = model.data.serial_number;
|
||||
return model;
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
import BaseAdapter from './base';
|
||||
|
||||
export default BaseAdapter.extend({
|
||||
createRecord(store, type, snapshot) {
|
||||
let name = snapshot.id || snapshot.attr('name');
|
||||
let url = this._url(
|
||||
type.modelName,
|
||||
{
|
||||
backend: snapshot.record.backend,
|
||||
scope: snapshot.record.scope,
|
||||
},
|
||||
name
|
||||
);
|
||||
return this.ajax(url, 'POST', { data: snapshot.serialize() }).then(() => {
|
||||
return {
|
||||
id: name,
|
||||
name,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
updateRecord() {
|
||||
return this.createRecord(...arguments);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import BaseAdapter from './base';
|
||||
|
||||
export default BaseAdapter.extend({
|
||||
createRecord(store, type, snapshot) {
|
||||
let name = snapshot.attr('name');
|
||||
return this.ajax(this._url(type.modelName, { backend: snapshot.record.backend }, name), 'POST').then(
|
||||
() => {
|
||||
return {
|
||||
id: name,
|
||||
name,
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
|
@ -28,6 +28,24 @@ App = Application.extend({
|
|||
],
|
||||
},
|
||||
},
|
||||
kmip: {
|
||||
dependencies: {
|
||||
services: [
|
||||
'auth',
|
||||
'flash-messages',
|
||||
'namespace',
|
||||
'path-help',
|
||||
'router',
|
||||
'store',
|
||||
'version',
|
||||
'wizard',
|
||||
'secret-mount-path',
|
||||
],
|
||||
externalRoutes: {
|
||||
secrets: 'vault.cluster.secrets.backends',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
import OuterHTML from './outer-html';
|
||||
export default OuterHTML.extend();
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* @module FieldGroupShow
|
||||
* FieldGroupShow components loop through a Model's fieldGroups
|
||||
* to display their attributes
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <FieldGroupShow @model={{model}} @showAllFields=true />
|
||||
* ```
|
||||
*
|
||||
* @param model {Object} - the model
|
||||
* @param [showAllFields=false] {boolean} - whether to show fields with empty values
|
||||
*/
|
||||
import Component from '@ember/component';
|
||||
import layout from '../templates/components/field-group-show';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
model: null,
|
||||
showAllFields: false,
|
||||
});
|
|
@ -5,7 +5,7 @@ import d3Axis from 'd3-axis';
|
|||
import d3TimeFormat from 'd3-time-format';
|
||||
import { assign } from '@ember/polyfills';
|
||||
import { computed } from '@ember/object';
|
||||
import { run, debounce } from '@ember/runloop';
|
||||
import { run } from '@ember/runloop';
|
||||
import { task, waitForEvent } from 'ember-concurrency';
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,8 @@ const HEIGHT = 240;
|
|||
export default Component.extend({
|
||||
classNames: ['http-requests-bar-chart-container'],
|
||||
counters: null,
|
||||
|
||||
/* eslint-disable ember/avoid-leaking-state-in-ember-objects */
|
||||
margin: { top: 24, right: 16, bottom: 24, left: 16 },
|
||||
padding: 0.04,
|
||||
width: 0,
|
||||
|
|
|
@ -3,7 +3,7 @@ import { computed } from '@ember/object';
|
|||
import Component from '@ember/component';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { methods } from 'vault/helpers/mountable-auth-methods';
|
||||
import { engines } from 'vault/helpers/mountable-secret-engines';
|
||||
import { engines, KMIP } from 'vault/helpers/mountable-secret-engines';
|
||||
|
||||
const METHODS = methods();
|
||||
const ENGINES = engines();
|
||||
|
@ -12,6 +12,7 @@ export default Component.extend({
|
|||
store: service(),
|
||||
wizard: service(),
|
||||
flashMessages: service(),
|
||||
version: service(),
|
||||
|
||||
/*
|
||||
* @param Function
|
||||
|
@ -51,7 +52,15 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
mountTypes: computed('mountType', function() {
|
||||
return this.mountType === 'secret' ? ENGINES : METHODS;
|
||||
return this.mountType === 'secret' ? this.engines : METHODS;
|
||||
}),
|
||||
|
||||
engines: computed('version.features[]', function() {
|
||||
if (this.version.hasFeature('KMIP')) {
|
||||
return ENGINES.concat([KMIP]);
|
||||
} else {
|
||||
return ENGINES;
|
||||
}
|
||||
}),
|
||||
|
||||
willDestroy() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Controller from '@ember/controller';
|
||||
import ListController from 'vault/mixins/list-controller';
|
||||
import ListController from 'core/mixins/list-controller';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
actions: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import Controller from '@ember/controller';
|
||||
import ListController from 'vault/mixins/list-controller';
|
||||
import ListController from 'core/mixins/list-controller';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
flashMessages: service(),
|
||||
|
|
|
@ -2,7 +2,7 @@ import { inject as service } from '@ember/service';
|
|||
import { computed } from '@ember/object';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import utils from 'vault/lib/key-utils';
|
||||
import ListController from 'vault/mixins/list-controller';
|
||||
import ListController from 'core/mixins/list-controller';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
flashMessages: service(),
|
||||
|
|
|
@ -4,7 +4,7 @@ import Controller from '@ember/controller';
|
|||
import utils from 'vault/lib/key-utils';
|
||||
import BackendCrumbMixin from 'vault/mixins/backend-crumb';
|
||||
import WithNavToNearestAncestor from 'vault/mixins/with-nav-to-nearest-ancestor';
|
||||
import ListController from 'vault/mixins/list-controller';
|
||||
import ListController from 'core/mixins/list-controller';
|
||||
|
||||
export default Controller.extend(ListController, BackendCrumbMixin, WithNavToNearestAncestor, {
|
||||
flashMessages: service(),
|
||||
|
|
|
@ -10,7 +10,11 @@ export default Controller.extend({
|
|||
onMountSuccess: function(type, path) {
|
||||
let transition;
|
||||
if (SUPPORTED_BACKENDS.includes(type)) {
|
||||
transition = this.transitionToRoute('vault.cluster.secrets.backend.index', path);
|
||||
if (type === 'kmip') {
|
||||
transition = this.transitionToRoute('vault.cluster.secrets.backend.kmip.scopes', path);
|
||||
} else {
|
||||
transition = this.transitionToRoute('vault.cluster.secrets.backend.index', path);
|
||||
}
|
||||
} else {
|
||||
transition = this.transitionToRoute('vault.cluster.secrets.backends');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { helper as buildHelper } from '@ember/component/helper';
|
||||
|
||||
export const KMIP = {
|
||||
displayName: 'KMIP',
|
||||
value: 'kmip',
|
||||
type: 'kmip',
|
||||
category: 'generic',
|
||||
};
|
||||
|
||||
const MOUNTABLE_SECRET_ENGINES = [
|
||||
{
|
||||
displayName: 'Active Directory',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { helper as buildHelper } from '@ember/component/helper';
|
||||
|
||||
const SUPPORTED_SECRET_BACKENDS = ['aws', 'cubbyhole', 'generic', 'kv', 'pki', 'ssh', 'transit'];
|
||||
const SUPPORTED_SECRET_BACKENDS = ['aws', 'cubbyhole', 'generic', 'kv', 'pki', 'ssh', 'transit', 'kmip'];
|
||||
|
||||
export function supportedSecretBackends() {
|
||||
return SUPPORTED_SECRET_BACKENDS;
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import Mixin from '@ember/object/mixin';
|
||||
|
||||
export default Mixin.create({
|
||||
queryParams: {
|
||||
page: {
|
||||
refreshModel: true,
|
||||
},
|
||||
pageFilter: {
|
||||
refreshModel: true,
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import DS from 'ember-data';
|
||||
import { computed } from '@ember/object';
|
||||
import { combineFieldGroups } from 'vault/utils/openapi-to-attrs';
|
||||
import fieldToAttrs from 'vault/utils/field-to-attrs';
|
||||
|
||||
export default DS.Model.extend({
|
||||
useOpenAPI: true,
|
||||
getHelpUrl(path) {
|
||||
return `/v1/${path}/config?help=1`;
|
||||
},
|
||||
|
||||
fieldGroups: computed(function() {
|
||||
let groups = [{ default: ['listenAddrs', 'connectionTimeout'] }];
|
||||
|
||||
groups = combineFieldGroups(groups, this.newFields, []);
|
||||
return fieldToAttrs(this, groups);
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import DS from 'ember-data';
|
||||
import fieldToAttrs from 'vault/utils/field-to-attrs';
|
||||
import { computed } from '@ember/object';
|
||||
const { attr } = DS;
|
||||
|
||||
export default DS.Model.extend({
|
||||
backend: attr({ readOnly: true }),
|
||||
scope: attr({ readOnly: true }),
|
||||
role: attr({ readOnly: true }),
|
||||
certificate: attr('string', { readOnly: true }),
|
||||
caChain: attr({ readOnly: true }),
|
||||
privateKey: attr('string', {
|
||||
readOnly: true,
|
||||
sensitive: true,
|
||||
}),
|
||||
format: attr('string', {
|
||||
possibleValues: ['pem', 'der', 'pem_bundle'],
|
||||
defaultValue: 'pem',
|
||||
label: 'Certificate format',
|
||||
}),
|
||||
fieldGroups: computed(function() {
|
||||
const groups = [
|
||||
{
|
||||
default: ['format'],
|
||||
},
|
||||
];
|
||||
|
||||
return fieldToAttrs(this, groups);
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,28 @@
|
|||
import DS from 'ember-data';
|
||||
import fieldToAttrs from 'vault/utils/field-to-attrs';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
const { attr } = DS;
|
||||
export default DS.Model.extend({
|
||||
useOpenAPI: true,
|
||||
backend: attr({ readOnly: true }),
|
||||
scope: attr({ readOnly: true }),
|
||||
getHelpUrl(path) {
|
||||
return `/v1/${path}/scope/example/role/example?help=1`;
|
||||
},
|
||||
|
||||
name: attr('string'),
|
||||
allowedOperations: attr(),
|
||||
fieldGroups: computed(function() {
|
||||
let fields = this.newFields.without('role');
|
||||
|
||||
const groups = [
|
||||
{
|
||||
default: ['name'],
|
||||
},
|
||||
{ 'Allowed Operations': fields },
|
||||
];
|
||||
|
||||
return fieldToAttrs(this, groups);
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { computed } from '@ember/object';
|
||||
import DS from 'ember-data';
|
||||
|
||||
const { attr } = DS;
|
||||
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||||
|
||||
export default DS.Model.extend({
|
||||
name: attr('string'),
|
||||
attrs: computed(function() {
|
||||
return expandAttributeMeta(this, ['name']);
|
||||
}),
|
||||
});
|
|
@ -83,6 +83,7 @@ Router.map(function() {
|
|||
this.route('secrets', function() {
|
||||
this.route('backends', { path: '/' });
|
||||
this.route('backend', { path: '/:backend' }, function() {
|
||||
this.mount('kmip');
|
||||
this.route('index', { path: '/' });
|
||||
this.route('configuration');
|
||||
// because globs / params can't be empty,
|
||||
|
@ -124,6 +125,7 @@ Router.map(function() {
|
|||
if (config.addRootMounts) {
|
||||
config.addRootMounts.call(this);
|
||||
}
|
||||
|
||||
this.route('not-found', { path: '/*path' });
|
||||
});
|
||||
this.route('not-found', { path: '/*path' });
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import ListRoute from 'vault/mixins/list-route';
|
||||
import ListRoute from 'core/mixins/list-route';
|
||||
|
||||
export default Route.extend(ListRoute, {
|
||||
model(params) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Route from '@ember/routing/route';
|
||||
import ListRoute from 'vault/mixins/list-route';
|
||||
import ListRoute from 'core/mixins/list-route';
|
||||
|
||||
export default Route.extend(ListRoute, {
|
||||
model(params) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import Route from '@ember/routing/route';
|
||||
import ClusterRoute from 'vault/mixins/cluster-route';
|
||||
import ListRoute from 'vault/mixins/list-route';
|
||||
import ListRoute from 'core/mixins/list-route';
|
||||
|
||||
export default Route.extend(ClusterRoute, ListRoute, {
|
||||
version: service(),
|
||||
|
|
|
@ -2,9 +2,11 @@ import { inject as service } from '@ember/service';
|
|||
import Route from '@ember/routing/route';
|
||||
export default Route.extend({
|
||||
flashMessages: service(),
|
||||
secretMountPath: service(),
|
||||
oldModel: null,
|
||||
model(params) {
|
||||
let { backend } = params;
|
||||
this.secretMountPath.update(backend);
|
||||
return this.store
|
||||
.query('secret-engine', {
|
||||
path: backend,
|
||||
|
|
|
@ -197,7 +197,7 @@ export default Service.extend({
|
|||
//we need list and create paths to set the correct urls for actions
|
||||
const { list, create } = paths;
|
||||
return generatedItemAdapter.extend({
|
||||
urlForItem(method, id, type) {
|
||||
urlForItem(method, id) {
|
||||
let listPath = list.find(pathInfo => pathInfo.path.includes(itemType));
|
||||
let { tag, path } = listPath;
|
||||
let url = `${this.buildURL()}/${tag}/${backend}${path}/`;
|
||||
|
@ -211,7 +211,7 @@ export default Service.extend({
|
|||
return this.urlForItem(modelName, id, snapshot);
|
||||
},
|
||||
|
||||
urlForUpdateRecord(id, modelName, snapshot) {
|
||||
urlForUpdateRecord(id) {
|
||||
let { tag, path } = create[0];
|
||||
path = path.slice(0, path.indexOf('{') - 1);
|
||||
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
|
||||
|
@ -224,7 +224,7 @@ export default Service.extend({
|
|||
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
|
||||
},
|
||||
|
||||
urlForDeleteRecord(id, modelName, snapshot) {
|
||||
urlForDeleteRecord(id) {
|
||||
let { tag, path } = paths.delete[0];
|
||||
path = path.slice(0, path.indexOf('{') - 1);
|
||||
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import Service from '@ember/service';
|
||||
|
||||
// this service tracks the path of the currently viewed secret mount
|
||||
// so that we can access that inside of engines where parent route params
|
||||
// are not accessible
|
||||
export default Service.extend({
|
||||
currentPath: null,
|
||||
update(path) {
|
||||
this.set('currentPath', path);
|
||||
},
|
||||
get() {
|
||||
return this.currentPath;
|
||||
},
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
{{#link-to "vault.cluster.access.namespaces.create"}}
|
||||
Create Namespace
|
||||
{{/link-to}}
|
||||
|
||||
<LearnLink @path="/vault/security/namespaces">
|
||||
Learn more
|
||||
</LearnLink>
|
|
@ -1,13 +0,0 @@
|
|||
{{#if items.length}}
|
||||
<div class="box is-fullwidth is-bottomless is-sideless is-paddingless">
|
||||
{{#each items as |item|}}
|
||||
{{yield (hash deleteItem=deleteItem saveItem=saveItem item=item)}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{else}}
|
||||
<EmptyState
|
||||
@title={{this.emptyTitle}}
|
||||
@message={{this.emptyMessage}}
|
||||
@emptyActions={{this.emptyActions}}
|
||||
/>
|
||||
{{/if}}
|
|
@ -18,42 +18,54 @@
|
|||
</ToolbarActions>
|
||||
</Toolbar>
|
||||
|
||||
<ListView @items={{model}} @itemNoun="namespace" @emptyActions="empty-action-namespaces" as |list|>
|
||||
<ListItem as |Item|>
|
||||
<Item.content>
|
||||
{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#with (concat currentNamespace (if currentNamespace "/") list.item.id) as |targetNamespace|}}
|
||||
{{#if (contains targetNamespace accessibleNamespaces)}}
|
||||
<li class="action">
|
||||
{{#link-to "vault.cluster.secrets" (query-params namespace=targetNamespace) class="is-block"}}
|
||||
Switch to Namespace
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
<li class="action">
|
||||
<ConfirmAction
|
||||
@buttonClasses="link is-destroy"
|
||||
@confirmButtonText="Remove"
|
||||
@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")
|
||||
)
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</ConfirmAction>
|
||||
</li>
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
<ListView @items={{model}} @itemNoun="namespace" as |list|>
|
||||
{{#if list.empty}}
|
||||
<list.empty>
|
||||
{{#link-to "vault.cluster.access.namespaces.create"}}
|
||||
Create Namespace
|
||||
{{/link-to}}
|
||||
|
||||
<LearnLink @path="/vault/security/namespaces">
|
||||
Learn more
|
||||
</LearnLink>
|
||||
</list.empty>
|
||||
{{else}}
|
||||
<ListItem as |Item|>
|
||||
<Item.content>
|
||||
{{list.item.id}}
|
||||
</Item.content>
|
||||
<Item.menu>
|
||||
{{#with (concat currentNamespace (if currentNamespace "/") list.item.id) as |targetNamespace|}}
|
||||
{{#if (contains targetNamespace accessibleNamespaces)}}
|
||||
<li class="action">
|
||||
{{#link-to "vault.cluster.secrets" (query-params namespace=targetNamespace) class="is-block"}}
|
||||
Switch to Namespace
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
<li class="action">
|
||||
<ConfirmAction
|
||||
@buttonClasses="link is-destroy"
|
||||
@confirmButtonText="Remove"
|
||||
@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")
|
||||
)
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</ConfirmAction>
|
||||
</li>
|
||||
</Item.menu>
|
||||
</ListItem>
|
||||
{{/if}}
|
||||
</ListView>
|
||||
{{else}}
|
||||
<UpgradePage @title="Namespaces" @minimumEdition="Vault Enterprise Pro" />
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
{{#each supportedBackends as |backend|}}
|
||||
{{#linked-block
|
||||
"vault.cluster.secrets.backend.list-root"
|
||||
(if (eq backend.engineType "kmip")
|
||||
"vault.cluster.secrets.backend.kmip.scopes"
|
||||
"vault.cluster.secrets.backend.list-root"
|
||||
)
|
||||
backend.id
|
||||
class="list-item-row"
|
||||
data-test-secret-backend-row=backend.id
|
||||
|
@ -30,7 +33,7 @@
|
|||
<ToolTip @horizontalPosition="left" as |T|>
|
||||
<T.trigger>
|
||||
<Icon
|
||||
@glyph={{or backend.engineType "secrets"}}
|
||||
@glyph={{or (if (eq backend.engineType "kmip") "secrets" backend.engineType) "secrets"}}
|
||||
@size="l"
|
||||
class="has-text-grey-light"
|
||||
/>
|
||||
|
@ -41,7 +44,12 @@
|
|||
</div>
|
||||
</T.content>
|
||||
</ToolTip>
|
||||
{{#link-to "vault.cluster.secrets.backend.list-root" backend.id
|
||||
{{#link-to
|
||||
(if (eq backend.engineType "kmip")
|
||||
"vault.cluster.secrets.backend.kmip.scopes"
|
||||
"vault.cluster.secrets.backend.list-root"
|
||||
)
|
||||
backend.id
|
||||
class="has-text-black has-text-weight-semibold"
|
||||
data-test-secret-path=true
|
||||
}}
|
||||
|
|
|
@ -23,7 +23,6 @@ export const expandOpenApiProps = function(props) {
|
|||
}
|
||||
let attrDefn = {
|
||||
editType,
|
||||
type: type,
|
||||
helpText: description,
|
||||
sensitive: sensitive,
|
||||
label: name || label,
|
||||
|
@ -33,6 +32,11 @@ export const expandOpenApiProps = function(props) {
|
|||
readOnly: isId,
|
||||
defaultValue: value || null,
|
||||
};
|
||||
// ttls write as a string and read as a number
|
||||
// so setting type on them runs the wrong transform
|
||||
if (editType !== 'ttl') {
|
||||
attrDefn.type = type;
|
||||
}
|
||||
// loop to remove empty vals
|
||||
for (let attrProp in attrDefn) {
|
||||
if (attrDefn[attrProp] == null) {
|
||||
|
|
|
@ -2,8 +2,11 @@ import { inject as service } from '@ember/service';
|
|||
import Component from '@ember/component';
|
||||
import { task } from 'ember-concurrency';
|
||||
import DS from 'ember-data';
|
||||
import layout from '../templates/components/edit-form';
|
||||
import { next } from '@ember/runloop';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
flashMessages: service(),
|
||||
|
||||
// public API
|
||||
|
@ -22,6 +25,10 @@ export default Component.extend({
|
|||
*/
|
||||
onSave: () => {},
|
||||
|
||||
// onSave may need values updated in render in a helper - if this
|
||||
// is the case, set this value to true
|
||||
callOnSaveAfterRender: false,
|
||||
|
||||
save: task(function*(model, options = { method: 'save' }) {
|
||||
let { method } = options;
|
||||
let messageKey = method === 'save' ? 'successMessage' : 'deleteSuccessMessage';
|
||||
|
@ -36,6 +43,12 @@ export default Component.extend({
|
|||
return;
|
||||
}
|
||||
this.get('flashMessages').success(this.get(messageKey));
|
||||
if (this.callOnSaveAfterRender) {
|
||||
next(() => {
|
||||
this.get('onSave')({ saveType: method, model });
|
||||
});
|
||||
return;
|
||||
}
|
||||
yield this.get('onSave')({ saveType: method, model });
|
||||
})
|
||||
.drop()
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* @module FieldGroupShow
|
||||
* FieldGroupShow components are used to...
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <FieldGroupShow @param1={param1} @param2={param2} />
|
||||
* ```
|
||||
*
|
||||
* @param param1 {String} - param1 is...
|
||||
* @param [param2=value] {String} - param2 is... //brackets mean it is optional and = sets the default value
|
||||
*/
|
||||
import Component from '@ember/component';
|
||||
import layout from '../templates/components/field-group-show';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
model: null,
|
||||
showAllFields: false,
|
||||
});
|
|
@ -1,5 +1,6 @@
|
|||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import layout from '../templates/components/form-field-groups';
|
||||
|
||||
/**
|
||||
* @module FormFieldGroups
|
||||
|
@ -27,6 +28,7 @@ import { computed } from '@ember/object';
|
|||
*/
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
|
||||
renderGroup: computed(function() {
|
|
@ -3,6 +3,7 @@ import { computed } from '@ember/object';
|
|||
import { capitalize } from 'vault/helpers/capitalize';
|
||||
import { humanize } from 'vault/helpers/humanize';
|
||||
import { dasherize } from 'vault/helpers/dasherize';
|
||||
import layout from '../templates/components/form-field';
|
||||
|
||||
/**
|
||||
* @module FormField
|
||||
|
@ -22,6 +23,7 @@ import { dasherize } from 'vault/helpers/dasherize';
|
|||
*/
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
'data-test-field': true,
|
||||
classNames: ['field'],
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from '../templates/components/info-tooltip';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
'data-test-component': 'info-tooltip',
|
||||
tagName: 'span',
|
||||
classNames: ['is-inline-block'],
|
|
@ -11,6 +11,7 @@ let LinkedBlockComponent = Component.extend({
|
|||
classNames: 'linked-block',
|
||||
|
||||
queryParams: null,
|
||||
linkPrefix: null,
|
||||
|
||||
encode: false,
|
||||
|
||||
|
@ -35,6 +36,11 @@ let LinkedBlockComponent = Component.extend({
|
|||
if (queryParams) {
|
||||
params.push({ queryParams });
|
||||
}
|
||||
if (this.linkPrefix) {
|
||||
let targetRoute = this.params[0];
|
||||
targetRoute = `${this.linkPrefix}.${targetRoute}`;
|
||||
this.params[0] = targetRoute;
|
||||
}
|
||||
this.get('router').transitionTo(...params);
|
||||
}
|
||||
},
|
|
@ -1,8 +1,10 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import Component from '@ember/component';
|
||||
import { task } from 'ember-concurrency';
|
||||
import layout from '../templates/components/list-item';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
flashMessages: service(),
|
||||
tagName: '',
|
||||
linkParams: null,
|
|
@ -1,5 +1,7 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from '../../templates/components/list-item/content';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
|
@ -1,6 +1,8 @@
|
|||
import Component from '@ember/component';
|
||||
import layout from '../../templates/components/list-item/popup-menu';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
item: null,
|
||||
hasMenu: null,
|
|
@ -2,8 +2,10 @@ import { gt } from '@ember/object/computed';
|
|||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import { range } from 'ember-composable-helpers/helpers/range';
|
||||
import layout from '../templates/components/list-pagination';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
classNames: ['box', 'is-shadowless', 'list-pagination'],
|
||||
page: null,
|
||||
lastPage: null,
|
|
@ -1,14 +1,21 @@
|
|||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import { pluralize } from 'ember-inflector';
|
||||
import layout from '../templates/components/list-view';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
items: null,
|
||||
itemNoun: 'item',
|
||||
// the dasherized name of a component to render
|
||||
// in the EmptyState component if there are no items in items.length
|
||||
emptyActions: '',
|
||||
showPagination: computed('paginationRouteName', 'items.meta{lastPage,total}', function() {
|
||||
return this.paginationRouteName && this.items.meta.lastPage > 1 && this.items.meta.total > 0;
|
||||
}),
|
||||
|
||||
paginationRouteName: '',
|
||||
|
||||
emptyTitle: computed('itemNoun', function() {
|
||||
let items = pluralize(this.get('itemNoun'));
|
|
@ -1,6 +1,7 @@
|
|||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import autosize from 'autosize';
|
||||
import layout from '../templates/components/masked-input';
|
||||
|
||||
/**
|
||||
* @module MaskedInput
|
||||
|
@ -24,6 +25,7 @@ import autosize from 'autosize';
|
|||
*/
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
value: null,
|
||||
placeholder: 'value',
|
||||
didInsertElement() {
|
|
@ -2,8 +2,10 @@ import { inject as service } from '@ember/service';
|
|||
import { not } from '@ember/object/computed';
|
||||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import layout from '../templates/components/namespace-reminder';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
namespace: service(),
|
||||
showMessage: not('namespace.inRootNamespace'),
|
||||
//public API
|
|
@ -1,12 +1,16 @@
|
|||
import { schedule, debounce } from '@ember/runloop';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Component from '@ember/component';
|
||||
|
||||
//TODO MOVE THESE TO THE ADDON
|
||||
import utils from 'vault/lib/key-utils';
|
||||
import keys from 'vault/lib/keycodes';
|
||||
import FocusOnInsertMixin from 'vault/mixins/focus-on-insert';
|
||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||
|
||||
const routeFor = function(type, mode) {
|
||||
import layout from '../templates/components/navigate-input';
|
||||
|
||||
const routeFor = function(type, mode, urls) {
|
||||
const MODES = {
|
||||
secrets: 'vault.cluster.secrets.backend',
|
||||
'secrets-cert': 'vault.cluster.secrets.backend',
|
||||
|
@ -14,6 +18,11 @@ const routeFor = function(type, mode) {
|
|||
'policy-list': 'vault.cluster.policies',
|
||||
leases: 'vault.cluster.access.leases',
|
||||
};
|
||||
// urls object should have create, list, show keys
|
||||
// so we'll return that here
|
||||
if (urls) {
|
||||
return urls[type.replace('-root', '')];
|
||||
}
|
||||
let useSuffix = true;
|
||||
const typeVal = mode === 'secrets' || mode === 'leases' ? type : type.replace('-root', '');
|
||||
const modeKey = mode + '-' + typeVal;
|
||||
|
@ -26,9 +35,11 @@ const routeFor = function(type, mode) {
|
|||
};
|
||||
|
||||
export default Component.extend(FocusOnInsertMixin, {
|
||||
layout,
|
||||
router: service(),
|
||||
|
||||
classNames: ['navigate-filter'],
|
||||
urls: null,
|
||||
|
||||
// these get passed in from the outside
|
||||
// actions that get passed in
|
||||
|
@ -75,19 +86,25 @@ export default Component.extend(FocusOnInsertMixin, {
|
|||
return;
|
||||
}
|
||||
if (this.get('filterMatchesKey') && !utils.keyIsFolder(val)) {
|
||||
let params = [routeFor('show', mode), extraParams, this.keyForNav(val)].compact();
|
||||
let params = [routeFor('show', mode, this.urls), extraParams, this.keyForNav(val)].compact();
|
||||
this.transitionToRoute(...params);
|
||||
} else {
|
||||
if (mode === 'policies') {
|
||||
return;
|
||||
}
|
||||
let route = routeFor('create', mode);
|
||||
let route = routeFor('create', mode, this.urls);
|
||||
if (baseKey) {
|
||||
this.transitionToRoute(route, this.keyForNav(baseKey), {
|
||||
queryParams: {
|
||||
initialKey: val,
|
||||
},
|
||||
});
|
||||
} else if (this.urls) {
|
||||
this.transitionToRoute(route, {
|
||||
queryParams: {
|
||||
initialKey: this.keyForNav(val),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.transitionToRoute(route + '-root', {
|
||||
queryParams: {
|
||||
|
@ -136,7 +153,7 @@ export default Component.extend(FocusOnInsertMixin, {
|
|||
},
|
||||
|
||||
navigate(key, mode, pageFilter) {
|
||||
const route = routeFor(key ? 'list' : 'list-root', mode);
|
||||
const route = routeFor(key ? 'list' : 'list-root', mode, this.urls);
|
||||
let args = [route];
|
||||
if (key) {
|
||||
args.push(key);
|
||||
|
@ -161,7 +178,7 @@ export default Component.extend(FocusOnInsertMixin, {
|
|||
|
||||
filterUpdatedNoNav: function(val, mode) {
|
||||
var key = val ? val.trim() : null;
|
||||
this.transitionToRoute(routeFor('list-root', mode), {
|
||||
this.transitionToRoute(routeFor('list-root', mode, this.urls), {
|
||||
queryParams: {
|
||||
pageFilter: key,
|
||||
page: 1,
|
|
@ -1,8 +1,10 @@
|
|||
import ArrayProxy from '@ember/array/proxy';
|
||||
import Component from '@ember/component';
|
||||
import { set, computed } from '@ember/object';
|
||||
import layout from '../templates/components/string-list';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
'data-test-component': 'string-list',
|
||||
classNames: ['field', 'string-list', 'form-section'],
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import HoverDropdown from 'ember-basic-dropdown-hover/components/basic-dropdown-hover';
|
||||
import layout from '../templates/components/tool-tip';
|
||||
|
||||
export default HoverDropdown.extend({
|
||||
layout,
|
||||
delay: 0,
|
||||
horizontalPosition: 'auto-right',
|
||||
});
|
|
@ -17,6 +17,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import OuterHTML from './outer-html';
|
||||
import Component from '@ember/component';
|
||||
import layout from '../templates/components/toolbar-filters';
|
||||
|
||||
export default OuterHTML.extend({});
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { computed } from '@ember/object';
|
||||
import Mixin from '@ember/object/mixin';
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import commonPrefix from 'vault/utils/common-prefix';
|
||||
import commonPrefix from 'core/utils/common-prefix';
|
||||
|
||||
export default Mixin.create({
|
||||
queryParams: {
|
|
@ -0,0 +1,30 @@
|
|||
import Mixin from '@ember/object/mixin';
|
||||
import { get } from '@ember/object';
|
||||
|
||||
export default Mixin.create({
|
||||
queryParams: {
|
||||
page: {
|
||||
refreshModel: true,
|
||||
},
|
||||
pageFilter: {
|
||||
refreshModel: true,
|
||||
},
|
||||
},
|
||||
|
||||
setupController(controller, resolvedModel) {
|
||||
let { pageFilter } = this.paramsFor(this.routeName);
|
||||
this._super(...arguments);
|
||||
controller.setProperties({
|
||||
filter: pageFilter || '',
|
||||
page: get(resolvedModel || {}, 'meta.currentPage') || 1,
|
||||
});
|
||||
},
|
||||
|
||||
resetController(controller, isExiting) {
|
||||
this._super(...arguments);
|
||||
if (isExiting) {
|
||||
controller.set('pageFilter', null);
|
||||
controller.set('filter', null);
|
||||
}
|
||||
},
|
||||
});
|
|
@ -18,9 +18,21 @@
|
|||
<MessageError @model={{model}} data-test-edit-form-error />
|
||||
<div class="box is-sideless is-fullwidth is-marginless">
|
||||
<NamespaceReminder @mode="save" />
|
||||
{{#each model.fields as |attr|}}
|
||||
{{form-field data-test-field attr=attr model=model}}
|
||||
{{/each}}
|
||||
{{#if (or model.fields model.attrs)}}
|
||||
{{#each (or model.fields model.attrs) as |attr|}}
|
||||
<FormField
|
||||
data-test-field
|
||||
@attr={{attr}}
|
||||
@model={{model}}
|
||||
@mode={{@mode}}
|
||||
/>
|
||||
{{/each}}
|
||||
{{else if model.fieldGroups}}
|
||||
<FormFieldGroups
|
||||
@model={{model}}
|
||||
@mode={{@mode}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field is-grouped is-grouped-split is-fullwidth box is-bottomless">
|
||||
<div class="field is-grouped">
|
|
@ -3,11 +3,11 @@
|
|||
{{#each-in fieldGroup as |group fields|}}
|
||||
{{#if (or (eq group "default") (eq group "Options"))}}
|
||||
{{#each fields as |attr|}}
|
||||
{{#unless (eq attr.options.fieldValue 'id')}}
|
||||
<InfoTableRow @alwaysRender={{true}}
|
||||
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||
@value={{get @model attr.name}} />
|
||||
{{/unless}}
|
||||
<InfoTableRow
|
||||
@alwaysRender={{showAllFields}}
|
||||
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||
@value={{get @model attr.name}}
|
||||
/>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<div class="box {{unless showAllFields 'is-shadowless'}} is-sideless is-fullwidth is-marginless">
|
||||
|
@ -15,12 +15,14 @@
|
|||
{{group}}
|
||||
</h2>
|
||||
{{#each fields as |attr|}}
|
||||
<InfoTableRow @alwaysRender={{showAllFields}}
|
||||
<InfoTableRow
|
||||
@alwaysRender={{showAllFields}}
|
||||
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||
@value={{get @model attr.name}} />
|
||||
@value={{get @model attr.name}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each-in}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
|
@ -100,7 +100,7 @@
|
|||
initialValue=(or (get model valuePath) attr.options.defaultValue)
|
||||
labelText=labelString
|
||||
warning=attr.options.warning
|
||||
setDefaultValue=(or attr.options.setDefault false)
|
||||
setDefaultValue=(or (get model valuePath) attr.options.setDefault false)
|
||||
onChange=(action (action "setAndBroadcast" valuePath))
|
||||
}}
|
||||
{{else if (eq attr.options.editType "stringArray")}}
|
|
@ -1,7 +1,7 @@
|
|||
{{#if componentName}}
|
||||
{{component componentName item=item}}
|
||||
{{else if linkParams}}
|
||||
<LinkedBlock @params={{linkParams}} @class="list-item-row">
|
||||
<LinkedBlock @params={{linkParams}} @linkPrefix={{@linkPrefix}} @class="list-item-row">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left is-flex-1">
|
||||
{{#link-to params=linkParams class="has-text-weight-semibold has-text-black is-display-flex is-flex-1 is-no-underline"}}
|
|
@ -0,0 +1 @@
|
|||
{{yield}}
|
|
@ -0,0 +1,23 @@
|
|||
{{#if
|
||||
(or
|
||||
(and items.meta items.meta.total)
|
||||
items.length
|
||||
)
|
||||
}}
|
||||
<div class="box is-fullwidth is-bottomless is-sideless is-paddingless">
|
||||
{{#each items as |item|}}
|
||||
{{yield (hash item=item)}}
|
||||
{{else}}
|
||||
{{yield}}
|
||||
{{/each}}
|
||||
{{#if showPagination}}
|
||||
<ListPagination
|
||||
@page={{items.meta.currentPage}}
|
||||
@lastPage={{items.meta.lastPage}}
|
||||
@link={{@paginationRouteName}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{yield (hash empty=(component "empty-state" title=this.emptyTitle message=this.emptyMessage))}}
|
||||
{{/if}}
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/edit-form';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/field-group-show';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/form-field-groups';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/form-field';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/info-tooltip';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/linked-block';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/list-item';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/list-item/content';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/list-item/popup-menu';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/list-pagination';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/list-view';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/masked-input';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/namespace-reminder';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/navigate-input';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/string-list';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/tool-tip';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/components/toolbar-filters';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/helpers/path-or-array';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/mixins/list-controller';
|
|
@ -0,0 +1 @@
|
|||
export { default } from 'core/mixins/list-route';
|
|
@ -4,10 +4,12 @@
|
|||
"ember-addon"
|
||||
],
|
||||
"dependencies": {
|
||||
"autosize": "*",
|
||||
"Duration.js": "*",
|
||||
"base64-js": "*",
|
||||
"ember-auto-import": "*",
|
||||
"ember-basic-dropdown": "*",
|
||||
"ember-basic-dropdown-hover": "*",
|
||||
"ember-cli-babel": "*",
|
||||
"ember-cli-clipboard": "*",
|
||||
"ember-cli-htmlbars": "*",
|
||||
|
@ -17,7 +19,9 @@
|
|||
"ember-concurrency": "*",
|
||||
"ember-maybe-in-element": "*",
|
||||
"ember-radio-button": "*",
|
||||
"ember-router-helpers": "*",
|
||||
"ember-svg-jar": "*",
|
||||
"ember-truth-helpers": "*"
|
||||
"ember-truth-helpers": "*",
|
||||
"escape-string-regexp": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import layout from '../templates/components/header-credentials';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
secretMountPath: service(),
|
||||
scope: null,
|
||||
role: null,
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import layout from '../templates/components/header-scope';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
secretMountPath: service(),
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import layout from '../templates/components/kmip-breadcrumb';
|
||||
import { or } from '@ember/object/computed';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
tagName: '',
|
||||
secretMountPath: service(),
|
||||
shouldShowPath: or('showPath', 'scope', 'role'),
|
||||
showPath: false,
|
||||
path: null,
|
||||
scope: null,
|
||||
role: null,
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import ListController from 'core/mixins/list-controller';
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
mountPoint: computed(function() {
|
||||
return getOwner(this).mountPoint;
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import ListController from 'core/mixins/list-controller';
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
mountPoint: computed(function() {
|
||||
return getOwner(this).mountPoint;
|
||||
}),
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import ListController from 'core/mixins/list-controller';
|
||||
import Controller from '@ember/controller';
|
||||
import { computed } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
|
||||
export default Controller.extend(ListController, {
|
||||
mountPoint: computed(function() {
|
||||
return getOwner(this).mountPoint;
|
||||
}),
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue