diff --git a/addons/api/addon/adapters/application.js b/addons/api/addon/adapters/application.js index 71c109cb0..3bd3342a1 100644 --- a/addons/api/addon/adapters/application.js +++ b/addons/api/addon/adapters/application.js @@ -1,6 +1,8 @@ import RESTAdapter from '@ember-data/adapter/rest'; import config from 'ember-get-config'; import { get } from '@ember/object'; +import { dasherize } from '@ember/string'; +import { pluralize } from 'ember-inflector'; export default class ApplicationAdapter extends RESTAdapter { // =attributes @@ -21,6 +23,17 @@ export default class ApplicationAdapter extends RESTAdapter { // =methods + /** + * Transforms the type to a dasherized string used in our API paths. + * + * @override + * @param {string} type + * @return {string} + */ + pathForType(type) { + return dasherize(pluralize(type)); + } + /** * Overrides default ajax method by rewritting PUT requests as PATCH. * PATCH is the request method used by our API for updates. diff --git a/addons/api/addon/adapters/host-catalog.js b/addons/api/addon/adapters/host-catalog.js new file mode 100644 index 000000000..79d4b9444 --- /dev/null +++ b/addons/api/addon/adapters/host-catalog.js @@ -0,0 +1,6 @@ +import ApplicationAdapter from './application'; +import ScopeAdapterMixin from '../mixins/scope-adapter'; + +export default class HostCatalogAdapter extends ApplicationAdapter.extend( + ScopeAdapterMixin +) { } diff --git a/addons/api/addon/generated/models/host-catalog.js b/addons/api/addon/generated/models/host-catalog.js new file mode 100644 index 000000000..4a8166e3c --- /dev/null +++ b/addons/api/addon/generated/models/host-catalog.js @@ -0,0 +1,41 @@ +import BaseModel from '../../models/base'; +import { attr } from '@ember-data/model'; + +/** + * HostCatalog manages Hosts and HostSets + */ +export default class GeneratedHostCatalogModel 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('boolean', { + description: 'Whether the catalog is disabled' + }) disabled; + + @attr({ + description: 'Attributes specific to the catalog type' + }) attributes; + +} diff --git a/addons/api/addon/models/host-catalog.js b/addons/api/addon/models/host-catalog.js new file mode 100644 index 000000000..a0162bfeb --- /dev/null +++ b/addons/api/addon/models/host-catalog.js @@ -0,0 +1,3 @@ +import GeneratedHostCatalogModel from '../generated/models/host-catalog'; + +export default class HostCatalogModel extends GeneratedHostCatalogModel { } diff --git a/addons/api/app/adapters/host-catalog.js b/addons/api/app/adapters/host-catalog.js new file mode 100644 index 000000000..00197a624 --- /dev/null +++ b/addons/api/app/adapters/host-catalog.js @@ -0,0 +1 @@ +export { default } from 'api/adapters/host-catalog'; diff --git a/addons/api/app/models/host-catalog.js b/addons/api/app/models/host-catalog.js new file mode 100644 index 000000000..7125cd050 --- /dev/null +++ b/addons/api/app/models/host-catalog.js @@ -0,0 +1 @@ +export { default } from 'api/models/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..6250cc547 --- /dev/null +++ b/addons/api/tests/unit/adapters/host-catalog-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Adapter | host catalog', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:host-catalog'); + assert.ok(adapter); + }); +}); diff --git a/addons/api/tests/unit/models/host-catalog-test.js b/addons/api/tests/unit/models/host-catalog-test.js new file mode 100644 index 000000000..b653f00a5 --- /dev/null +++ b/addons/api/tests/unit/models/host-catalog-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | host catalog', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('host-catalog', {}); + assert.ok(model); + }); +}); diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index ce0e06960..de1cadb6c 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -9,24 +9,22 @@ export default function() { // delay for each request, automatically set to 0 during testing this.timing = 350; - /* - Shorthand cheatsheet: - - this.get('/posts'); - this.post('/posts'); - this.get('/posts/:id'); - this.put('/posts/:id'); // or this.patch - this.del('/posts/:id'); - - https://www.ember-cli-mirage.com/docs/route-handlers/shorthands - */ - + // Allow any configured API host to passthrough, which is useful in + // development for testing against a locally running backend. if (config.api.host) this.passthrough(`${config.api.host}/**`); this.passthrough(); + // project this.get('/orgs/:org_id/projects'); this.post('/orgs/:org_id/projects'); this.get('/orgs/:org_id/projects/:id'); this.patch('/orgs/:org_id/projects/:id'); this.del('/orgs/:org_id/projects/:id'); + + // host-catalog + this.get('/orgs/:org_id/projects/:project_id/host-catalogs'); + this.post('/orgs/:org_id/projects/:project_id/host-catalogs'); + this.get('/orgs/:org_id/projects/:project_id/host-catalogs/:id'); + this.patch('/orgs/:org_id/projects/:project_id/host-catalogs/:id'); + this.del('/orgs/:org_id/projects/:project_id/host-catalogs/:id'); } diff --git a/ui/core/mirage/factories/host-catalog.js b/ui/core/mirage/factories/host-catalog.js new file mode 100644 index 000000000..ffd635036 --- /dev/null +++ b/ui/core/mirage/factories/host-catalog.js @@ -0,0 +1,3 @@ +import factory from '../generated/factories/host-catalog'; + +export default factory.extend(); diff --git a/ui/core/mirage/generated/factories/host-catalog.js b/ui/core/mirage/generated/factories/host-catalog.js new file mode 100644 index 000000000..daf2d356f --- /dev/null +++ b/ui/core/mirage/generated/factories/host-catalog.js @@ -0,0 +1,16 @@ +import { Factory } from 'ember-cli-mirage'; +import { random, date } from 'faker'; + +/** + * GeneratedHostCatalogModelFactory + */ +export default Factory.extend({ + + type: 'static', + name: () => random.words(), + description: () => random.words(), + created_time: () => date.recent(), + updated_time: () => date.recent(), + disabled: () => random.boolean(), + +}); diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js index 070bbc1ee..fbf47a0b6 100644 --- a/ui/core/mirage/scenarios/default.js +++ b/ui/core/mirage/scenarios/default.js @@ -1,5 +1,14 @@ export default function(server) { + // Scope resources (org and project) have their relationship modelled. + server.createList('project', 3); + // For simplicity, other resources have their relationships modelled _except_ + // their relationships to scope. These leads to the situation where the UI + // displays _all subresources_ as if they belong to _every scope_. This is + // a tradeoff due to the complexity of relationship modelling. + + server.createList('host-catalog', 3); + } diff --git a/ui/core/mirage/serializers/host-catalog.js b/ui/core/mirage/serializers/host-catalog.js new file mode 100644 index 000000000..e7b237047 --- /dev/null +++ b/ui/core/mirage/serializers/host-catalog.js @@ -0,0 +1,5 @@ +import ApplicationSerializer from './application'; + +export default ApplicationSerializer.extend({ + modelName: 'host-catalog' +});