refactor: 💡 implement new pathing for hosts

This commit is contained in:
Randall Morey committed 2020-09-10 17:59:31 -04:00
1 parent 2d29d2216f
commit ebf129d35b
21 files changed
+106 -113

No files matched your search

+1 -1
View File
@@ -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;
+3 -23
View File
@@ -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;
}
@@ -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', {
@@ -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;
-13
View File
@@ -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
/**
+13
View File
@@ -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;
}
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/serializers/host';
+3 -19
View File
@@ -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);
});
});
@@ -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
});
});
@@ -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);
});
});
@@ -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 });
@@ -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 });
@@ -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 })
))
});
}
@@ -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
});
}
@@ -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 } };
}
}
@@ -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 });
}
/**
@@ -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
});
}
+13 -7
View File
@@ -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');
+1 -2
View File
@@ -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 });
}
})
+1
View File
@@ -2,6 +2,7 @@ import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
hostCatalog: belongsTo()
});
+18 -1
View File
@@ -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;
}
});