UI OpenAPI fixes: itemType pluralization, hide deprecated attrs, utilize apiPath, fix get param label (#7166)

This commit is contained in:
Madalyn 2019-07-23 15:56:22 -04:00 committed by GitHub
parent f8cefa9b18
commit 18fa9e418c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 44 deletions

View File

@ -52,7 +52,7 @@ export default Route.extend(ListRoute, {
setupController(controller) {
this._super(...arguments);
const { apiPath, method, itemType } = this.getMethodAndModelInfo();
controller.set('itemType', singularize(itemType));
controller.set('itemType', itemType);
controller.set('method', method);
this.pathHelp.getPaths(apiPath, method, itemType).then(paths => {
controller.set('paths', paths.navPaths.reduce((acc, cur) => acc.concat(cur.path), []));

View File

@ -10,6 +10,7 @@ import { getOwner } from '@ember/application';
import { capitalize } from '@ember/string';
import { assign } from '@ember/polyfills';
import { expandOpenApiProps, combineAttributes } from 'vault/utils/openapi-to-attrs';
import { supportedAuthBackends } from 'vault/helpers/supported-auth-backends';
import fieldToAttrs from 'vault/utils/field-to-attrs';
import { resolve } from 'rsvp';
import { debug } from '@ember/debug';
@ -55,22 +56,20 @@ export default Service.extend({
//if we have an adapter already use that, otherwise create one
if (!adapterFactory) {
debug(`Creating new adapter for ${modelType}`);
const adapter = this.getNewAdapter(backend, paths, itemType);
const adapter = this.getNewAdapter(paths, itemType);
owner.register(`adapter:${modelType}`, adapter);
}
//if we have an item we want the create info for that itemType
let tag, path;
let path;
if (itemType) {
const createPath = paths.create.find(path => path.path.includes(itemType));
tag = createPath.tag; //tag is for type of backend, e.g. auth or secret
path = createPath.path;
path = path.slice(0, path.indexOf('{') - 1) + '/example';
} else {
//we need the mount config
tag = paths.configPath[0].tag;
path = paths.configPath[0].path;
}
helpUrl = `/v1/${tag}/${backend}${path}?help=true`;
helpUrl = `/v1/${apiPath}${path}?help=true`;
return this.registerNewModelWithProps(helpUrl, backend, newModel, modelName);
});
}
@ -79,31 +78,31 @@ export default Service.extend({
reducePaths(paths, currentPath) {
const pathName = currentPath[0];
const pathInfo = currentPath[1];
//config is a get/post endpoint that doesn't take route params
//and isn't also a list endpoint
//and isn't also a list endpoint and has an Action of Configure
if (
pathInfo.post &&
pathInfo.get &&
(pathInfo['x-vault-displayAttrs'] && pathInfo['x-vault-displayAttrs'].action === 'Configure')
) {
paths.configPath.push({ path: pathName, tag: pathInfo.get.tags[0] });
paths.configPath.push({ path: pathName });
return paths; //config path should only be config path
}
//list endpoints all have { name: "list" } in their get parameters
if (pathInfo.get && pathInfo.get.parameters && pathInfo.get.parameters[0].name === 'list') {
paths.list.push({ path: pathName, tag: pathInfo.get.tags[0] });
paths.list.push({ path: pathName });
}
if (pathInfo.delete) {
paths.delete.push({ path: pathName, tag: pathInfo.delete.tags[0] });
paths.delete.push({ path: pathName });
}
//create endpoints have path an action (e.g. "Create" or "Generate")
if (pathInfo.post && pathInfo['x-vault-displayAttrs'] && pathInfo['x-vault-displayAttrs'].action) {
paths.create.push({
path: pathName,
tag: pathInfo.post.tags[0],
action: pathInfo['x-vault-displayAttrs'].action,
});
}
@ -122,7 +121,7 @@ export default Service.extend({
let paths = Object.entries(pathInfo);
return paths.reduce(this.reducePaths, {
apiPath: [],
apiPath: apiPath,
configPath: [],
list: [],
create: [],
@ -149,16 +148,13 @@ export default Service.extend({
//include url params
if (params) {
const { name, schema, description } = params[0];
let label = capitalize(name);
if (label.toLowerCase() !== 'name') {
label += ' name';
}
let label = name.split('_').join(' ');
paramProp[name] = {
'x-vault-displayAttrs': {
name: name,
name: label,
group: 'default',
},
label: label,
type: schema.type,
description: description,
isId: true,
@ -174,16 +170,16 @@ export default Service.extend({
});
},
getNewAdapter(backend, paths, itemType) {
getNewAdapter(paths, itemType) {
//we need list and create paths to set the correct urls for actions
const { list, create } = paths;
const { list, create, apiPath } = paths;
const createPath = create.find(path => path.path.includes(itemType));
const listPath = list.find(pathInfo => pathInfo.path.includes(itemType));
const deletePath = paths.delete.find(path => path.path.includes(itemType));
return generatedItemAdapter.extend({
urlForItem(method, id) {
let { tag, path } = listPath;
let url = `${this.buildURL()}/${tag}/${backend}${path}/`;
let { path } = listPath;
let url = `${this.buildURL()}/${apiPath}${path}/`;
if (id) {
url = url + encodePath(id);
}
@ -195,22 +191,22 @@ export default Service.extend({
},
urlForUpdateRecord(id) {
let { tag, path } = createPath;
let { path } = createPath;
path = path.slice(0, path.indexOf('{') - 1);
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
return `${this.buildURL()}/${apiPath}${path}/${id}`;
},
urlForCreateRecord(modelType, snapshot) {
const { id } = snapshot;
let { tag, path } = createPath;
let { path } = createPath;
path = path.slice(0, path.indexOf('{') - 1);
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
return `${this.buildURL()}/${apiPath}${path}/${id}`;
},
urlForDeleteRecord(id) {
let { tag, path } = deletePath;
let { path } = deletePath;
path = path.slice(0, path.indexOf('{') - 1);
return `${this.buildURL()}/${tag}/${backend}${path}/${id}`;
return `${this.buildURL()}/${apiPath}${path}/${id}`;
},
});
},

View File

@ -22,10 +22,10 @@
<ToolbarActions>
<ToolbarLink @params={{array
"vault.cluster.access.method.item.create"
(pluralize itemType)
itemType
}}>
Create
{{itemType}}
{{singularize itemType}}
</ToolbarLink>
</ToolbarActions>
</Toolbar>
@ -35,27 +35,27 @@
@message="A list of {{pluralize itemType}} will be listed here. Create your first {{itemType}} to get started.">
{{#link-to
"vault.cluster.access.method.item.create"
(pluralize itemType)
itemType
class="link"
}}
Create {{itemType}}
Create {{singularize itemType}}
{{/link-to}}
</list.empty>
{{else if list.item}}
<ListItem @linkParams={{array "vault.cluster.access.method.item.show"
(pluralize itemType) list.item.id}} as |Item|>
itemType list.item.id}} as |Item|>
<Item.content>
<Icon @glyph="folder-outline" class="has-text-grey-light" @size="l" />{{list.item.id}}
</Item.content>
<Item.menu>
<li class="action">
{{#link-to "vault.cluster.access.method.item.show" list.item.id class="is-block"}}
View {{itemType}}
View {{singularize itemType}}
{{/link-to}}
</li>
<li class="action">
{{#link-to "vault.cluster.access.method.item.edit" list.item.id class="is-block"}}
Edit {{itemType}}
Edit {{singularize itemType}}
{{/link-to}}
</li>
<li>
@ -64,14 +64,14 @@
Item.callMethod
"destroyRecord"
list.item
(concat "Successfully deleted " itemType " " list.item.id)
(concat "There was an error deleting this " itemType)
(concat "Successfully deleted " (singularize itemType) " " list.item.id)
(concat "There was an error deleting this " (singularize itemType))
(action "refreshItemList")
)
}} @confirmMessage={{concat "Are you sure you want to delete " list.item.id "?"}}
@cancelButtonText="Cancel" data-test-secret-delete="true">
Delete
{{itemType}}
{{singularize itemType}}
</ConfirmAction>
</li>
</Item.menu>

View File

@ -8,7 +8,7 @@
</span>
{{#link-to
"vault.cluster.access.method.item.list"
(pluralize itemType)
itemType
}}
{{pluralize itemType}}
{{/link-to}}
@ -41,9 +41,9 @@
Delete
{{itemType}}
</ConfirmAction>
<ToolbarLink @params={{array "vault.cluster.access.method.item.edit" (pluralize itemType) model.id}}
<ToolbarLink @params={{array "vault.cluster.access.method.item.edit" itemType model.id}}
@data-test-configure-link="true">
Edit {{itemType}}
Edit {{singularize itemType}}
</ToolbarLink>
</ToolbarActions>
</Toolbar>

View File

@ -8,7 +8,10 @@ export const expandOpenApiProps = function(props) {
// expand all attributes
for (const propName in props) {
const prop = props[propName];
let { description, items, type, format, isId, label } = prop;
let { description, items, type, format, isId, deprecated } = prop;
if (deprecated === true) {
continue;
}
let { name, value, group, sensitive } = prop['x-vault-displayAttrs'] || {};
if (type === 'integer') {
@ -21,11 +24,11 @@ export const expandOpenApiProps = function(props) {
} else if (items) {
editType = items.type + capitalize(type);
}
let attrDefn = {
editType,
helpText: description,
sensitive: sensitive,
label: name || label,
possibleValues: prop['enum'],
fieldValue: isId ? 'id' : null,
fieldGroup: group || 'default',
@ -33,6 +36,8 @@ export const expandOpenApiProps = function(props) {
defaultValue: value || null,
};
attrDefn.label = capitalize(name || propName);
// ttls write as a string and read as a number
// so setting type on them runs the wrong transform
if (editType !== 'ttl' && type !== 'array') {

View File

@ -58,32 +58,36 @@ module('Unit | Util | OpenAPI Data Utilities', function() {
editType: 'stringArray',
defaultValue: 'Grace Hopper,Lady Ada',
fieldGroup: 'default',
label: 'Awesome-people',
},
favoriteIceCream: {
editType: 'string',
type: 'string',
possibleValues: ['vanilla', 'chocolate', 'strawberry'],
fieldGroup: 'default',
label: 'Favorite-ice-cream',
},
defaultValue: {
editType: 'number',
type: 'number',
defaultValue: 300,
fieldGroup: 'default',
label: 'Default-value',
},
default: {
editType: 'number',
type: 'number',
defaultValue: 30,
fieldGroup: 'default',
label: 'Default',
},
superSecret: {
type: 'string',
editType: 'string',
sensitive: true,
helpText: 'A really secret thing',
fieldGroup: 'default',
label: 'Super-secret',
},
};