diff --git a/addons/api/addon/adapters/host.js b/addons/api/addon/adapters/host.js new file mode 100644 index 000000000..ae1747b06 --- /dev/null +++ b/addons/api/addon/adapters/host.js @@ -0,0 +1,38 @@ +import ApplicationAdapter from './application'; +import { inject as service } from '@ember/service'; + +export default class HostAdapter extends ApplicationAdapter { + + // =services + + @service store; + + // =methods + + /** + * 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. + * + * @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); + } + } + +} diff --git a/addons/api/addon/generated/models/host.js b/addons/api/addon/generated/models/host.js new file mode 100644 index 000000000..0d9e0dd2d --- /dev/null +++ b/addons/api/addon/generated/models/host.js @@ -0,0 +1,42 @@ +import BaseModel from '../../models/base'; +import { attr } from '@ember-data/model'; + +/** + * Host contains all fields related to a Host resource + */ +export default class GeneratedHostModel extends BaseModel { + + // =attributes + + @attr('string', { + description: 'The type of the resource, to help differentiate schemas' + }) type; + + @attr('string', { + description: 'Optional name for identification purposes' + }) name; + + @attr('string', { + description: 'Optional user-set description for identification purposes' + }) description; + + @attr('date', { + description: 'The time this resource was created\nOutput only.', + readOnly: true + }) created_time; + + @attr('date', { + description: 'The time this resource was last updated\nOutput only.', + readOnly: true + }) updated_time; + + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + + @attr('string', { + description: 'The address (DNS or IP name) used to reach the host' + }) address; + +} diff --git a/addons/api/addon/models/host-catalog.js b/addons/api/addon/models/host-catalog.js index 6f3729a47..894ee9cf1 100644 --- a/addons/api/addon/models/host-catalog.js +++ b/addons/api/addon/models/host-catalog.js @@ -1,11 +1,3 @@ import GeneratedHostCatalogModel from '../generated/models/host-catalog'; -import { hasMany } from '@ember-data/model'; -export default class HostCatalogModel extends GeneratedHostCatalogModel { - - /** - * @type {HostSetModel[]} - */ - @hasMany('host-set') hostSets; - -} +export default class HostCatalogModel extends GeneratedHostCatalogModel {} diff --git a/addons/api/addon/models/host-set.js b/addons/api/addon/models/host-set.js index ad1fd89a6..01a376f6b 100644 --- a/addons/api/addon/models/host-set.js +++ b/addons/api/addon/models/host-set.js @@ -1,13 +1,3 @@ import GeneratedHostSetModel from '../generated/models/host-set'; -import { belongsTo } from '@ember-data/model'; -export default class HostSetModel extends GeneratedHostSetModel { - - // =relationships - - /** - * @type {HostCatalogModel} - */ - @belongsTo('host-catalog') hostCatalog; - -} +export default class HostSetModel extends GeneratedHostSetModel {} diff --git a/addons/api/addon/models/host.js b/addons/api/addon/models/host.js new file mode 100644 index 000000000..451097080 --- /dev/null +++ b/addons/api/addon/models/host.js @@ -0,0 +1,3 @@ +import GeneratedHostModel from '../generated/models/host'; + +export default class HostModel extends GeneratedHostModel {} diff --git a/addons/api/app/adapters/host.js b/addons/api/app/adapters/host.js new file mode 100644 index 000000000..46bc96d3c --- /dev/null +++ b/addons/api/app/adapters/host.js @@ -0,0 +1 @@ +export { default } from 'api/adapters/host'; diff --git a/addons/api/app/models/host.js b/addons/api/app/models/host.js new file mode 100644 index 000000000..ce1f67327 --- /dev/null +++ b/addons/api/app/models/host.js @@ -0,0 +1 @@ +export { default } from 'api/models/host'; diff --git a/addons/api/tests/unit/adapters/host-test.js b/addons/api/tests/unit/adapters/host-test.js new file mode 100644 index 000000000..9e019284e --- /dev/null +++ b/addons/api/tests/unit/adapters/host-test.js @@ -0,0 +1,28 @@ +import { module, test } from 'qunit'; +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'); + }); + +}); diff --git a/addons/api/tests/unit/models/host-test.js b/addons/api/tests/unit/models/host-test.js new file mode 100644 index 000000000..d19d98fc3 --- /dev/null +++ b/addons/api/tests/unit/models/host-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | host', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('host', {}); + assert.ok(model); + }); +}); diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index 89159b0e0..4a949b05f 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -88,6 +88,14 @@ export default function() { this.patch('/scopes/:scope_id/host-catalogs/:id'); this.del('/scopes/:scope_id/host-catalogs/:id'); + // host + + this.get('/scopes/:scope_id/host-catalogs/:host_catalog_id/hosts'); + this.post('/scopes/:scope_id/host-catalogs/:host_catalog_id/hosts'); + this.get('/scopes/:scope_id/host-catalogs/:host_catalog_id/hosts/:id'); + this.patch('/scopes/:scope_id/host-catalogs/:host_catalog_id/hosts/:id'); + this.del('/scopes/:scope_id/host-catalogs/:host_catalog_id/hosts/:id'); + // host-set this.get('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets'); diff --git a/ui/core/mirage/factories/host-catalog.js b/ui/core/mirage/factories/host-catalog.js index d2f84b3c5..ffd635036 100644 --- a/ui/core/mirage/factories/host-catalog.js +++ b/ui/core/mirage/factories/host-catalog.js @@ -1,16 +1,3 @@ import factory from '../generated/factories/host-catalog'; -import { trait } from 'ember-cli-mirage'; -export default factory.extend({ - - /** - * Create catalogs with associated host sets and hosts. - */ - withChildren: trait({ - afterCreate(record, server) { - const host_set_ids = server.createList('host-set', 3).map(set => set.id); - record.update({ host_set_ids }); - } - }) - -}); +export default factory.extend(); diff --git a/ui/core/mirage/factories/host.js b/ui/core/mirage/factories/host.js new file mode 100644 index 000000000..eb463f1f9 --- /dev/null +++ b/ui/core/mirage/factories/host.js @@ -0,0 +1,3 @@ +import factory from '../generated/factories/host'; + +export default factory.extend(); diff --git a/ui/core/mirage/generated/factories/host.js b/ui/core/mirage/generated/factories/host.js new file mode 100644 index 000000000..2d6925e82 --- /dev/null +++ b/ui/core/mirage/generated/factories/host.js @@ -0,0 +1,17 @@ +import { Factory } from 'ember-cli-mirage'; +import { random, date, internet } from 'faker'; + +/** + * GeneratedHostModelFactory + */ +export default Factory.extend({ + + type: 'static', + name: () => random.words(), + description: () => random.words(), + created_time: () => date.recent(), + updated_time: () => date.recent(), + version: () => random.number(), + address: () => internet.ipv6(), + +}); diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js index 9215e8a80..2e830c4ce 100644 --- a/ui/core/mirage/scenarios/default.js +++ b/ui/core/mirage/scenarios/default.js @@ -25,9 +25,13 @@ export default function(server) { // Other resources - server.db.scopes.where({type: 'project'}).forEach(projectScope => { - const scope = { id: projectScope.id, type: projectScope.type }; - server.createList('host-catalog', 2, { scope }, 'withChildren'); + server.db.scopes.where({type: 'project'}).forEach(({ id, type }) => { + const scope = { id, type }; + server.createList('host-catalog', 2, { scope }); + // Hosts and host sets are supposed to be associated to a host catalog. + // For simplicity of mocks, we don't actually associate them here. + server.createList('host-set', 3, { scope }); + server.createList('host', 10, { scope }); }); }