diff --git a/builtin/credential/ldap/path_config.go b/builtin/credential/ldap/path_config.go index c7d1b76916e0..0d2eb3608ef6 100644 --- a/builtin/credential/ldap/path_config.go +++ b/builtin/credential/ldap/path_config.go @@ -21,6 +21,9 @@ func pathConfig(b *backend) *framework.Path { HelpSynopsis: pathConfigHelpSyn, HelpDescription: pathConfigHelpDesc, + DisplayAttrs: &framework.DisplayAttributes{ + Action: "Configure", + }, } } diff --git a/builtin/credential/ldap/path_groups.go b/builtin/credential/ldap/path_groups.go index 9222496449e0..76e64c4505a0 100644 --- a/builtin/credential/ldap/path_groups.go +++ b/builtin/credential/ldap/path_groups.go @@ -48,6 +48,9 @@ func pathGroups(b *backend) *framework.Path { HelpSynopsis: pathGroupHelpSyn, HelpDescription: pathGroupHelpDesc, + DisplayAttrs: &framework.DisplayAttributes{ + Action: "Create", + }, } } diff --git a/builtin/credential/ldap/path_users.go b/builtin/credential/ldap/path_users.go index 3371c44248c4..60276cf64e5e 100644 --- a/builtin/credential/ldap/path_users.go +++ b/builtin/credential/ldap/path_users.go @@ -22,6 +22,7 @@ func pathUsersList(b *backend) *framework.Path { HelpDescription: pathUserHelpDesc, DisplayAttrs: &framework.DisplayAttributes{ Navigation: true, + Action: "Create", }, } } @@ -54,6 +55,9 @@ func pathUsers(b *backend) *framework.Path { HelpSynopsis: pathUserHelpSyn, HelpDescription: pathUserHelpDesc, + DisplayAttrs: &framework.DisplayAttributes{ + Action: "Create", + }, } } diff --git a/ui/app/components/generated-item-list.js b/ui/app/components/generated-item-list.js new file mode 100644 index 000000000000..61258ba040ca --- /dev/null +++ b/ui/app/components/generated-item-list.js @@ -0,0 +1,31 @@ +import { inject as service } from '@ember/service'; +import Component from '@ember/component'; +import { getOwner } from '@ember/application'; + +/** + * @module GeneratedItemList + * The `GeneratedItemList` component lists generated items related to mounts (e.g. groups, roles, users) + * + * @example + * ```js + * + * ``` + * + * @property model=null {DS.Model} - The corresponding item model that is being configured. + * @property itemType {String} - the type of item displayed + * + */ + +export default Component.extend({ + model: null, + itemType: null, + router: service(), + store: service(), + actions: { + refreshItemList() { + let route = getOwner(this).lookup(`route:${this.router.currentRouteName}`); + this.store.clearAllDatasets(); + route.refresh(); + }, + }, +}); diff --git a/ui/app/components/generated-item.js b/ui/app/components/generated-item.js index a6ee1a6db86c..ccf815c8806d 100644 --- a/ui/app/components/generated-item.js +++ b/ui/app/components/generated-item.js @@ -6,7 +6,7 @@ import DS from 'ember-data'; /** * @module GeneratedItem - * The `GeneratedItem` is the form to configure generated items related to mounts (e.g. groups, roles, users) + * The `GeneratedItem` component is the form to configure generated items related to mounts (e.g. groups, roles, users) * * @example * ```js diff --git a/ui/app/helpers/tabs-for-auth-section.js b/ui/app/helpers/tabs-for-auth-section.js index 399fdb850c0f..c66ed62220d6 100644 --- a/ui/app/helpers/tabs-for-auth-section.js +++ b/ui/app/helpers/tabs-for-auth-section.js @@ -85,7 +85,6 @@ export function tabsForAuthSection([model, sectionType = 'authSettings', paths]) }); return tabs; } - if (paths) { tabs = paths.map(path => { let itemName = path.slice(1); //get rid of leading slash diff --git a/ui/app/routes/vault/cluster/access/method.js b/ui/app/routes/vault/cluster/access/method.js index 8bf31415e2f8..c29851ce9cea 100644 --- a/ui/app/routes/vault/cluster/access/method.js +++ b/ui/app/routes/vault/cluster/access/method.js @@ -6,7 +6,6 @@ import { inject as service } from '@ember/service'; export default Route.extend({ pathHelp: service('path-help'), model(params) { - // eslint-disable-line rule const { path } = params; return this.store.findAll('auth-method').then(modelArray => { const model = modelArray.findBy('id', path); diff --git a/ui/app/routes/vault/cluster/access/method/index.js b/ui/app/routes/vault/cluster/access/method/index.js index 58b2fa477aa6..a3bff252cb83 100644 --- a/ui/app/routes/vault/cluster/access/method/index.js +++ b/ui/app/routes/vault/cluster/access/method/index.js @@ -1,7 +1,10 @@ import Route from '@ember/routing/route'; - +import { tabsForAuthSection } from 'vault/helpers/tabs-for-auth-section'; export default Route.extend({ beforeModel() { - return this.transitionTo('vault.cluster.access.method.section', 'configuration'); + let { methodType, paths } = this.modelFor('vault.cluster.access.method'); + paths = paths ? paths.navPaths.reduce((acc, cur) => acc.concat(cur.path), []) : null; + const activeTab = tabsForAuthSection([methodType, 'authConfig', paths])[0].routeParams; + return this.transitionTo(...activeTab); }, }); diff --git a/ui/app/routes/vault/cluster/access/method/item.js b/ui/app/routes/vault/cluster/access/method/item.js index 1b4d73f38466..45b52698d7a9 100644 --- a/ui/app/routes/vault/cluster/access/method/item.js +++ b/ui/app/routes/vault/cluster/access/method/item.js @@ -7,22 +7,25 @@ export default Route.extend({ pathHelp: service('path-help'), beforeModel() { - const { item_type: itemType } = this.paramsFor(this.routeName); - const { path: method } = this.paramsFor('vault.cluster.access.method'); - let methodModel = this.modelFor('vault.cluster.access.method'); - let { apiPath, type } = methodModel; + const { apiPath, type, method, itemType } = this.getMethodAndModelInfo(); let modelType = `generated-${singularize(itemType)}-${type}`; return this.pathHelp.getNewModel(modelType, method, apiPath, itemType); }, + getMethodAndModelInfo() { + const { item_type: itemType } = this.paramsFor(this.routeName); + const { path: method } = this.paramsFor('vault.cluster.access.method'); + const methodModel = this.modelFor('vault.cluster.access.method'); + const { apiPath, type } = methodModel; + return { apiPath, type, method, itemType }; + }, + setupController(controller) { this._super(...arguments); - const { item_type: itemType } = this.paramsFor(this.routeName); - const { path } = this.paramsFor('vault.cluster.access.method'); - const { apiPath } = this.modelFor('vault.cluster.access.method'); + const { apiPath, method, itemType } = this.getMethodAndModelInfo(); controller.set('itemType', itemType); - controller.set('method', path); - this.pathHelp.getPaths(apiPath, path, itemType).then(paths => { + controller.set('method', method); + this.pathHelp.getPaths(apiPath, method, itemType).then(paths => { controller.set('paths', Array.from(paths.list, pathInfo => pathInfo.path)); }); }, diff --git a/ui/app/routes/vault/cluster/access/method/item/list.js b/ui/app/routes/vault/cluster/access/method/item/list.js index 65d9dee7896d..5c62ed3f3386 100644 --- a/ui/app/routes/vault/cluster/access/method/item/list.js +++ b/ui/app/routes/vault/cluster/access/method/item/list.js @@ -6,13 +6,19 @@ import ListRoute from 'vault/mixins/list-route'; export default Route.extend(ListRoute, { wizard: service(), pathHelp: service('path-help'), - model() { + + getMethodAndModelInfo() { const { item_type: itemType } = this.paramsFor('vault.cluster.access.method.item'); - const { page, pageFilter } = this.paramsFor(this.routeName); + const { path: method } = this.paramsFor('vault.cluster.access.method'); const methodModel = this.modelFor('vault.cluster.access.method'); - const { type } = methodModel; + const { apiPath, type } = methodModel; + return { apiPath, type, method, itemType }; + }, + + model() { + const { type, method, itemType } = this.getMethodAndModelInfo(); + const { page, pageFilter } = this.paramsFor(this.routeName); let modelType = `generated-${singularize(itemType)}-${type}`; - const { path: method } = this.paramsFor('vault.cluster.access.method'); return this.store .lazyPaginatedQuery(modelType, { @@ -38,16 +44,18 @@ export default Route.extend(ListRoute, { } return true; }, + reload() { + this.store.clearAllDatasets(); + this.refresh(); + }, }, setupController(controller) { this._super(...arguments); - const { item_type: itemType } = this.paramsFor('vault.cluster.access.method.item'); - let { path } = this.paramsFor('vault.cluster.access.method'); + const { apiPath, method, itemType } = this.getMethodAndModelInfo(); controller.set('itemType', singularize(itemType)); - controller.set('method', path); - const { apiPath } = this.modelFor('vault.cluster.access.method'); - this.pathHelp.getPaths(apiPath, path, itemType).then(paths => { - controller.set('paths', Array.from(paths.list, pathInfo => pathInfo.path)); + controller.set('method', method); + this.pathHelp.getPaths(apiPath, method, itemType).then(paths => { + controller.set('paths', paths.navPaths.reduce((acc, cur) => acc.concat(cur.path), [])); }); }, }); diff --git a/ui/app/routes/vault/cluster/access/method/section.js b/ui/app/routes/vault/cluster/access/method/section.js index dc982188f990..ee58779d6ecc 100644 --- a/ui/app/routes/vault/cluster/access/method/section.js +++ b/ui/app/routes/vault/cluster/access/method/section.js @@ -6,6 +6,7 @@ import DS from 'ember-data'; export default Route.extend({ wizard: service(), + model(params) { const { section_name: section } = params; if (section !== 'configuration') { diff --git a/ui/app/services/path-help.js b/ui/app/services/path-help.js index 1b5acfc7ec6c..16bf86628aac 100644 --- a/ui/app/services/path-help.js +++ b/ui/app/services/path-help.js @@ -61,8 +61,9 @@ export default Service.extend({ //if we have an item we want the create info for that itemType let tag, path; if (itemType) { - tag = paths.create[0].tag; - path = paths.create[0].path; + 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 @@ -75,80 +76,59 @@ export default Service.extend({ } }, - getPaths(apiPath, backend, itemType) { - debug(`Fetching relevant paths for ${backend} from ${apiPath}`); - return this.ajax(`/v1/${apiPath}?help=1`, backend).then(help => { - const pathInfo = help.openapi.paths; - let paths = Object.keys(pathInfo); + 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 + 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] }); + return paths; //config path should only be config path + } - //TODO: consolidate this into a single reduce() - //config is a get/post endpoint that doesn't take route params - //and isn't also a list endpoint - const configPath = paths - .map(path => { - if ( - pathInfo[path].post && - !path.includes('{') && - pathInfo[path].get && - (!pathInfo[path].get.parameters || pathInfo[path].get.parameters[0].name !== 'list') - ) { - return { path: path, tag: pathInfo[path].get.tags[0] }; - } - }) - .compact(); + //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] }); + } - //list endpoints all have { name: "list" } in their get parameters - const listPaths = paths - .map(path => { - if ( - pathInfo[path].get && - pathInfo[path].get.parameters && - pathInfo[path].get.parameters[0].name == 'list' - ) { - return { path: path, tag: pathInfo[path].get.tags[0] }; - } - }) - .compact(); + if (pathInfo.delete) { + paths.delete.push({ path: pathName, tag: pathInfo.delete.tags[0] }); + } - //we always want to keep list endpoints for menus - //but only use scoped post/delete endpoints - if (itemType) { - paths = paths.filter(path => path.includes(itemType)); - } - const deletePaths = paths - .map(path => { - if (pathInfo[path].delete) { - return { path: path, tag: pathInfo[path].delete.tags[0] }; - } - }) - .compact(); + //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, + }); + } - //create endpoints have path params, signified by "{}" - //we have to filter out login endpoints for auth methods - const createPaths = paths - .map(path => { - if (pathInfo[path].post && path.includes('{') && !path.includes('login')) { - return { path: path, tag: pathInfo[path].post.tags[0] }; - } - }) - .compact(); + if (pathInfo['x-vault-displayAttrs'] && pathInfo['x-vault-displayAttrs'].navigation) { + paths.navPaths.push({ path: pathName }); + } + + return paths; + }, - const navPaths = paths - .map(path => { - if (pathInfo[path]['x-vault-displayAttrs'] && pathInfo[path]['x-vault-displayAttrs'].navigation) { - return { path: path }; - } - }) - .compact(); - //return paths object with all relevant information - return { - apiPath: apiPath, - configPath: configPath, - list: listPaths, - create: createPaths, - delete: deletePaths, - navPaths: navPaths, - }; + getPaths(apiPath, backend) { + debug(`Fetching relevant paths for ${backend} from ${apiPath}`); + return this.ajax(`/v1/${apiPath}?help=1`, backend).then(help => { + const pathInfo = help.openapi.paths; + let paths = Object.entries(pathInfo); + + return paths.reduce(this.reducePaths, { + apiPath: [], + configPath: [], + list: [], + create: [], + delete: [], + navPaths: [], + }); }); }, @@ -157,6 +137,7 @@ export default Service.extend({ //as determined by the expandOpenApiProps util getProps(helpUrl, backend) { debug(`Fetching schema properties for ${backend} from ${helpUrl}`); + return this.ajax(helpUrl, backend).then(help => { //paths is an array but it will have a single entry // for the scope we're in @@ -196,9 +177,11 @@ export default Service.extend({ getNewAdapter(backend, paths, itemType) { //we need list and create paths to set the correct urls for actions const { list, create } = 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 listPath = list.find(pathInfo => pathInfo.path.includes(itemType)); let { tag, path } = listPath; let url = `${this.buildURL()}/${tag}/${backend}${path}/`; if (id) { @@ -212,20 +195,20 @@ export default Service.extend({ }, urlForUpdateRecord(id) { - let { tag, path } = create[0]; + let { tag, path } = createPath; path = path.slice(0, path.indexOf('{') - 1); return `${this.buildURL()}/${tag}/${backend}${path}/${id}`; }, urlForCreateRecord(modelType, snapshot) { const { id } = snapshot; - let { tag, path } = create[0]; + let { tag, path } = createPath; path = path.slice(0, path.indexOf('{') - 1); return `${this.buildURL()}/${tag}/${backend}${path}/${id}`; }, urlForDeleteRecord(id) { - let { tag, path } = paths.delete[0]; + let { tag, path } = deletePath; path = path.slice(0, path.indexOf('{') - 1); return `${this.buildURL()}/${tag}/${backend}${path}/${id}`; }, diff --git a/ui/app/templates/components/generated-item-list.hbs b/ui/app/templates/components/generated-item-list.hbs new file mode 100644 index 000000000000..1838ae873863 --- /dev/null +++ b/ui/app/templates/components/generated-item-list.hbs @@ -0,0 +1,80 @@ + + + {{#key-value-header path="vault.cluster.access.methods"}} +
  • + + / + + {{#link-to "vault.cluster.access.methods"}} + methods + {{/link-to}} +
  • + {{/key-value-header}} +
    + +

    + {{method}} +

    +
    +
    +{{section-tabs model "authShow" paths}} + + + + Create + {{itemType}} + + + + + {{#if list.empty}} + + {{#link-to + "vault.cluster.access.method.item.create" + (pluralize itemType) + class="link" + }} + Create {{itemType}} + {{/link-to}} + + {{else if list.item}} + + + {{list.item.id}} + + +
  • + {{#link-to "vault.cluster.access.method.item.show" list.item.id class="is-block"}} + View {{itemType}} + {{/link-to}} +
  • +
  • + {{#link-to "vault.cluster.access.method.item.edit" list.item.id class="is-block"}} + Edit {{itemType}} + {{/link-to}} +
  • +
  • + + Delete + {{itemType}} + +
  • +
    +
    + {{/if}} +
    \ No newline at end of file diff --git a/ui/app/templates/components/generated-item.hbs b/ui/app/templates/components/generated-item.hbs index fd2e8efd9d7f..8a16e0ada00a 100644 --- a/ui/app/templates/components/generated-item.hbs +++ b/ui/app/templates/components/generated-item.hbs @@ -25,11 +25,14 @@

    {{capitalize mode}} {{singularize itemType}} + {{#if (eq mode "edit")}} + {{model.id}} + {{/if}}

    {{/if}} -{{#if (not (eq mode "create"))}} +{{#if (eq mode "show")}} - - {{#key-value-header path="vault.cluster.access.methods"}} -
  • - - / - - {{#link-to "vault.cluster.access.methods"}} - methods - {{/link-to}} -
  • - {{/key-value-header}} -
    - -

    - {{capitalize method}} -

    -
    - -{{section-tabs model "authShow" paths}} - - - - Create - {{itemType}} - - - -{{#if model.meta.total}} - {{#each model as |item|}} - {{#linked-block - "vault.cluster.access.method.item.show" - (pluralize itemType) - item.id - class="list-item-row" - data-test-method-row=true - }} -
    -
    - {{#link-to - "vault.cluster.access.method.item.show" - (pluralize itemType) - item.id - class="is-block has-text-black has-text-weight-semibold" - data-test-method-link=true - }} - - {{item.id}} - - {{/link-to}} -
    - {{item.id}} -
    -
    -
    - {{/linked-block}} - {{/each}} - {{#if (gt model.meta.lastPage 1)}} - {{list-pagination - page=model.meta.currentPage - lastPage=model.meta.lastPage - link="vault.cluster.access.method.item.list" - }} - {{/if}} -{{else}} - - {{#link-to - "vault.cluster.access.method.item.create" - (pluralize itemType) - tagName="button" - class="link" - }} - - Create - {{itemType}} - - - {{/link-to}} - -{{/if}} \ No newline at end of file + \ No newline at end of file diff --git a/ui/app/templates/vault/cluster/access/method/section.hbs b/ui/app/templates/vault/cluster/access/method/section.hbs index 72b9a301ca1e..7c6f1136d3ae 100644 --- a/ui/app/templates/vault/cluster/access/method/section.hbs +++ b/ui/app/templates/vault/cluster/access/method/section.hbs @@ -13,7 +13,7 @@

    - {{capitalize model.id}} + {{model.id}}

    @@ -21,10 +21,7 @@ {{#if (eq section "configuration")}} - + Configure diff --git a/ui/app/templates/vault/cluster/access/methods.hbs b/ui/app/templates/vault/cluster/access/methods.hbs index fbc609681786..fe0938bc6675 100644 --- a/ui/app/templates/vault/cluster/access/methods.hbs +++ b/ui/app/templates/vault/cluster/access/methods.hbs @@ -8,10 +8,7 @@ - + Enable new method @@ -19,158 +16,136 @@ {{#each (sort-by "path" model) as |method|}} {{#if (eq method.methodType "ldap")}} - -
    -
    -
    - - - +
    +
    +
    + + + - - -
    - {{method.methodType}} -
    -
    -
    - - {{method.path}} - -
    - + }} @size="l" class="has-text-grey-light" /> + + +
    + {{method.methodType}} +
    +
    + + + {{method.path}} + +
    + {{method.accessor}} - +
    +
    -
    -
    -
    - {{#popup-menu name="auth-backend-nav"}} - + {{/popup-menu}} +
    -
    - + {{else}} -
    -
    -
    -
    - - - +
    +
    +
    + + + - - -
    - {{method.methodType}} -
    -
    -
    - - {{method.path}} - -
    - + }} @size="l" class="has-text-grey-light" /> + + +
    + {{method.methodType}} +
    +
    + + + {{method.path}} + +
    + {{method.accessor}} - +
    +
    -
    -
    -
    - {{#popup-menu name="auth-backend-nav"}} - + {{/popup-menu}} +
    -
    {{/if}} -{{/each}} +{{/each}} \ No newline at end of file diff --git a/ui/app/utils/openapi-to-attrs.js b/ui/app/utils/openapi-to-attrs.js index fd516304eddb..5717eb3a34b1 100644 --- a/ui/app/utils/openapi-to-attrs.js +++ b/ui/app/utils/openapi-to-attrs.js @@ -32,9 +32,10 @@ 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') { + if (editType !== 'ttl' && type !== 'array') { attrDefn.type = type; } // loop to remove empty vals diff --git a/ui/lib/core/addon/templates/components/edit-form.hbs b/ui/lib/core/addon/templates/components/edit-form.hbs index b439bea5c1f2..0c179a82e3dd 100644 --- a/ui/lib/core/addon/templates/components/edit-form.hbs +++ b/ui/lib/core/addon/templates/components/edit-form.hbs @@ -1,43 +1,20 @@ -{{#if model.canDelete}} - - - - - {{deleteButtonText}} - - - - -{{/if}}
    {{#if (or model.fields model.attrs)}} {{#each (or model.fields model.attrs) as |attr|}} - + {{/each}} {{else if model.fieldGroups}} - + {{/if}}
    -
    @@ -50,4 +27,4 @@ {{/if}}
    - + \ No newline at end of file diff --git a/ui/lib/core/addon/templates/components/field-group-show.hbs b/ui/lib/core/addon/templates/components/field-group-show.hbs index 9207497ca5d3..04e3b843402e 100644 --- a/ui/lib/core/addon/templates/components/field-group-show.hbs +++ b/ui/lib/core/addon/templates/components/field-group-show.hbs @@ -3,11 +3,11 @@ {{#each-in fieldGroup as |group fields|}} {{#if (or (eq group "default") (eq group "Options"))}} {{#each fields as |attr|}} - + {{#if (not-eq attr.options.fieldValue "id")}} + + {{/if}} {{/each}} {{else}}
    @@ -15,14 +15,12 @@ {{group}} {{#each fields as |attr|}} - + @value={{get @model attr.name}} /> {{/each}}
    {{/if}} {{/each-in}} {{/each}} -
    +
    \ No newline at end of file diff --git a/ui/tests/integration/components/edit-form-test.js b/ui/tests/integration/components/edit-form-test.js index 62cfe85a65d8..ddf4c6287a21 100644 --- a/ui/tests/integration/components/edit-form-test.js +++ b/ui/tests/integration/components/edit-form-test.js @@ -46,19 +46,6 @@ module('Integration | Component | edit form', function(hooks) { await render(hbs`{{edit-form model=model}}`); assert.ok(component.fields.length, 2); - assert.ok(component.showsDelete); - assert.equal(component.deleteText, 'Delete'); - }); - - test('it renders: custom deleteButton', async function(assert) { - let model = createModel(); - let delText = 'Exterminate'; - this.set('model', model); - this.set('deleteButtonText', delText); - await render(hbs`{{edit-form model=model deleteButtonText=deleteButtonText}}`); - - assert.ok(component.showsDelete); - assert.equal(component.deleteText, delText); }); test('it calls flash message fns on save', async function(assert) { diff --git a/ui/tests/unit/utils/openapi-to-attrs-test.js b/ui/tests/unit/utils/openapi-to-attrs-test.js index 6c3bd82ed012..d62138ab4e05 100644 --- a/ui/tests/unit/utils/openapi-to-attrs-test.js +++ b/ui/tests/unit/utils/openapi-to-attrs-test.js @@ -56,7 +56,6 @@ module('Unit | Util | OpenAPI Data Utilities', function() { }, awesomePeople: { editType: 'stringArray', - type: 'array', defaultValue: 'Grace Hopper,Lady Ada', fieldGroup: 'default', }, @@ -126,7 +125,6 @@ module('Unit | Util | OpenAPI Data Utilities', function() { awesomePeople: attr({ label: 'People Who Are Awesome', editType: 'stringArray', - type: 'array', defaultValue: 'Grace Hopper,Lady Ada', }), favoriteIceCream: attr('string', {