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, {},