diff --git a/addons/api/addon/adapters/host-catalog.js b/addons/api/addon/adapters/host-catalog.js new file mode 100644 index 000000000..78c1d9a03 --- /dev/null +++ b/addons/api/addon/adapters/host-catalog.js @@ -0,0 +1,13 @@ +import ApplicationAdapter from './application'; + +export default class HostCatalogAdapter extends ApplicationAdapter { + + // =attributes + + /** + * Host catalogs use the new, unprefixed pathing style. + * @override + */ + hasScopePrefix = false; + +} diff --git a/addons/api/addon/adapters/host-set.js b/addons/api/addon/adapters/host-set.js index fbbe11495..d237c63d9 100644 --- a/addons/api/addon/adapters/host-set.js +++ b/addons/api/addon/adapters/host-set.js @@ -7,32 +7,12 @@ export default class HostSetAdapter extends ApplicationAdapter { @service store; - // =methods + // =attributes /** - * Append a host catalog URL ahead of the host sets path if `hostCatalogID` is - * passed via adapter options. Otherwise, generate the prefix as normal. - * - * TODO: generalize the interface to resource-prefixed URLs by accepting - * a modelName and an ID, rather than looking for a known key. - * + * Host sets use the new, unprefixed pathing style. * @override - * @param {string} path - * @param {string} parentURL - * @param {string} modelName - * @param {string} id - * @param {object} snapshot - * @return {string} urlPrefix */ - urlPrefix(path, parentURL, modelName, id, snapshot) { - const hostCatalogID = snapshot?.adapterOptions?.hostCatalogID; - if (hostCatalogID) { - const hostCatalogAdapter = this.store.adapterFor('host-catalog'); - return hostCatalogAdapter - ._buildPrefixedURL('host-catalog', hostCatalogID, snapshot); - } else { - return super.urlPrefix(...arguments); - } - } + hasScopePrefix = false; } diff --git a/addons/api/addon/adapters/host.js b/addons/api/addon/adapters/host.js index ae1747b06..d6b6ea5eb 100644 --- a/addons/api/addon/adapters/host.js +++ b/addons/api/addon/adapters/host.js @@ -7,32 +7,12 @@ export default class HostAdapter extends ApplicationAdapter { @service store; - // =methods + // =attributes /** - * Append a host catalog URL ahead of the host path if `hostCatalogID` is - * passed via adapter options. Otherwise, generate the prefix as normal. - * - * TODO: generalize the interface to resource-prefixed URLs by accepting - * a modelName and an ID, rather than looking for a known key. - * + * Hosts use the new, unprefixed pathing style. * @override - * @param {string} path - * @param {string} parentURL - * @param {string} modelName - * @param {string} id - * @param {object} snapshot - * @return {string} urlPrefix */ - urlPrefix(path, parentURL, modelName, id, snapshot) { - const hostCatalogID = snapshot?.adapterOptions?.hostCatalogID; - if (hostCatalogID) { - const hostCatalogAdapter = this.store.adapterFor('host-catalog'); - return hostCatalogAdapter - ._buildPrefixedURL('host-catalog', hostCatalogID, snapshot); - } else { - return super.urlPrefix(...arguments); - } - } + hasScopePrefix = false; } diff --git a/addons/api/addon/generated/models/host-set.js b/addons/api/addon/generated/models/host-set.js index d1af3fe32..309165055 100644 --- a/addons/api/addon/generated/models/host-set.js +++ b/addons/api/addon/generated/models/host-set.js @@ -15,7 +15,6 @@ export default class GeneratedHostSetModel extends BaseModel { @attr('string', { description: 'The owning host catalog ID.', - readOnly: true }) host_catalog_id; @attr('string', { diff --git a/addons/api/addon/generated/models/host.js b/addons/api/addon/generated/models/host.js index 0d9e0dd2d..50f1463e0 100644 --- a/addons/api/addon/generated/models/host.js +++ b/addons/api/addon/generated/models/host.js @@ -12,6 +12,10 @@ export default class GeneratedHostModel extends BaseModel { description: 'The type of the resource, to help differentiate schemas' }) type; + @attr('string', { + description: 'The owning host catalog ID.', + }) host_catalog_id; + @attr('string', { description: 'Optional name for identification purposes' }) name; @@ -35,8 +39,4 @@ export default class GeneratedHostModel extends BaseModel { }) version; - @attr('string', { - description: 'The address (DNS or IP name) used to reach the host' - }) address; - } diff --git a/addons/api/addon/models/fragment-host-attributes.js b/addons/api/addon/models/fragment-host-attributes.js new file mode 100644 index 000000000..114da4bca --- /dev/null +++ b/addons/api/addon/models/fragment-host-attributes.js @@ -0,0 +1,9 @@ +import Fragment from 'ember-data-model-fragments/fragment'; +import { attr } from '@ember-data/model'; + +export default class FragmentHostAttributesModel extends Fragment { + + @attr('string', { + description: 'The address (DNS or IP name) used to reach the host' + }) address; +} diff --git a/addons/api/addon/models/host-set.js b/addons/api/addon/models/host-set.js index c4b93e905..ffa0f7906 100644 --- a/addons/api/addon/models/host-set.js +++ b/addons/api/addon/models/host-set.js @@ -1,6 +1,5 @@ import GeneratedHostSetModel from '../generated/models/host-set'; import { fragmentArray } from 'ember-data-model-fragments/attributes'; -//import { computed } from '@ember/object'; export default class HostSetModel extends GeneratedHostSetModel { @@ -12,18 +11,6 @@ export default class HostSetModel extends GeneratedHostSetModel { */ @fragmentArray('fragment-string', {readOnly: true}) host_ids; - // TODO this is here in case we want it in the future, - // especially for the target / add host sets workflow - /** - * Returns the host catalog instance associated with this host set if - * it is already loaded into the store. - * @type {?HostCatalogModel} - */ - // @computed('host_catalog_id') - // get hostCatalog() { - // return this.store.peekRecord('host-catalog', this.host_catalog_id); - // } - // =methods /** diff --git a/addons/api/addon/models/host.js b/addons/api/addon/models/host.js index 451097080..a2e855084 100644 --- a/addons/api/addon/models/host.js +++ b/addons/api/addon/models/host.js @@ -1,3 +1,12 @@ import GeneratedHostModel from '../generated/models/host'; +import { fragment } from 'ember-data-model-fragments/attributes'; -export default class HostModel extends GeneratedHostModel {} +export default class HostModel extends GeneratedHostModel { + + /** + * Attributes of this resource, if any, represented as a JSON fragment. + * @type {FragmentHostAttributesModel} + */ + @fragment('fragment-host-attributes', { defaultValue: {} }) attributes; + +} diff --git a/addons/api/addon/serializers/host-catalog.js b/addons/api/addon/serializers/host-catalog.js new file mode 100644 index 000000000..766dff5d6 --- /dev/null +++ b/addons/api/addon/serializers/host-catalog.js @@ -0,0 +1,13 @@ +import ApplicationSerializer from './application'; + +export default class HostCatalogSerializer extends ApplicationSerializer { + + // =attributes + + /** + * Serialized the scope ID into the `scope_id` field. + * @type {boolean} + */ + serializeScopeID = true; + +} diff --git a/addons/api/addon/serializers/host-set.js b/addons/api/addon/serializers/host-set.js index 3ce7c7161..697e7748d 100644 --- a/addons/api/addon/serializers/host-set.js +++ b/addons/api/addon/serializers/host-set.js @@ -2,6 +2,14 @@ import ApplicationSerializer from './application'; export default class HostSetSerializer extends ApplicationSerializer { + // =attributes + + /** + * Serialized the scope ID into the `scope_id` field. + * @type {boolean} + */ + serializeScopeID = true; + // =methods /** diff --git a/addons/api/addon/serializers/host.js b/addons/api/addon/serializers/host.js new file mode 100644 index 000000000..06a7b91d3 --- /dev/null +++ b/addons/api/addon/serializers/host.js @@ -0,0 +1,13 @@ +import ApplicationSerializer from './application'; + +export default class HostSerializer extends ApplicationSerializer { + + // =attributes + + /** + * Serialized the scope ID into the `scope_id` field. + * @type {boolean} + */ + serializeScopeID = true; + +} diff --git a/addons/api/app/adapters/host-catalog.js b/addons/api/app/adapters/host-catalog.js new file mode 100644 index 000000000..00197a624 --- /dev/null +++ b/addons/api/app/adapters/host-catalog.js @@ -0,0 +1 @@ +export { default } from 'api/adapters/host-catalog'; diff --git a/addons/api/app/models/fragment-host-attributes.js b/addons/api/app/models/fragment-host-attributes.js new file mode 100644 index 000000000..201efcb7a --- /dev/null +++ b/addons/api/app/models/fragment-host-attributes.js @@ -0,0 +1 @@ +export { default } from 'api/models/fragment-host-attributes'; diff --git a/addons/api/app/serializers/host-catalog.js b/addons/api/app/serializers/host-catalog.js new file mode 100644 index 000000000..e2818e2c7 --- /dev/null +++ b/addons/api/app/serializers/host-catalog.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/host-catalog'; diff --git a/addons/api/app/serializers/host.js b/addons/api/app/serializers/host.js new file mode 100644 index 000000000..33844fbaf --- /dev/null +++ b/addons/api/app/serializers/host.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/host'; diff --git a/addons/api/tests/unit/adapters/host-catalog-test.js b/addons/api/tests/unit/adapters/host-catalog-test.js new file mode 100644 index 000000000..02fba945c --- /dev/null +++ b/addons/api/tests/unit/adapters/host-catalog-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Adapter | host catalog', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:host-catalog'); + assert.ok(adapter); + }); +}); diff --git a/addons/api/tests/unit/adapters/host-set-test.js b/addons/api/tests/unit/adapters/host-set-test.js index e47c7a7d6..1ab6f7a63 100644 --- a/addons/api/tests/unit/adapters/host-set-test.js +++ b/addons/api/tests/unit/adapters/host-set-test.js @@ -6,23 +6,17 @@ module('Unit | Adapter | host set', function(hooks) { test('it generates correct complete URLs', function (assert) { assert.expect(2); - const scopeID = 'o_1'; const hostCatalogID = 'hc_098'; const method = 'my-custom-method'; - const mockSnapshot = { - adapterOptions: { - scopeID, - method - } - }; + const mockSnapshot = { adapterOptions: { method } }; const adapter = this.owner.lookup('adapter:host-set'); // Without hostCatalogID... let url = adapter.buildURL('host-set', null, mockSnapshot, 'findAll'); - assert.equal(url, '/v1/scopes/o_1/host-sets:my-custom-method'); + assert.equal(url, '/v1/host-sets:my-custom-method'); // With hostCatalogID... mockSnapshot.adapterOptions.hostCatalogID = hostCatalogID; url = adapter.buildURL('host-set', null, mockSnapshot, 'findAll'); - assert.equal(url, '/v1/scopes/o_1/host-catalogs/hc_098/host-sets:my-custom-method'); + assert.equal(url, '/v1/host-sets:my-custom-method'); }); }); diff --git a/addons/api/tests/unit/adapters/host-test.js b/addons/api/tests/unit/adapters/host-test.js index 9e019284e..1e45bbee7 100644 --- a/addons/api/tests/unit/adapters/host-test.js +++ b/addons/api/tests/unit/adapters/host-test.js @@ -4,25 +4,9 @@ import { setupTest } from 'ember-qunit'; module('Unit | Adapter | host', function(hooks) { setupTest(hooks); - test('it generates correct complete URLs', function (assert) { - assert.expect(2); - const scopeID = 'o_1'; - const hostCatalogID = 'hc_098'; - const method = 'my-custom-method'; - const mockSnapshot = { - adapterOptions: { - scopeID, - method - } - }; - const adapter = this.owner.lookup('adapter:host'); - // Without hostCatalogID... - let url = adapter.buildURL('host', null, mockSnapshot, 'findAll'); - assert.equal(url, '/v1/scopes/o_1/hosts:my-custom-method'); - // With hostCatalogID... - mockSnapshot.adapterOptions.hostCatalogID = hostCatalogID; - url = adapter.buildURL('host', null, mockSnapshot, 'findAll'); - assert.equal(url, '/v1/scopes/o_1/host-catalogs/hc_098/hosts:my-custom-method'); + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:host'); + assert.ok(adapter); }); }); diff --git a/addons/api/tests/unit/models/host-test.js b/addons/api/tests/unit/models/host-test.js index d19d98fc3..3cc0a3ad9 100644 --- a/addons/api/tests/unit/models/host-test.js +++ b/addons/api/tests/unit/models/host-test.js @@ -10,4 +10,15 @@ module('Unit | Model | host', function(hooks) { let model = store.createRecord('host', {}); assert.ok(model); }); + + test('it contains attributes', function(assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('host', { + type: 'static', + attributes: { + address: '127.0.0.1' + } + }); + assert.equal(model.attributes.address, '127.0.0.1'); + }); }); diff --git a/addons/api/tests/unit/serializers/host-catalog-test.js b/addons/api/tests/unit/serializers/host-catalog-test.js new file mode 100644 index 000000000..64a20b044 --- /dev/null +++ b/addons/api/tests/unit/serializers/host-catalog-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | host catalog', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('host-catalog'); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('host-catalog', {}); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); diff --git a/addons/api/tests/unit/serializers/host-set-test.js b/addons/api/tests/unit/serializers/host-set-test.js index 595c6f771..c10cbe915 100644 --- a/addons/api/tests/unit/serializers/host-set-test.js +++ b/addons/api/tests/unit/serializers/host-set-test.js @@ -11,6 +11,7 @@ module('Unit | Serializer | host set', function(hooks) { const record = store.createRecord('host-set', { name: 'Host Set 1', description: 'Description', + host_catalog_id: '123', version: 1 }); const snapshot = record._createSnapshot(); @@ -19,6 +20,7 @@ module('Unit | Serializer | host set', function(hooks) { assert.deepEqual(serializedRecord, { name: 'Host Set 1', description: 'Description', + host_catalog_id: '123', version: 1 }); }); diff --git a/addons/api/tests/unit/serializers/host-test.js b/addons/api/tests/unit/serializers/host-test.js new file mode 100644 index 000000000..c31a5ce4e --- /dev/null +++ b/addons/api/tests/unit/serializers/host-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | host', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('host'); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('host', {}); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); diff --git a/ui/core/app/components/form/host-set/hosts/index.hbs b/ui/core/app/components/form/host-set/hosts/index.hbs index 1943e26aa..088270a0b 100644 --- a/ui/core/app/components/form/host-set/hosts/index.hbs +++ b/ui/core/app/components/form/host-set/hosts/index.hbs @@ -41,7 +41,7 @@ onChange={{fn @toggleHost option.host}} /> {{option.host.name}} - {{option.host.address}} + {{option.host.attributes.address}} {{/each}} diff --git a/ui/core/app/components/form/host/index.hbs b/ui/core/app/components/form/host/index.hbs index 9152b0ba0..2168b7285 100644 --- a/ui/core/app/components/form/host/index.hbs +++ b/ui/core/app/components/form/host/index.hbs @@ -47,6 +47,24 @@ {{/if}} + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + - this.store.findRecord('host', host.value, { adapterOptions: { scopeID, hostCatalogID } }) + this.store.findRecord('host', host.value, { reload: true }) )) }); } diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/new.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/new.js index f0dbcc3bd..378b78c7a 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/new.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/new.js @@ -9,10 +9,11 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsNe * @return {HostSetModel} */ model() { - const scopeModel = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); + const { id: host_catalog_id } = + this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); return this.store.createRecord('host-set', { type: 'static', - scopeModel + host_catalog_id }); } diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js index 805112d67..d8bfcfddc 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js @@ -14,8 +14,10 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsRoute * Loads all hosts under the current host catalog and it's parent project scope. * @return {Promise{[HostModel]}} */ - async model() { - return this.store.findAll('host', this.adapterOptions()); + model() { + const { id: host_catalog_id } = + this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); + return this.store.query('host', { host_catalog_id }); } // =actions @@ -40,12 +42,12 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsRoute async save(host) { try { const { isNew } = host; - await host.save(this.adapterOptions()); - this.refresh(); + await host.save(); + await this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.hosts.host', host); + await this.refresh(); this.notify.success( this.intl.t(isNew ? 'notify.create-success' : 'notify.save-success') ); - this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.hosts.host', host); } catch (error) { // TODO: replace with translated strings this.notify.error(error.message, { closeAfter: null }); @@ -59,7 +61,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsRoute @action async delete(host) { try { - await host.destroyRecord(this.adapterOptions()); + await host.destroyRecord(); this.refresh(); this.notify.success(this.intl.t('notify.delete-success')); this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.hosts'); @@ -68,14 +70,4 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsRoute this.notify.error(error.message, { closeAfter: null }); } } - - /** - * Configure adapter options using current host catalog scope and it's parent project scope. - * @return {object} - */ - adapterOptions() { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; - return { adapterOptions : { scopeID, hostCatalogID } }; - } } diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js index 907454d36..2561da8d6 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js @@ -10,11 +10,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsHostR * @return {HostModel} */ async model({ host_id }) { - const { id: scopeID } = this.modelFor('scopes.scope.projects.project'); - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; - return this.store.findRecord('host', host_id, { - adapterOptions: { scopeID, hostCatalogID } - }); + return this.store.findRecord('host', host_id, { reload: true }); } /** diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js index 39f90d1bb..d8234bc47 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js @@ -9,10 +9,11 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsNewRo * @return {HostModel} */ model() { - const scopeModel = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); + const { id: host_catalog_id } = + this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); return this.store.createRecord('host', { type: 'static', - scopeModel + host_catalog_id }); } diff --git a/ui/core/app/routes/scopes/scope/projects/project/targets/target/add-host-sets.js b/ui/core/app/routes/scopes/scope/projects/project/targets/target/add-host-sets.js index f1fdc55ec..96e1cd71a 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/targets/target/add-host-sets.js +++ b/ui/core/app/routes/scopes/scope/projects/project/targets/target/add-host-sets.js @@ -13,10 +13,9 @@ export default class ScopesScopeProjectsProjectTargetsTargetAddHostSetsRoute ext // =methods /** - * Empty out any previously loaded host catalogs and host sets. + * Empty out any previously loaded host sets. */ beforeModel() { - this.store.unloadAll('host-catalog'); this.store.unloadAll('host-set'); } @@ -27,12 +26,10 @@ export default class ScopesScopeProjectsProjectTargetsTargetAddHostSetsRoute ext async model() { const target = this.modelFor('scopes.scope.projects.project.targets.target'); - const { scopeID } = target; - const hostCatalogs = - await this.store.findAll('host-catalog', { adapterOptions: { scopeID } }); - await all(hostCatalogs.map(({ id: hostCatalogID }) => - this.store - .findAll('host-set', { adapterOptions: { scopeID, hostCatalogID } }) + const { id: scope_id } = this.modelFor('scopes.scope.projects.project'); + const hostCatalogs = await this.store.query('host-catalog', { scope_id }); + await all(hostCatalogs.map(({ id: host_catalog_id }) => + this.store.query('host-set', { host_catalog_id }) )); const hostSets = this.store.peekAll('host-set'); return { diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs index 034f2b9a1..2cac93ee4 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs @@ -6,6 +6,7 @@ {{t "form.label.name"}} {{t "form.label.type"}} {{t "form.label.id"}} + {{t "form.label.address"}} @@ -26,6 +27,9 @@ {{host.id}} + + {{host.attributes.address}} + {{/each}} diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index a95797a20..754e5a880 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -147,40 +147,44 @@ export default function() { // Other resources // host-catalog - this.get('/scopes/:scope_id/host-catalogs'); - this.post('/scopes/:scope_id/host-catalogs'); - this.get('/scopes/:scope_id/host-catalogs/:id'); - this.patch('/scopes/:scope_id/host-catalogs/:id'); - this.del('/scopes/:scope_id/host-catalogs/:id'); + this.get('/host-catalogs', ({ hostCatalogs }, { queryParams: { scope_id: scopeId } }) => { + return hostCatalogs.where({ scopeId }); + }); + this.post('/host-catalogs'); + this.get('/host-catalogs/:id'); + this.patch('/host-catalogs/:id'); + this.del('/host-catalogs/:id'); // host - this.get('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { + this.get('/hosts', function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) { return hosts.where({ hostCatalogId }); }); - this.post('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { + this.post('/hosts', function ({ hostCatalogs, hosts }) { const attrs = this.normalizedRequestAttrs(); - attrs.hostCatalogId = hostCatalogId; + const hostCatalog = hostCatalogs.find(attrs.hostCatalogId); + attrs.scopeId = hostCatalog.scope.id; return hosts.create(attrs); }); - this.get('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts/:id'); - this.patch('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts/:id'); - this.del('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts/:id'); + this.get('/hosts/:id'); + this.patch('/hosts/:id'); + this.del('/hosts/:id'); // host-set - this.get('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { + this.get('/host-sets', function ({ hostSets }, { queryParams: { host_catalog_id: hostCatalogId } }) { return hostSets.where({ hostCatalogId }); }); - this.post('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { + this.post('/host-sets', function ({ hostCatalogs, hostSets }) { const attrs = this.normalizedRequestAttrs(); - attrs.hostCatalogId = hostCatalogId; + const hostCatalog = hostCatalogs.find(attrs.hostCatalogId); + attrs.scopeId = hostCatalog.scope.id; return hostSets.create(attrs); }); - this.get('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets/:id'); - this.patch('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets/:id'); - this.del('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets/:id'); - this.post('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets/:idMethod', function ({ hostSets }, { params: { idMethod } }) { + this.get('/host-sets/:id'); + this.patch('/host-sets/:id'); + this.del('/host-sets/:id'); + this.post('/host-sets/:idMethod', function ({ hostSets }, { params: { idMethod } }) { const attrs = this.normalizedRequestAttrs(); const id = idMethod.split(':')[0]; const method = idMethod.split(':')[1]; diff --git a/ui/core/mirage/factories/host-catalog.js b/ui/core/mirage/factories/host-catalog.js index b6ce98947..1eaed0433 100644 --- a/ui/core/mirage/factories/host-catalog.js +++ b/ui/core/mirage/factories/host-catalog.js @@ -5,7 +5,7 @@ export default factory.extend({ withChildren: trait({ afterCreate(hostCatalog, server) { - const scope = hostCatalog.scope; + const { scope } = hostCatalog; const hosts = server.createList('host', 10, { scope, hostCatalog }); server.createList('host-set', 3, { scope, hostCatalog, hosts }); } diff --git a/ui/core/mirage/factories/target.js b/ui/core/mirage/factories/target.js index 7c74806a6..a96e15556 100644 --- a/ui/core/mirage/factories/target.js +++ b/ui/core/mirage/factories/target.js @@ -13,7 +13,12 @@ export default factory.extend({ afterCreate(target, server) { let randomlySelectedHostSets; randomlySelectedHostSets = server.schema.hostSets - .where(item => item.scope.id === target.scope.id).models + // BLERG: fun fact, for no reason at all, the element passed + // into a where function is not a full model instance, as you might + // expect at this level of abstraction, but appears to be a serialized + // representation of the model instance. It's very confusing since + // the result set of `where` _is a collection of model instances_. + .where(hostSet => hostSet.scopeId === target.scope.id).models .filter(() => randomBoolean(hostSetChance)); target.update({hostSets: randomlySelectedHostSets}); } diff --git a/ui/core/mirage/generated/factories/host.js b/ui/core/mirage/generated/factories/host.js index 2d6925e82..e6fccf602 100644 --- a/ui/core/mirage/generated/factories/host.js +++ b/ui/core/mirage/generated/factories/host.js @@ -12,6 +12,6 @@ export default Factory.extend({ created_time: () => date.recent(), updated_time: () => date.recent(), version: () => random.number(), - address: () => internet.ipv6(), + attributes: () => { return { address: internet.ipv6() } }, }); diff --git a/ui/core/mirage/models/host-catalog.js b/ui/core/mirage/models/host-catalog.js new file mode 100644 index 000000000..08b1f5ad3 --- /dev/null +++ b/ui/core/mirage/models/host-catalog.js @@ -0,0 +1,7 @@ +import { Model, belongsTo } from 'ember-cli-mirage'; + +export default Model.extend({ + + scope: belongsTo() + +}); diff --git a/ui/core/mirage/models/host-set.js b/ui/core/mirage/models/host-set.js index 3aa8fbf7e..5a579e119 100644 --- a/ui/core/mirage/models/host-set.js +++ b/ui/core/mirage/models/host-set.js @@ -2,6 +2,7 @@ import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; export default Model.extend({ + scope: belongsTo(), target: belongsTo(), hostCatalog: belongsTo(), hosts: hasMany() diff --git a/ui/core/mirage/models/host.js b/ui/core/mirage/models/host.js index 89aba81e6..b9a941a4f 100644 --- a/ui/core/mirage/models/host.js +++ b/ui/core/mirage/models/host.js @@ -2,6 +2,7 @@ import { Model, belongsTo } from 'ember-cli-mirage'; export default Model.extend({ + scope: belongsTo(), hostCatalog: belongsTo() }); diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js index c878699ef..1524a7647 100644 --- a/ui/core/mirage/scenarios/default.js +++ b/ui/core/mirage/scenarios/default.js @@ -24,8 +24,7 @@ export default function(server) { // Other resources server.schema.scopes.where({type: 'project'}).models.forEach(scope => { - const scopePojo = { id: scope.id, type: scope.type }; - server.createList('host-catalog', 2, { scope: scopePojo }, 'withChildren'); + server.createList('host-catalog', 2, { scope }, 'withChildren'); server.createList('target', 2, { scope }, 'withRandomHostSets'); }); diff --git a/ui/core/mirage/serializers/host-catalog.js b/ui/core/mirage/serializers/host-catalog.js index e7b237047..34277f96e 100644 --- a/ui/core/mirage/serializers/host-catalog.js +++ b/ui/core/mirage/serializers/host-catalog.js @@ -1,5 +1,22 @@ import ApplicationSerializer from './application'; +import { underscore } from '@ember/string'; export default ApplicationSerializer.extend({ - modelName: 'host-catalog' + modelName: 'host-catalog', + + keyForRelationshipId(relationshipName) { + return `${this._container.inflector.singularize( + underscore(relationshipName) + )}_id`; + }, + + _hashForModel(model) { + const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments); + json.scope = { + id: model.scope.id, + type: model.scope.type + }; + return json; + } + }); diff --git a/ui/core/mirage/serializers/host-set.js b/ui/core/mirage/serializers/host-set.js index bd680326e..16d665375 100644 --- a/ui/core/mirage/serializers/host-set.js +++ b/ui/core/mirage/serializers/host-set.js @@ -10,10 +10,20 @@ export default ApplicationSerializer.extend({ )}_ids`; }, + keyForRelationshipId(relationshipName) { + return `${this._container.inflector.singularize( + underscore(relationshipName) + )}_id`; + }, + _hashForModel(model) { const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments); json.host_ids = model.hostIds; json.host_catalog_id = model.hostCatalogId; + json.scope = { + id: model.scope.id, + type: model.scope.type + }; return json; } diff --git a/ui/core/mirage/serializers/host.js b/ui/core/mirage/serializers/host.js index ccd3994ca..4fb0353b4 100644 --- a/ui/core/mirage/serializers/host.js +++ b/ui/core/mirage/serializers/host.js @@ -1,5 +1,22 @@ import ApplicationSerializer from './application'; +import { underscore } from '@ember/string'; export default ApplicationSerializer.extend({ - modelName: 'host' + modelName: 'host', + + keyForRelationshipId(relationshipName) { + return `${this._container.inflector.singularize( + underscore(relationshipName) + )}_id`; + }, + + _hashForModel(model) { + const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments); + json.scope = { + id: model.scope.id, + type: model.scope.type + }; + return json; + } + }); diff --git a/ui/core/tests/acceptance/bread-crumbs-test.js b/ui/core/tests/acceptance/bread-crumbs-test.js index 9400e9dbe..4dc48c832 100644 --- a/ui/core/tests/acceptance/bread-crumbs-test.js +++ b/ui/core/tests/acceptance/bread-crumbs-test.js @@ -45,12 +45,7 @@ module('Acceptance | breadcrumbs', function (hooks) { user = this.server.create('user', { scope: orgScope }); role = this.server.create('role', { scope: orgScope }); group = this.server.create('group', { scope: orgScope }); - hostCatalog = this.server.create('host-catalog', { - scope: { - id: project.id, - type: project.type - } - }); + hostCatalog = this.server.create('host-catalog', { scope: getProjectScope() }); projectsURL = `/scopes/${orgScope.id}/projects`; newProjectURL = `${projectsURL}/new`; diff --git a/ui/core/tests/acceptance/host-catalogs-test.js b/ui/core/tests/acceptance/host-catalogs-test.js index 3b79331c9..f88332113 100644 --- a/ui/core/tests/acceptance/host-catalogs-test.js +++ b/ui/core/tests/acceptance/host-catalogs-test.js @@ -36,16 +36,13 @@ module('Acceptance | host catalogs', function (hooks) { // Setup Mirage mock resources for this test instances.scopes.global = this.server.create('scope', { id: 'global' }); instances.scopes.org = this.server.create('scope', { type: 'org', - scope: { id: instances.scopes.global.id, type: instances.scopes.global.type } + scope: { id: 'global', type: 'global' } }); instances.scopes.project = this.server.create('scope', { type: 'project', - scope: { id: instances.scopes.org.id, type: instances.scopes.org.type } + scope: { id: instances.scopes.org.id, type: 'org' } }); instances.hostCatalog = this.server.create('host-catalog', { - scope: { - id: instances.scopes.project.id, - type: instances.scopes.project.type - } + scope: instances.scopes.project }); // Generate route URLs for resources @@ -124,7 +121,7 @@ module('Acceptance | host catalogs', function (hooks) { test('errors are displayed when save host catalog fails', async function (assert) { assert.expect(1); - this.server.patch('/scopes/:scope_id/host-catalogs/:id', () => { + this.server.patch('/host-catalogs/:id', () => { return new Response( 490, {}, @@ -149,7 +146,7 @@ module('Acceptance | host catalogs', function (hooks) { test('errors are displayed when delete host catalog fails', async function (assert) { assert.expect(1); - this.server.del('/scopes/:scope_id/host-catalogs/:id', () => { + this.server.del('/host-catalogs/:id', () => { return new Response( 490, {}, @@ -173,7 +170,7 @@ module('Acceptance | host catalogs', function (hooks) { test('saving a new host catalog with invalid fields displays error messages', async function (assert) { assert.expect(2); - this.server.post('/scopes/:scope_id/host-catalogs', () => { + this.server.post('/host-catalogs', () => { return new Response( 400, {}, @@ -211,7 +208,7 @@ module('Acceptance | host catalogs', function (hooks) { test('saving an existing host catalog with invalid fields displays error messages', async function (assert) { assert.expect(2); - this.server.patch('/scopes/:scope_id/host-catalogs/:id', () => { + this.server.patch('/host-catalogs/:id', () => { return new Response( 400, {},