From 6e77ea655f4df1c403520cc16d9740856026e226 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 26 Jan 2022 13:03:21 -0500 Subject: [PATCH] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20support=20for=20"?= =?UTF-8?q?unknown"=20dynamic=20host=20catalogs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/models/host-catalog.js | 32 ++++++--- addons/api/mirage/factories/host-catalog.js | 25 ++++++- .../generated/factories/host-catalog.js | 11 +-- addons/api/mirage/scenarios/default.js | 2 +- .../tests/unit/models/host-catalog-test.js | 72 ++++++++++++------- addons/core/translations/resources/en-us.yaml | 3 + .../scopes/scope/host-catalogs/index.hbs | 14 +++- 7 files changed, 114 insertions(+), 45 deletions(-) diff --git a/addons/api/addon/models/host-catalog.js b/addons/api/addon/models/host-catalog.js index 8a0a64bd5..ec34b50e3 100644 --- a/addons/api/addon/models/host-catalog.js +++ b/addons/api/addon/models/host-catalog.js @@ -1,8 +1,12 @@ import GeneratedHostCatalogModel from '../generated/models/host-catalog'; +export const types = ['aws', 'azure']; + export default class HostCatalogModel extends GeneratedHostCatalogModel { + // =attributes + /** - * Returns if the host-catalog is static type or not. + * True if the host catalog is static. * @type {boolean} */ get isStatic() { @@ -10,7 +14,7 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel { } /** - * Returns if the host-catalog is a plugin or not. + * True if the host catalog is a plugin. * @type {boolean} */ get isPlugin() { @@ -18,7 +22,15 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel { } /** - * Returns if host-catalog plugin is AWS or not + * True if the host catalog is an unknown type. + * @type {boolean} + */ + get isUnknown() { + return this.isPlugin && !types.includes(this.plugin.name); + } + + /** + * True if host catalog plugin type is AWS. * @type {boolean} */ get isAWS() { @@ -26,23 +38,27 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel { } /** - * Return if host-catalog plugin is Azure or not. + * True if host catalog plugin type is Azure. * @type {boolean} */ get isAzure() { return this.compositeType === 'azure'; } - /** If host-catalog is a plugins returns its name, - * otherwise returns the host-catalog type + /** + * If host catalog is a plugin return `plugin.name`, + * otherwise return the host catalog type. * @type {string} */ get compositeType() { - return this.isPlugin ? this.plugin.name : this.type; + if (this.isUnknown) return 'unknown'; + if (this.isPlugin) return this.plugin.name; + return 'static'; } /** - * Sets type, if type is different than static, sets plugin name to type + * Sets `type`. If type is different than `static`, sets `type` to `plugin` + * and `plugin.name` to the specified type. */ set compositeType(type) { if (type === 'static') { diff --git a/addons/api/mirage/factories/host-catalog.js b/addons/api/mirage/factories/host-catalog.js index 3179f2c99..4cd7423ae 100644 --- a/addons/api/mirage/factories/host-catalog.js +++ b/addons/api/mirage/factories/host-catalog.js @@ -1,7 +1,14 @@ import factory from '../generated/factories/host-catalog'; import { trait } from 'ember-cli-mirage'; import permissions from '../helpers/permissions'; -import { datatype, address } from 'faker'; +import { datatype, address, random } from 'faker'; + +const types = ['static', 'plugin']; +// Represents known plugin types, except "foobar" which models the possibility +// of receiving an _unknown_ type, which the UI must handle gracefully. +const pluginTypes = ['aws', 'azure', 'foobar']; + +let pluginTypeCounter = 1; export default factory.extend({ authorized_actions: () => @@ -17,6 +24,22 @@ export default factory.extend({ 'host-sets': ['create', 'list'], }; }, + + id: (i) => `host-catalog-id-${i}`, + + // Cycle through available types + type: (i) => types[i % types.length], + + plugin: function (i) { + if (this.type === 'plugin') { + return { + id: `plugin-id-${i}`, + name: pluginTypes[pluginTypeCounter++ % pluginTypes.length], + description: random.words(), + }; + } + }, + attributes() { switch (this.plugin?.name) { case 'aws': diff --git a/addons/api/mirage/generated/factories/host-catalog.js b/addons/api/mirage/generated/factories/host-catalog.js index fa8135226..36d5e64c6 100644 --- a/addons/api/mirage/generated/factories/host-catalog.js +++ b/addons/api/mirage/generated/factories/host-catalog.js @@ -5,19 +5,10 @@ import { random, date, datatype } from 'faker'; * GeneratedHostCatalogModelFactory */ export default Factory.extend({ - type: () => random.arrayElement(['static', 'plugin']), + type: 'static', name: () => random.words(), description: () => random.words(), created_time: () => date.recent(), updated_time: () => date.recent(), disabled: () => datatype.boolean(), - plugin: function (i) { - if (this.type == 'plugin') { - return { - id: `pl_${datatype.hexaDecimal(5)}`, - name: i % 2 ? 'aws' : 'azure', - description: random.words(), - }; - } - }, }); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index 51175f672..ceb61b566 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -46,7 +46,7 @@ export default function (server) { // Other resources server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => { - server.createList('host-catalog', 4, { scope }, 'withChildren'); + server.createList('host-catalog', 8, { scope }, 'withChildren'); server.createList('credential-store', 3, { scope }, 'withAssociations'); server.createList('target', 2, { scope }, 'withAssociations'); // Sessions have target data. Create it after targets. diff --git a/addons/api/tests/unit/models/host-catalog-test.js b/addons/api/tests/unit/models/host-catalog-test.js index 7a8a77147..fb2c2cf51 100644 --- a/addons/api/tests/unit/models/host-catalog-test.js +++ b/addons/api/tests/unit/models/host-catalog-test.js @@ -10,29 +10,52 @@ module('Unit | Model | host catalog', function (hooks) { assert.ok(model); }); - test('it has isStatic function and returns the expected values', async function (assert) { + test('it has isStatic property and returns the expected values', async function (assert) { assert.expect(3); const store = this.owner.lookup('service:store'); - const modelA = store.createRecord('host-catalog', { type: 'static' }); - const modelB = store.createRecord('host-catalog', { type: 'plugin' }); - assert.equal(typeof modelA.isStatic, 'boolean'); - assert.true(modelA.isStatic); + const modelA = store.createRecord('host-catalog', { compositeType: 'aws' }); + const modelB = store.createRecord('host-catalog', { + compositeType: 'foobar', + }); + const modelC = store.createRecord('host-catalog', { + compositeType: 'static', + }); + assert.false(modelA.isStatic); assert.false(modelB.isStatic); + assert.true(modelC.isStatic); }); - test('it has isPlugin function and returns the expected values', async function (assert) { - assert.expect(3); + test('it has isPlugin property and returns the expected values', async function (assert) { + assert.expect(2); const store = this.owner.lookup('service:store'); - const modelPlugin = store.createRecord('host-catalog', { type: 'plugin' }); - const modelStatic = store.createRecord('host-catalog', { type: 'static' }); - assert.equal(typeof modelPlugin.isPlugin, 'boolean'); + const modelPlugin = store.createRecord('host-catalog', { + compositeType: 'aws', + }); + const modelStatic = store.createRecord('host-catalog', { + compositeType: 'static', + }); assert.true(modelPlugin.isPlugin); assert.false(modelStatic.isPlugin); }); - test('it has isAWS function and returns the expected values', async function (assert) { + test('it has isUnknown property and returns the expected values', async function (assert) { assert.expect(3); const store = this.owner.lookup('service:store'); + const modelA = store.createRecord('host-catalog', { + compositeType: 'static', + }); + const modelB = store.createRecord('host-catalog', { compositeType: 'aws' }); + const modelC = store.createRecord('host-catalog', { + compositeType: 'no-such-type', + }); + assert.false(modelA.isUnknown); + assert.false(modelB.isUnknown); + assert.true(modelC.isUnknown); + }); + + test('it has isAWS property and returns the expected values', async function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); const modelAws = store.createRecord('host-catalog', { type: 'plugin', plugin: { name: 'aws' }, @@ -40,13 +63,12 @@ module('Unit | Model | host catalog', function (hooks) { const modelRandom = store.createRecord('host-catalog', { plugin: { name: 'random' }, }); - assert.equal(typeof modelAws.isAWS, 'boolean'); assert.true(modelAws.isAWS); assert.false(modelRandom.isAWS); }); - test('it has isAzure function and return the expected values', async function (assert) { - assert.expect(3); + test('it has isAzure property and return the expected values', async function (assert) { + assert.expect(2); const store = this.owner.lookup('service:store'); const modelAzure = store.createRecord('host-catalog', { type: 'plugin', @@ -55,7 +77,6 @@ module('Unit | Model | host catalog', function (hooks) { const modelRandom = store.createRecord('host-catalog', { plugin: { name: 'random' }, }); - assert.equal(typeof modelAzure.isAzure, 'boolean'); assert.true(modelAzure.isAzure); assert.false(modelRandom.isAzure); }); @@ -63,16 +84,20 @@ module('Unit | Model | host catalog', function (hooks) { test('get compositeType returns expected values', async function (assert) { assert.expect(3); const store = this.owner.lookup('service:store'); - const modelPlugin = store.createRecord('host-catalog', { - type: 'plugin', - plugin: { name: 'Test name' }, - }); - const modelStatic = store.createRecord('host-catalog', { + const modelA = store.createRecord('host-catalog', { type: 'static', }); - assert.equal(typeof modelPlugin.compositeType, 'string'); - assert.equal(modelPlugin.compositeType, 'Test name'); - assert.equal(modelStatic.compositeType, 'static'); + const modelB = store.createRecord('host-catalog', { + type: 'plugin', + plugin: { name: 'aws' }, + }); + const modelC = store.createRecord('host-catalog', { + type: 'plugin', + plugin: { name: 'no-such-type' }, + }); + assert.equal(modelA.compositeType, 'static'); + assert.equal(modelB.compositeType, 'aws'); + assert.equal(modelC.compositeType, 'unknown'); }); test('set compositeType sets expected values', async function (assert) { @@ -84,7 +109,6 @@ module('Unit | Model | host catalog', function (hooks) { const modelStatic = store.createRecord('host-catalog', { compositeType: 'static', }); - assert.equal(modelPlugin.type, 'plugin'); assert.equal(modelPlugin.plugin.name, 'aws'); assert.equal(modelStatic.type, 'static'); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index f787cf133..d1de853d6 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -85,6 +85,7 @@ host-catalog: delete: Delete Host Catalog types: static: Static + unknown: Unknown host-set: title: Host Set title_plural: Host Sets @@ -111,6 +112,7 @@ host-set: description: No hosts available for selection. types: static: Static + unknown: Unknown host: title: Host title_plural: Hosts @@ -130,6 +132,7 @@ host: delete: Delete Host types: static: Static + unknown: Unknown session: title: Session title_plural: Sessions diff --git a/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs b/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs index 7765915cd..b2280bc1a 100644 --- a/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs +++ b/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs @@ -59,7 +59,19 @@ {{#if hostCatalog.isStatic}} {{t - (concat 'resources.host-catalog.types.' hostCatalog.type) + (concat + 'resources.host-catalog.types.' + hostCatalog.compositeType + ) + }} + + {{else if hostCatalog.isUnknown}} + + {{t + (concat + 'resources.host-catalog.types.' + hostCatalog.compositeType + ) }} {{else}}