diff --git a/addons/api/addon/generated/models/auth-method.js b/addons/api/addon/generated/models/auth-method.js index 995e65efd..7dd5805c0 100644 --- a/addons/api/addon/generated/models/auth-method.js +++ b/addons/api/addon/generated/models/auth-method.js @@ -39,4 +39,9 @@ export default class GeneratedAuthMethodModel extends BaseModel { }) disabled; + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + } diff --git a/addons/api/addon/generated/models/group.js b/addons/api/addon/generated/models/group.js index bce0d1076..e8c442e1b 100644 --- a/addons/api/addon/generated/models/group.js +++ b/addons/api/addon/generated/models/group.js @@ -33,4 +33,10 @@ export default class GeneratedGroupModel extends BaseModel { description: 'Whether the resource is disabled', }) disabled; + + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + } diff --git a/addons/api/addon/generated/models/host-catalog.js b/addons/api/addon/generated/models/host-catalog.js index 4a8166e3c..7207048c2 100644 --- a/addons/api/addon/generated/models/host-catalog.js +++ b/addons/api/addon/generated/models/host-catalog.js @@ -38,4 +38,9 @@ export default class GeneratedHostCatalogModel extends BaseModel { description: 'Attributes specific to the catalog type' }) attributes; + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + } diff --git a/addons/api/addon/generated/models/scope.js b/addons/api/addon/generated/models/scope.js index a7448b034..3c3731b3d 100644 --- a/addons/api/addon/generated/models/scope.js +++ b/addons/api/addon/generated/models/scope.js @@ -34,4 +34,9 @@ export default class GeneratedScopeModel extends BaseModel { }) updated_time; + @attr('number', { + description: 'Current version number of this resource.', + }) + version; + } diff --git a/addons/api/addon/generated/models/user.js b/addons/api/addon/generated/models/user.js index 98fff7c32..433faeceb 100644 --- a/addons/api/addon/generated/models/user.js +++ b/addons/api/addon/generated/models/user.js @@ -33,4 +33,9 @@ export default class GeneratedUserModel extends BaseModel { description: 'Whether the resource is disabled', }) disabled; + + @attr('number', { + description: 'Current version number of this resource.', + }) + version; } diff --git a/addons/api/addon/serializers/application.js b/addons/api/addon/serializers/application.js index c839eb78c..bfe422161 100644 --- a/addons/api/addon/serializers/application.js +++ b/addons/api/addon/serializers/application.js @@ -40,6 +40,10 @@ export default class ApplicationSerializer extends RESTSerializer { let value = super.serializeAttribute(...arguments); // Do not serialize read-only attributes. if (options.readOnly) delete json[key]; + // Version is sent only if it has a non-nullish value + if (key === 'version') { + if (json[key] === null || json[key] === undefined) delete json[key]; + } // Do not serialize `disabled` fields. // TODO: disabled is temporarily disabled if (key === 'disabled') delete json[key]; diff --git a/addons/api/tests/unit/serializers/application-test.js b/addons/api/tests/unit/serializers/application-test.js index 4769cfa3f..c067939b9 100644 --- a/addons/api/tests/unit/serializers/application-test.js +++ b/addons/api/tests/unit/serializers/application-test.js @@ -29,6 +29,28 @@ module('Unit | Serializer | application', function (hooks) { }); }); + test('it serializes non-nullish version fields', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const record = store.createRecord('user', { + name: 'User', + description: 'Description', + version: null + }); + let serializedRecord = record.serialize(); + assert.deepEqual(serializedRecord, { + name: 'User', + description: 'Description' + }); + record.version = 1; + serializedRecord = record.serialize(); + assert.deepEqual(serializedRecord, { + name: 'User', + description: 'Description', + version: 1 + }); + }); + test('it normalizes array records from an `items` root key', function (assert) { assert.expect(1); const store = this.owner.lookup('service:store'); diff --git a/ui/core/app/components/form/host/index.hbs b/ui/core/app/components/form/host/index.hbs new file mode 100644 index 000000000..9152b0ba0 --- /dev/null +++ b/ui/core/app/components/form/host/index.hbs @@ -0,0 +1,55 @@ + + + + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + + diff --git a/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js new file mode 100644 index 000000000..0ce0c8ba4 --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js @@ -0,0 +1,20 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsController extends Controller { + + // =services + + @service intl; + + // =attributes + + /** + * Hosts breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.hosts'); + } + +} diff --git a/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js new file mode 100644 index 000000000..7b1b2883b --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js @@ -0,0 +1,15 @@ +import Controller from '@ember/controller'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsHostController extends Controller { + + // =attributes + + /** + * Host breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.model.displayName; + } + +} diff --git a/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js new file mode 100644 index 000000000..cc56bcf08 --- /dev/null +++ b/ui/core/app/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js @@ -0,0 +1,20 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsNewController extends Controller { + + // =services + + @service intl; + + // =attributes + + /** + * Translated new host breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('titles.new'); + } + +} diff --git a/ui/core/app/router.js b/ui/core/app/router.js index a047d9042..f0f18253c 100644 --- a/ui/core/app/router.js +++ b/ui/core/app/router.js @@ -27,6 +27,10 @@ Router.map(function () { this.route('host-set', { path: ':host_set_id' }, function() {}); this.route('new'); }); + this.route('hosts', function() { + this.route('host', { path: ':host_id' }, function() {}); + this.route('new'); + }); }); }); this.route('targets', function() { 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 b77bfcf35..74f1a2783 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 @@ -15,9 +15,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsRo * @return {Promise{[HostSetModel]}} */ async model() { - const scopeID = this.modelFor('scopes.scope.projects.project').id; - const hostCatalogID = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog').id; - return this.store.findAll('host-set', { adapterOptions: { scopeID, hostCatalogID } }); + return this.store.findAll('host-set', this.adapterOptions()); } // =actions 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 66c552c4d..6d2b4abd1 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 @@ -24,7 +24,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsHo * @param {object} model */ renderTemplate(controller, model) { - this.render('scopes/scope/projects/project/host-catalogs/host-catalog/host-sets'); + super.renderTemplate(...arguments); this.render('scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header', { into: 'scopes/scope/projects/project/host-catalogs/host-catalog', 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 87f67abc7..f0dbcc3bd 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 @@ -6,7 +6,7 @@ export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostSetsNe /** * Creates a new unsaved host set in current host catalog scope. - * @return {HostCatalogModel} + * @return {HostSetModel} */ model() { const scopeModel = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); 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 new file mode 100644 index 000000000..805112d67 --- /dev/null +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.js @@ -0,0 +1,81 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsRoute extends Route { + // =services + + @service intl; + @service notify; + + // =methods + + /** + * 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()); + } + + // =actions + + /** + * Rollback changes on a host. + * @param {HostModel} host + */ + @action + cancel(host) { + const { isNew } = host; + host.rollbackAttributes(); + if (isNew) this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.hosts'); + } + + /** + * Handle save of a host. + * @param {HostModel} host + * @param {Event} e + */ + @action + async save(host) { + try { + const { isNew } = host; + await host.save(this.adapterOptions()); + 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 }); + } + } + + /** + * Delete host in current scope and redirect to index. + * @param {HostModel} host + */ + @action + async delete(host) { + try { + await host.destroyRecord(this.adapterOptions()); + this.refresh(); + this.notify.success(this.intl.t('notify.delete-success')); + this.transitionTo('scopes.scope.projects.project.host-catalogs.host-catalog.hosts'); + } catch (error) { + // TODO: replace with translated strings + 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 new file mode 100644 index 000000000..907454d36 --- /dev/null +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.js @@ -0,0 +1,47 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsHostRoute extends Route { + // =methods + + /** + * Load a host using current host-catalog and it's parent project scope. + * @param {object} params + * @param {string} params.host_id + * @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, { + adapterOptions: { scopeID, hostCatalogID } + }); + } + + /** + * Renders the host specific templates for header, navigation, and action page sections. + * @override + * @param {object} controller + * @param {object} model + */ + renderTemplate(controller, model) { + super.renderTemplate(...arguments); + + this.render('scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'header', + model: model + }); + + this.render('scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-navigation', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'navigation', + model: model + }); + + this.render('scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-actions', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'actions', + model: model + }); + } +} diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.js new file mode 100644 index 000000000..a270ffacc --- /dev/null +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsHostIndexRoute extends Route { +} diff --git a/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.js b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.js new file mode 100644 index 000000000..96bba9927 --- /dev/null +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsIndexRoute extends Route { +} 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 new file mode 100644 index 000000000..39f90d1bb --- /dev/null +++ b/ui/core/app/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.js @@ -0,0 +1,46 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogHostsNewRoute extends Route { + + // =methods + + /** + * Creates a new unsaved host in current host catalog scope. + * @return {HostModel} + */ + model() { + const scopeModel = this.modelFor('scopes.scope.projects.project.host-catalogs.host-catalog'); + return this.store.createRecord('host', { + type: 'static', + scopeModel + }); + } + + /** + * Renders new host specific templates for header, navigation, and action page sections. + * @override + * @param {object} controller + * @param {object} model + */ + renderTemplate(controller, model) { + super.renderTemplate(...arguments); + + this.render('scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new/-header', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'header', + model: model + }); + + this.render('_empty', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'navigation', + model: model + }); + + this.render('_empty', { + into: 'scopes/scope/projects/project/host-catalogs/host-catalog', + outlet: 'actions', + model: model + }); + } +} diff --git a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs index a5bc4f485..3a7d79661 100644 --- a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs +++ b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs @@ -21,16 +21,16 @@ - {{t 'form.label.name'}} - {{t 'form.label.type'}} - {{t 'form.label.id'}} + {{t 'form.label.name'}} + {{t 'form.label.type'}} + {{t 'form.label.id'}} {{#each @model as |authMethod|}} - +

{{authMethod.description}}

-
+ {{t (concat 'auth.method-types.' authMethod.type)}} - {{authMethod.id}} + + {{authMethod.id}} +
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/groups/index.hbs b/ui/core/app/templates/scopes/scope/groups/index.hbs index cddaa478b..158ea31d0 100644 --- a/ui/core/app/templates/scopes/scope/groups/index.hbs +++ b/ui/core/app/templates/scopes/scope/groups/index.hbs @@ -21,22 +21,25 @@ - {{t 'form.label.name'}} - {{t 'form.label.description'}} + {{t "form.label.name"}} + {{t "form.label.id"}} {{#each @model as |group|}} - + {{group.name}} +

{{group.description}}

+
+ + {{group.id}} - {{group.description}}
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-actions.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-actions.hbs index 9f1032438..50cd97fe0 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-actions.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-actions.hbs @@ -1,4 +1,10 @@ + + {{t "actions.add-host"}} + {{t 'titles.host-sets'}} + + {{t 'titles.hosts'}} + diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs index 8b7dc963b..a3d132659 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs @@ -3,15 +3,15 @@ - {{t "form.label.name"}} - {{t "form.label.type"}} - {{t "form.label.id"}} + {{t "form.label.name"}} + {{t "form.label.type"}} + {{t "form.label.id"}} {{#each @model as |hostSet|}} - +

{{hostSet.description}}

-
+ {{hostSet.type}} diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.hbs new file mode 100644 index 000000000..863e34ea9 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts.hbs @@ -0,0 +1,3 @@ +{{title (t "resources.hosts")}} + +{{outlet}} \ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-actions.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-actions.hbs new file mode 100644 index 000000000..a63265116 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-actions.hbs @@ -0,0 +1,9 @@ + + + {{t 'actions.delete-host'}} + + \ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs new file mode 100644 index 000000000..3187158d1 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs @@ -0,0 +1 @@ +

{{t "resources.host"}}

\ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-navigation.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-navigation.hbs new file mode 100644 index 000000000..d79e3afa2 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-navigation.hbs @@ -0,0 +1,5 @@ + + + {{t 'titles.details'}} + + \ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.hbs new file mode 100644 index 000000000..e2147cab0 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host.hbs @@ -0,0 +1 @@ +{{outlet}} \ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.hbs new file mode 100644 index 000000000..6cc780607 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index.hbs @@ -0,0 +1,5 @@ + diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs new file mode 100644 index 000000000..3e5b48c5f --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs @@ -0,0 +1,48 @@ +{{#if @model}} + + + + + {{t "form.label.name"}} + {{t "form.label.type"}} + {{t "form.label.id"}} + + + + {{#each @model as |host|}} + + + + {{host.displayName}} + +

{{host.description}}

+
+ + {{host.type}} + + + {{host.id}} + +
+ {{/each}} +
+
+ +{{else}} + + + + + {{t "descriptions.hosts-welcome"}} + + + + {{t "titles.new"}} + + + + +{{/if}} diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.hbs new file mode 100644 index 000000000..29bf7404f --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new.hbs @@ -0,0 +1,7 @@ +{{title (t 'titles.new')}} + + \ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new/-header.hbs new file mode 100644 index 000000000..ace8ccb08 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new/-header.hbs @@ -0,0 +1 @@ +

{{t "titles.new"}}

\ No newline at end of file diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs index 8cc81e3db..56c923f9c 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs @@ -24,18 +24,15 @@ - {{t "form.label.id"}} - {{t "form.label.name"}} - {{t "form.label.type"}} + {{t "form.label.name"}} + {{t "form.label.type"}} + {{t "form.label.id"}} {{#each @model as |hostCatalog|}} - - {{hostCatalog.id}} - - +

{{hostCatalog.description}}

-
+ {{hostCatalog.type}} + + {{hostCatalog.id}} +
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/roles/index.hbs b/ui/core/app/templates/scopes/scope/roles/index.hbs index e0e28cf9a..7572875cf 100644 --- a/ui/core/app/templates/scopes/scope/roles/index.hbs +++ b/ui/core/app/templates/scopes/scope/roles/index.hbs @@ -21,22 +21,25 @@ - {{t 'form.label.name'}} - {{t 'form.label.description'}} + {{t "form.label.name"}} + {{t "form.label.id"}} {{#each @model as |role|}} - + {{role.displayName}} +

{{role.description}}

+
+ + {{role.id}} - {{role.description}}
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/users/index.hbs b/ui/core/app/templates/scopes/scope/users/index.hbs index fb0a06a09..40c312997 100644 --- a/ui/core/app/templates/scopes/scope/users/index.hbs +++ b/ui/core/app/templates/scopes/scope/users/index.hbs @@ -21,8 +21,8 @@ - {{t 'form.label.name'}} - {{t 'form.label.description'}} + {{t "form.label.name"}} + {{t "form.label.id"}} @@ -35,8 +35,11 @@ > {{user.name}} +

{{user.description}}

- {{user.description}} + + {{user.id}} +
{{/each}}
diff --git a/ui/core/tests/acceptance/host-catalogs-test.js b/ui/core/tests/acceptance/host-catalogs-test.js index fada1730e..3b79331c9 100644 --- a/ui/core/tests/acceptance/host-catalogs-test.js +++ b/ui/core/tests/acceptance/host-catalogs-test.js @@ -69,7 +69,7 @@ module('Acceptance | host catalogs', function (hooks) { assert.expect(1); authenticateSession({}); await visit(urls.hostCatalogs); - await click('main tbody .rose-table-cell:nth-child(2) a'); + await click('main tbody .rose-table-header-cell:nth-child(1) a'); await a11yAudit(); assert.equal(currentURL(), urls.hostCatalog); }); diff --git a/ui/core/tests/acceptance/hosts-test.js b/ui/core/tests/acceptance/hosts-test.js new file mode 100644 index 000000000..33ab3f05b --- /dev/null +++ b/ui/core/tests/acceptance/hosts-test.js @@ -0,0 +1,61 @@ +import { module, test } from 'qunit'; +// import { visit, currentURL } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +// import a11yAudit from 'ember-a11y-testing/test-support/audit'; +// import { +// authenticateSession, +// // These are left here intentionally for future reference. +// //currentSession, +// //invalidateSession, +// } from 'ember-simple-auth/test-support'; + +module('Acceptance | hosts', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + hooks.beforeEach(function () { + // Setup Mirage mock resources for this test + // Generate route URLs for resources + }); + + test('visiting host', async function (assert) { + assert.expect(0); + }); + + test('can navigate to a host form', async function (assert) { + assert.expect(0); + }); + + test('can update a host and save changes', async function (assert) { + assert.expect(0); + }); + + test('can update a host and cancel changes', async function (assert) { + assert.expect(0); + }); + + test('can create new host', async function (assert) { + assert.expect(0); + }); + + test('can cancel new host creation', async function (assert) { + assert.expect(0); + }); + + test('saving a new host with invalid fields displays error messages', async function (assert) { + assert.expect(0); + }); + + test('errors are displayed when save on auth method fails', async function (assert) { + assert.expect(0); + }); + + test('errors are displayed when delete on a host fails', async function (assert) { + assert.expect(0); + }); + + test('saving an existing host with invalid fields displays error messages', async function (assert) { + assert.expect(0); + }); +}); diff --git a/ui/core/tests/integration/components/form/host-test.js b/ui/core/tests/integration/components/form/host-test.js new file mode 100644 index 000000000..39c5147db --- /dev/null +++ b/ui/core/tests/integration/components/form/host-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | form/host', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + this.submit = () => {}; + this.cancel = () => {}; + + await render(hbs` + `); + + assert.ok(find('form')); + }); +}); diff --git a/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js new file mode 100644 index 000000000..0abab9e08 --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/projects/project/host-catalogs/host-catalog/hosts', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/projects/project/host-catalogs/host-catalog/hosts'); + assert.ok(controller); + }); +}); diff --git a/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js new file mode 100644 index 000000000..caa2b88fd --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host'); + assert.ok(controller); + }); +}); diff --git a/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js new file mode 100644 index 000000000..0fc59faf5 --- /dev/null +++ b/ui/core/tests/unit/controllers/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new'); + assert.ok(controller); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js new file mode 100644 index 000000000..528fd1ac1 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/projects/project/host-catalogs/host-catalog/hosts', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/projects/project/host-catalogs/host-catalog/hosts'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js new file mode 100644 index 000000000..ea1cc4118 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index-test.js b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index-test.js new file mode 100644 index 000000000..58704fe8c --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/host/index'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index-test.js b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index-test.js new file mode 100644 index 000000000..151e905b5 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js new file mode 100644 index 000000000..93ad5522c --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/projects/project/host-catalogs/host-catalog/hosts/new'); + assert.ok(route); + }); +}); diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 20114979f..fea3cd671 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -16,8 +16,10 @@ actions: delete-host-catalog: Delete host catalog delete-auth-method: Delete auth method delete-host-set: Delete host set + delete-host: Delete host delete-target: Delete target add-host-set: Create Host Set + add-host: Create Host auth: titles: no-scopes: No Scopes Available @@ -36,6 +38,9 @@ target: protocols: ssh: SSH SSH: SSH +host: + types: + static: Static resources: user: User users: Users @@ -53,6 +58,8 @@ resources: auth-methods: Auth Methods host-set: Host Set host-sets: Host Sets + hosts: Hosts + host: Host target: Target targets: Targets titles: @@ -67,6 +74,7 @@ titles: projects-welcome: Welcome to Projects host-catalogs-welcome: Welcome to Host Catalogs host-sets-welcome: Welcome to Host Sets + hosts-welcome: Welcome to Hosts users-welcome: Welcome to Users roles-welcome: Welcome to Roles groups-welcome: Welcome to Groups @@ -76,6 +84,7 @@ titles: new-grant: New Grant principals: Principals host-sets: Host Sets + hosts: Hosts targets: Targets global: Global descriptions: @@ -84,6 +93,7 @@ descriptions: projects-welcome: Projects allow you to create and manage host catalogs. To start, create a project. host-catalogs-welcome: Host catalogs allow you to configure to collect and create hosts and host sets. To start, create a host catalog. host-sets-welcome: Configure a static host set in this host catalog. + hosts-welcome: Configure a static host in this host catalog. users-welcome: Users are authorized to access Boundary. roles-welcome: Roles are collections of capabilities that can be granted to user and/or groups. groups-welcome: Groups are collections of users.