From cb762131e82ae9ab258acb66cc01456561cea6e2 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 9 Sep 2020 13:04:17 -0400 Subject: [PATCH 1/5] feat: Add attributes fragment to a host --- addons/api/addon/generated/models/host.js | 4 ---- addons/api/addon/models/fragment-host-attributes.js | 9 +++++++++ addons/api/addon/models/host.js | 11 ++++++++++- addons/api/app/models/fragment-host-attributes.js | 1 + addons/api/tests/unit/models/host-test.js | 11 +++++++++++ 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 addons/api/addon/models/fragment-host-attributes.js create mode 100644 addons/api/app/models/fragment-host-attributes.js diff --git a/addons/api/addon/generated/models/host.js b/addons/api/addon/generated/models/host.js index 0d9e0dd2d..8713b9b89 100644 --- a/addons/api/addon/generated/models/host.js +++ b/addons/api/addon/generated/models/host.js @@ -35,8 +35,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.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/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/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'); + }); }); From 2217a601dd19899b9a5c922754b841d256afd2ba Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Wed, 9 Sep 2020 13:05:02 -0400 Subject: [PATCH 2/5] feat: Add host address --- .../components/form/host-set/hosts/index.hbs | 2 +- ui/core/app/components/form/host/index.hbs | 18 ++++++++++++++++++ .../host-catalogs/host-catalog/hosts/host.js | 1 + .../host-catalogs/host-catalog/hosts/index.hbs | 4 ++++ ui/core/mirage/generated/factories/host.js | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-) 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}} + + + {{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/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() } }, }); From e3594738115dbec37439f2b62e80e2f503e47f99 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 10 Sep 2020 16:19:27 -0400 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20implement=20new?= =?UTF-8?q?=20pathing=20for=20host=20catalogs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/adapters/host-catalog.js | 13 +++++++ addons/api/addon/serializers/host-catalog.js | 13 +++++++ addons/api/app/adapters/host-catalog.js | 1 + addons/api/app/serializers/host-catalog.js | 1 + .../tests/unit/adapters/host-catalog-test.js | 12 +++++++ .../api/tests/unit/adapters/host-set-test.js | 2 +- addons/api/tests/unit/adapters/host-test.js | 2 +- .../unit/serializers/host-catalog-test.js | 23 +++++++++++++ .../scope/projects/project/host-catalogs.js | 6 ++-- .../project/host-catalogs/host-catalog.js | 5 +-- .../project/targets/target/add-host-sets.js | 7 ++-- ui/core/mirage/config.js | 34 ++++++++++--------- ui/core/mirage/factories/host-catalog.js | 5 +-- ui/core/mirage/models/host-catalog.js | 7 ++++ ui/core/mirage/scenarios/default.js | 3 +- ui/core/mirage/serializers/host-catalog.js | 19 ++++++++++- ui/core/tests/acceptance/bread-crumbs-test.js | 7 +--- .../tests/acceptance/host-catalogs-test.js | 17 ++++------ 18 files changed, 127 insertions(+), 50 deletions(-) create mode 100644 addons/api/addon/adapters/host-catalog.js create mode 100644 addons/api/addon/serializers/host-catalog.js create mode 100644 addons/api/app/adapters/host-catalog.js create mode 100644 addons/api/app/serializers/host-catalog.js create mode 100644 addons/api/tests/unit/adapters/host-catalog-test.js create mode 100644 addons/api/tests/unit/serializers/host-catalog-test.js create mode 100644 ui/core/mirage/models/host-catalog.js 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/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/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/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/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..9071a703a 100644 --- a/addons/api/tests/unit/adapters/host-set-test.js +++ b/addons/api/tests/unit/adapters/host-set-test.js @@ -22,7 +22,7 @@ module('Unit | Adapter | host set', function(hooks) { // 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-catalogs/hc_098/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..1e557ad26 100644 --- a/addons/api/tests/unit/adapters/host-test.js +++ b/addons/api/tests/unit/adapters/host-test.js @@ -22,7 +22,7 @@ module('Unit | Adapter | host', function(hooks) { // 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'); + assert.equal(url, '/v1/host-catalogs/hc_098/hosts:my-custom-method'); }); }); 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/ui/core/app/routes/scopes/scope/projects/project/host-catalogs.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs.js index 8ef0f103d..feebc44d2 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs.js @@ -13,12 +13,12 @@ export default class ScopesScopeProjectsProjectHostCatalogsRoute extends Route { /** - * Loads all scopes under the current scope. + * Loads all host catalogs under the current scope. * @return {Promise{[HostCatalogModel]}} */ async model() { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - return this.store.findAll('host-catalog', { adapterOptions: { scopeID } }); + const { id: scope_id } = this.modelFor('scopes.scope.projects.project'); + return this.store.query('host-catalog', { scope_id }); } // =actions diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog.js index b9afbdf98..ef495cef4 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog.js @@ -11,10 +11,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogRoute exte * @return {HostCatalogModel} */ async model({ host_catalog_id }) { - const { id: scopeID } = this.modelFor('scopes.scope'); - return this.store.findRecord('host-catalog', host_catalog_id, { - adapterOptions: { scopeID }, - }); + return this.store.findRecord('host-catalog', 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..d7723d4f0 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'); } @@ -28,8 +27,8 @@ export default class ScopesScopeProjectsProjectTargetsTargetAddHostSetsRoute ext const target = this.modelFor('scopes.scope.projects.project.targets.target'); const { scopeID } = target; - const hostCatalogs = - await this.store.findAll('host-catalog', { adapterOptions: { scopeID } }); + 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: hostCatalogID }) => this.store .findAll('host-set', { adapterOptions: { scopeID, hostCatalogID } }) diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index a95797a20..828c3f971 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -147,40 +147,42 @@ 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('/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { return hosts.where({ hostCatalogId }); }); - this.post('/scopes/:scope_id/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { + this.post('/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { const attrs = this.normalizedRequestAttrs(); attrs.hostCatalogId = hostCatalogId; 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('/host-catalogs/:hostCatalogId/hosts/:id'); + this.patch('/host-catalogs/:hostCatalogId/hosts/:id'); + this.del('/host-catalogs/:hostCatalogId/hosts/:id'); // host-set - this.get('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { + this.get('/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { return hostSets.where({ hostCatalogId }); }); - this.post('/scopes/:scope_id/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { + this.post('/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { const attrs = this.normalizedRequestAttrs(); attrs.hostCatalogId = hostCatalogId; 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-catalogs/:hostCatalogId/host-sets/:id'); + this.patch('/host-catalogs/:hostCatalogId/host-sets/:id'); + this.del('/host-catalogs/:hostCatalogId/host-sets/:id'); + this.post('/host-catalogs/:hostCatalogId/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..15ae0bb26 100644 --- a/ui/core/mirage/factories/host-catalog.js +++ b/ui/core/mirage/factories/host-catalog.js @@ -6,8 +6,9 @@ export default factory.extend({ withChildren: trait({ afterCreate(hostCatalog, server) { const scope = hostCatalog.scope; - const hosts = server.createList('host', 10, { scope, hostCatalog }); - server.createList('host-set', 3, { scope, hostCatalog, hosts }); + const scopePojo = { id: scope.id, type: scope.type }; + const hosts = server.createList('host', 10, { scope: scopePojo, hostCatalog }); + server.createList('host-set', 3, { scope: scopePojo, hostCatalog, hosts }); } }) 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/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/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, {}, From 2d29d2216ff6dce860beacc86739beb8995ca53f Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 10 Sep 2020 16:57:11 -0400 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20implement=20new?= =?UTF-8?q?=20pathing=20for=20host=20sets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/adapters/host-set.js | 26 +++---------------- addons/api/addon/serializers/host-set.js | 8 ++++++ .../api/tests/unit/adapters/host-set-test.js | 12 +++------ .../host-catalogs/host-catalog/host-sets.js | 21 ++++----------- .../host-catalog/host-sets/host-set.js | 7 +---- .../project/targets/target/add-host-sets.js | 6 ++--- ui/core/mirage/config.js | 16 +++++------- ui/core/mirage/factories/host-catalog.js | 4 +-- ui/core/mirage/factories/target.js | 7 ++++- ui/core/mirage/models/host-set.js | 1 + ui/core/mirage/serializers/host-set.js | 10 +++++++ 11 files changed, 47 insertions(+), 71 deletions(-) diff --git a/addons/api/addon/adapters/host-set.js b/addons/api/addon/adapters/host-set.js index fbbe11495..fe35a1935 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 catalogs 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/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/tests/unit/adapters/host-set-test.js b/addons/api/tests/unit/adapters/host-set-test.js index 9071a703a..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/host-catalogs/hc_098/host-sets:my-custom-method'); + assert.equal(url, '/v1/host-sets:my-custom-method'); }); }); diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js index 4fbec613f..045a0f632 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js @@ -8,19 +8,6 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo @service intl; @service notify; - // =attributes - - /** - * Configure adapter options using current host catalog and - * the current project scope. - * @return {object} - */ - get 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 } }; - } - // =methods /** @@ -29,7 +16,9 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo */ async model() { this.store.unloadAll('host-set'); - return this.store.findAll('host-set', this.adapterOptions); + const { id: host_catalog_id } = + this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); + return this.store.query('host-set', { host_catalog_id }); } // =actions @@ -54,7 +43,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo async save(hostSet) { try { const { isNew } = hostSet; - await hostSet.save(this.adapterOptions); + await hostSet.save(); this.notify.success( this.intl.t(isNew ? 'notify.create-success' : 'notify.save-success') ); @@ -72,7 +61,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo @action async delete(hostSet) { try { - await hostSet.destroyRecord(this.adapterOptions); + await hostSet.destroyRecord(); this.notify.success(this.intl.t('notify.delete-success')); this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets'); } catch (error) { diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set.js index 4c98b45f2..7b422c1ac 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set.js @@ -10,12 +10,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsHo * @return {HostSetModel} */ async model({ host_set_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-set', host_set_id, { - reload: true, - adapterOptions: { scopeID, hostCatalogID } - }); + return this.store.findRecord('host-set', host_set_id, { reload: true }); } /** 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 d7723d4f0..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 @@ -26,12 +26,10 @@ export default class ScopesScopeProjectsProjectTargetsTargetAddHostSetsRoute ext async model() { const target = this.modelFor('scopes.scope.projects.project.targets.target'); - const { scopeID } = target; 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: hostCatalogID }) => - this.store - .findAll('host-set', { adapterOptions: { scopeID, hostCatalogID } }) + 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/mirage/config.js b/ui/core/mirage/config.js index 828c3f971..7c7a1fdf8 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -171,18 +171,14 @@ export default function() { // host-set - this.get('/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('/host-catalogs/:hostCatalogId/host-sets', function ({ hostSets }, { params: { hostCatalogId } }) { - const attrs = this.normalizedRequestAttrs(); - attrs.hostCatalogId = hostCatalogId; - return hostSets.create(attrs); - }); - this.get('/host-catalogs/:hostCatalogId/host-sets/:id'); - this.patch('/host-catalogs/:hostCatalogId/host-sets/:id'); - this.del('/host-catalogs/:hostCatalogId/host-sets/:id'); - this.post('/host-catalogs/:hostCatalogId/host-sets/:idMethod', function ({ hostSets }, { params: { idMethod } }) { + this.post('/host-sets'); + 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 15ae0bb26..f2541fcb7 100644 --- a/ui/core/mirage/factories/host-catalog.js +++ b/ui/core/mirage/factories/host-catalog.js @@ -5,10 +5,10 @@ export default factory.extend({ withChildren: trait({ afterCreate(hostCatalog, server) { - const scope = hostCatalog.scope; + const { scope } = hostCatalog; const scopePojo = { id: scope.id, type: scope.type }; const hosts = server.createList('host', 10, { scope: scopePojo, hostCatalog }); - server.createList('host-set', 3, { scope: scopePojo, hostCatalog, hosts }); + 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/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/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; } From ebf129d35b40d55f7780764a3b08585b9f50dd36 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 10 Sep 2020 17:59:31 -0400 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20implement=20new?= =?UTF-8?q?=20pathing=20for=20hosts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/adapters/host-set.js | 2 +- addons/api/addon/adapters/host.js | 26 +++---------------- addons/api/addon/generated/models/host-set.js | 1 - addons/api/addon/generated/models/host.js | 4 +++ addons/api/addon/models/host-set.js | 13 ---------- addons/api/addon/serializers/host.js | 13 ++++++++++ addons/api/app/serializers/host.js | 1 + addons/api/tests/unit/adapters/host-test.js | 22 +++------------- .../tests/unit/serializers/host-set-test.js | 2 ++ .../api/tests/unit/serializers/host-test.js | 23 ++++++++++++++++ .../host-catalogs/host-catalog/host-sets.js | 6 ++--- .../host-sets/host-set/add-hosts.js | 11 +++----- .../host-catalog/host-sets/host-set/hosts.js | 11 +------- .../host-catalog/host-sets/new.js | 5 ++-- .../host-catalogs/host-catalog/hosts.js | 24 ++++++----------- .../host-catalogs/host-catalog/hosts/host.js | 7 +---- .../host-catalogs/host-catalog/hosts/new.js | 5 ++-- ui/core/mirage/config.js | 20 +++++++++----- ui/core/mirage/factories/host-catalog.js | 3 +-- ui/core/mirage/models/host.js | 1 + ui/core/mirage/serializers/host.js | 19 +++++++++++++- 21 files changed, 106 insertions(+), 113 deletions(-) create mode 100644 addons/api/addon/serializers/host.js create mode 100644 addons/api/app/serializers/host.js create mode 100644 addons/api/tests/unit/serializers/host-test.js diff --git a/addons/api/addon/adapters/host-set.js b/addons/api/addon/adapters/host-set.js index fe35a1935..d237c63d9 100644 --- a/addons/api/addon/adapters/host-set.js +++ b/addons/api/addon/adapters/host-set.js @@ -10,7 +10,7 @@ export default class HostSetAdapter extends ApplicationAdapter { // =attributes /** - * Host catalogs use the new, unprefixed pathing style. + * Host sets use the new, unprefixed pathing style. * @override */ 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 8713b9b89..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; 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/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/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-test.js b/addons/api/tests/unit/adapters/host-test.js index 1e557ad26..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/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/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/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js index 045a0f632..3d2ec03bc 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets.js @@ -14,8 +14,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo * Loads all host-sets under the current host catalog and it's parent scope. * @return {Promise{[HostSetModel]}} */ - async model() { - this.store.unloadAll('host-set'); + model() { const { id: host_catalog_id } = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); return this.store.query('host-set', { host_catalog_id }); @@ -44,10 +43,11 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo try { const { isNew } = hostSet; await hostSet.save(); + await this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets.host-set', hostSet); + 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.host-sets.host-set', hostSet); } catch (error) { // TODO: replace with translated strings this.notify.error(error.message, { closeAfter: null }); diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/add-hosts.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/add-hosts.js index b7ef1afd2..d4a301f93 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/add-hosts.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/add-hosts.js @@ -24,11 +24,10 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsHo * @return {Promise{HostSetModel,[HostModel]}} */ async model() { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; + const { id: host_catalog_id } = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); return hash({ hostSet: this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets.host-set'), - hosts: this.store.findAll('host', { adapterOptions: { scopeID, hostCatalogID } }) + hosts: this.store.query('host', { host_catalog_id }) }); } @@ -84,13 +83,11 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsHo @action async addHosts(hostSet, hostIDs) { try { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; - await hostSet.addHosts(hostIDs, { adapterOptions : { scopeID, hostCatalogID } }); + await hostSet.addHosts(hostIDs); + await this.replaceWith('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets.host-set.hosts'); this.notify.success( this.intl.t('notify.save-success') ); - this.replaceWith('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets.host-set.hosts'); } catch (error) { // TODO: replace with translated strings this.notify.error(error.message, { closeAfter: null }); diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.js index f349d0c72..7ae488994 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.js +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.js @@ -12,25 +12,16 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsHo // =methods - /** - * Empty out any previously loaded hosts. - */ - beforeModel() { - this.store.unloadAll('host'); - } - /** * Loads all hosts under the current host set. * @return {Promise{HostSetModel,[HostModel]}} */ async model() { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; const hostSet = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog.host-sets.host-set'); return hash({ hostSet, hosts: all(hostSet.host_ids.map(host => - 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 87525e6c8..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,12 +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, { - reload: true, - 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/mirage/config.js b/ui/core/mirage/config.js index 7c7a1fdf8..754e5a880 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -157,24 +157,30 @@ export default function() { // host - this.get('/host-catalogs/:hostCatalogId/hosts', function ({ hosts }, { params: { hostCatalogId } }) { + this.get('/hosts', function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) { return hosts.where({ hostCatalogId }); }); - this.post('/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('/host-catalogs/:hostCatalogId/hosts/:id'); - this.patch('/host-catalogs/:hostCatalogId/hosts/:id'); - this.del('/host-catalogs/:hostCatalogId/hosts/:id'); + this.get('/hosts/:id'); + this.patch('/hosts/:id'); + this.del('/hosts/:id'); // host-set this.get('/host-sets', function ({ hostSets }, { queryParams: { host_catalog_id: hostCatalogId } }) { return hostSets.where({ hostCatalogId }); }); - this.post('/host-sets'); + this.post('/host-sets', function ({ hostCatalogs, hostSets }) { + const attrs = this.normalizedRequestAttrs(); + const hostCatalog = hostCatalogs.find(attrs.hostCatalogId); + attrs.scopeId = hostCatalog.scope.id; + return hostSets.create(attrs); + }); this.get('/host-sets/:id'); this.patch('/host-sets/:id'); this.del('/host-sets/:id'); diff --git a/ui/core/mirage/factories/host-catalog.js b/ui/core/mirage/factories/host-catalog.js index f2541fcb7..1eaed0433 100644 --- a/ui/core/mirage/factories/host-catalog.js +++ b/ui/core/mirage/factories/host-catalog.js @@ -6,8 +6,7 @@ export default factory.extend({ withChildren: trait({ afterCreate(hostCatalog, server) { const { scope } = hostCatalog; - const scopePojo = { id: scope.id, type: scope.type }; - const hosts = server.createList('host', 10, { scope: scopePojo, hostCatalog }); + const hosts = server.createList('host', 10, { scope, hostCatalog }); server.createList('host-set', 3, { scope, hostCatalog, hosts }); } }) 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/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; + } + });