diff --git a/addons/api/addon/models/host-catalog.js b/addons/api/addon/models/host-catalog.js
index ec34b50e3..08e1a7d82 100644
--- a/addons/api/addon/models/host-catalog.js
+++ b/addons/api/addon/models/host-catalog.js
@@ -26,7 +26,7 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
* @type {boolean}
*/
get isUnknown() {
- return this.isPlugin && !types.includes(this.plugin.name);
+ return this.isPlugin && !types.includes(this.plugin?.name);
}
/**
diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml
index 05105fbac..87beceb23 100644
--- a/addons/core/translations/form/en-us.yaml
+++ b/addons/core/translations/form/en-us.yaml
@@ -118,3 +118,13 @@ callback_url:
filter:
label: Filter
help: A boolean expression defining a filter run against the provided information.
+tenant_id:
+ label: Tenant ID
+subscription_id:
+ label: Subscription ID
+access_key_id:
+ label: Access Key ID
+secret_access_key:
+ label: Secret Access Key
+region:
+ label: Region
\ No newline at end of file
diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml
index 4ac6c4023..27e3497c0 100644
--- a/addons/core/translations/resources/en-us.yaml
+++ b/addons/core/translations/resources/en-us.yaml
@@ -78,16 +78,32 @@ host-catalog:
title: Host Catalog
title_plural: Host Catalogs
description: A host catalog is a collection of hosts and host sets.
+ type: Type
messages:
welcome:
title: Welcome to Host Catalogs
actions:
delete: Delete Host Catalog
types:
- static: Static
- unknown: Unknown
- aws: AWS
- azure: Azure
+ static:
+ label: Static
+ help: Provide a list of hosts and host sets with static addresses
+ unknown:
+ label: Unknown
+ aws:
+ label: AWS
+ azure:
+ label: Azure
+ dynamic:
+ label: Dynamic
+ help: Automate discovery of target hosts and services on Azure or AWS
+ form:
+ provider:
+ label: Provider Details
+ description: This is the provider for this host catalog. The format of the host set filters are specific to each provider.
+ choose_a_provider:
+ label: Choose a provider
+ description: There are several built-in plugins for the most common providers. You can choose from on of the included plugins or use a custom plugin.
host-set:
title: Host Set
title_plural: Host Sets
diff --git a/addons/rose/addon/styles/rose/components/form/_radio-card.scss b/addons/rose/addon/styles/rose/components/form/_radio-card.scss
index 5e8018b40..d8b69c896 100644
--- a/addons/rose/addon/styles/rose/components/form/_radio-card.scss
+++ b/addons/rose/addon/styles/rose/components/form/_radio-card.scss
@@ -61,7 +61,7 @@ $radio-svg: (
display: inline-flex;
align-items: center;
justify-content: center;
- margin: $size-m $size-xs $size-xl 0;
+ margin: $size-m $size-xs $size-m 0;
.radio-card-overlay {
position: absolute;
diff --git a/ui/admin/app/components/form/host-catalog/aws/index.hbs b/ui/admin/app/components/form/host-catalog/aws/index.hbs
new file mode 100644
index 000000000..d343e3cdd
--- /dev/null
+++ b/ui/admin/app/components/form/host-catalog/aws/index.hbs
@@ -0,0 +1,150 @@
+
+
+ {{#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}}
+
+
+ {{#if @model.isNew}}
+
+ <:title>{{t 'form.type.label'}}
+ <:body>
+
+
+
+
+
+
+
+
+
+ <:title>{{t 'resources.host-catalog.form.provider.label'}}
+
+
+
+ <:title>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.label'
+ }}
+ <:description>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.description'
+ }}
+
+ <:body>
+
+
+
+
+
+
+ {{else}}
+
+ <:title>{{t 'resources.host-catalog.form.provider.label'}}
+ <:description>{{t
+ 'resources.host-catalog.form.provider.description'
+ }}
+ <:body>
+
+
+
+
+
+ {{/if}}
+
+
+
+ {{#if (can 'save model' @model)}}
+
+ {{/if}}
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/host-catalog/azure/index.hbs b/ui/admin/app/components/form/host-catalog/azure/index.hbs
new file mode 100644
index 000000000..468416242
--- /dev/null
+++ b/ui/admin/app/components/form/host-catalog/azure/index.hbs
@@ -0,0 +1,156 @@
+
+
+ {{#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}}
+
+
+ {{#if @model.isNew}}
+ {{!-- {{t
+ 'resources.host-catalog.form.provider.label'
+ }} --}}
+
+
+ <:title>{{t 'form.type.label'}}
+ <:body>
+
+
+
+
+
+
+
+
+
+ <:title>{{t 'resources.host-catalog.form.provider.label'}}
+
+
+ <:title>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.label'
+ }}
+ <:description>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.description'
+ }}
+
+ <:body>
+
+
+
+
+
+
+ {{else}}
+
+
+ <:title>{{t 'resources.host-catalog.form.provider.label'}}
+ <:description>{{t
+ 'resources.host-catalog.form.provider.description'
+ }}
+
+ <:body>
+
+
+
+
+
+ {{/if}}
+
+
+
+ {{#if (can 'save model' @model)}}
+
+ {{/if}}
+
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/host-catalog/index.hbs b/ui/admin/app/components/form/host-catalog/index.hbs
index 39571b820..90cebebc9 100644
--- a/ui/admin/app/components/form/host-catalog/index.hbs
+++ b/ui/admin/app/components/form/host-catalog/index.hbs
@@ -1,56 +1,7 @@
-
-
-
- {{#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}}
-
- {{#if (can 'save model' @model)}}
-
- {{/if}}
-
\ No newline at end of file
+{{component
+ (concat 'form/host-catalog/' @model.compositeType)
+ model=@model
+ submit=@submit
+ cancel=@cancel
+ changeType=@changeType
+}}
\ No newline at end of file
diff --git a/ui/admin/app/components/form/host-catalog/static/index.hbs b/ui/admin/app/components/form/host-catalog/static/index.hbs
new file mode 100644
index 000000000..bc0ac2421
--- /dev/null
+++ b/ui/admin/app/components/form/host-catalog/static/index.hbs
@@ -0,0 +1,120 @@
+
+
+ {{#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}}
+
+
+ {{#if @model.isNew}}
+
+ <:title>{{t 'form.type.label'}}
+ <:body>
+
+
+
+
+
+
+
+ {{#if @model.isPlugin}}
+
+
+ <:title>{{t 'resources.host-catalog.form.provider.label'}}
+
+
+
+ <:title>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.label'
+ }}
+ <:description>{{t
+ 'resources.host-catalog.form.provider.choose_a_provider.description'
+ }}
+
+ <:body>
+
+
+
+
+
+
+ {{/if}}
+ {{/if}}
+
+ {{#if (can 'save model' @model)}}
+
+ {{/if}}
+
\ No newline at end of file
diff --git a/ui/admin/app/controllers/scopes/scope/host-catalogs/new.js b/ui/admin/app/controllers/scopes/scope/host-catalogs/new.js
new file mode 100644
index 000000000..182b9c423
--- /dev/null
+++ b/ui/admin/app/controllers/scopes/scope/host-catalogs/new.js
@@ -0,0 +1,7 @@
+import Controller from '@ember/controller';
+
+export default class ScopesScopeHostCatalogsNewController extends Controller {
+ // =attributes
+
+ queryParams = ['type'];
+}
diff --git a/ui/admin/app/routes/scopes/scope/host-catalogs/new.js b/ui/admin/app/routes/scopes/scope/host-catalogs/new.js
index 9af8baaef..588ecac90 100644
--- a/ui/admin/app/routes/scopes/scope/host-catalogs/new.js
+++ b/ui/admin/app/routes/scopes/scope/host-catalogs/new.js
@@ -1,17 +1,53 @@
import Route from '@ember/routing/route';
+import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
export default class ScopesScopeHostCatalogsNewRoute extends Route {
+ // =services
+
+ @service router;
+
+ // =attributes
+
+ queryParams = {
+ type: {
+ refreshModel: true,
+ },
+ };
+
// =methods
+ /**
+ * Rollback/destroy any new, unsaved instances from this route before
+ * creating another.
+ */
+ beforeModel() {
+ if (this.currentModel?.isNew) this.currentModel.rollbackAttributes();
+ }
+
/**
* Creates a new unsaved host catalog belonging to the current scope.
* @return {HostCatalogModel}
*/
model() {
const scopeModel = this.modelFor('scopes.scope');
- return this.store.createRecord('host-catalog', {
- type: 'static',
- scopeModel,
- });
+ return this.store.createRecord('host-catalog', { scopeModel });
+ }
+
+ afterModel(model, transition) {
+ this.changeType(transition.to.queryParams?.type);
+ }
+
+ /**
+ * Update type of host catalog
+ * @param {string} type
+ */
+ @action
+ async changeType(type) {
+ const model = this.modelFor('scopes.scope.host-catalogs.new');
+ if (!type) type = 'static'; // Unknown host catalog type defaults to 'static'
+ if (model.isUnknown) type = 'aws'; //Is this the default case for plugin type?
+ model.compositeType = type;
+ await this.router.replaceWith({ queryParams: { type } });
}
}
diff --git a/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs b/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs
index f7def8b62..79e33a11c 100644
--- a/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs
+++ b/ui/admin/app/templates/scopes/scope/host-catalogs/index.hbs
@@ -62,6 +62,7 @@
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
+ '.label'
)
}}
@@ -71,6 +72,7 @@
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
+ '.label'
)
}}
@@ -86,6 +88,7 @@
(concat
'resources.host-catalog.types.'
hostCatalog.compositeType
+ '.label'
)
}}
diff --git a/ui/admin/app/templates/scopes/scope/host-catalogs/new.hbs b/ui/admin/app/templates/scopes/scope/host-catalogs/new.hbs
index fb936598e..68fad6fd1 100644
--- a/ui/admin/app/templates/scopes/scope/host-catalogs/new.hbs
+++ b/ui/admin/app/templates/scopes/scope/host-catalogs/new.hbs
@@ -18,6 +18,7 @@
@model={{@model}}
@submit={{route-action 'save' @model}}
@cancel={{route-action 'cancel' @model}}
+ @changeType={{route-action 'changeType'}}
/>
diff --git a/ui/admin/tests/acceptance/host-catalogs/create-test.js b/ui/admin/tests/acceptance/host-catalogs/create-test.js
index b47b3b4ea..19fc1dd3d 100644
--- a/ui/admin/tests/acceptance/host-catalogs/create-test.js
+++ b/ui/admin/tests/acceptance/host-catalogs/create-test.js
@@ -31,6 +31,8 @@ module('Acceptance | host-catalogs | create', function (hooks) {
hostCatalogs: null,
hostCatalog: null,
newHostCatalog: null,
+ newStaticHostCatalog: null,
+ newDynamicHostCatalog: null,
};
hooks.beforeEach(function () {
@@ -64,6 +66,8 @@ module('Acceptance | host-catalogs | create', function (hooks) {
urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`;
urls.newHostCatalog = `${urls.hostCatalogs}/new`;
+ urls.newStaticHostCatalog = `${urls.newHostCatalog}?type=static`;
+ urls.newDynamicHostCatalog = `${urls.newHostCatalog}?type=aws`;
// Generate resource couner
gethostCatalogCount = () =>
this.server.schema.hostCatalogs.all().models.length;
@@ -71,26 +75,49 @@ module('Acceptance | host-catalogs | create', function (hooks) {
authenticateSession({});
});
- test('Users can create new host catalogs', async function (assert) {
+ test('Users can create new static host catalogs', async function (assert) {
assert.expect(1);
const count = gethostCatalogCount();
- await visit(urls.newHostCatalog);
+ await visit(urls.newStaticHostCatalog);
await fillIn('[name="name"]', 'random string');
+ await fillIn('[name="description"]', 'random string');
+ await fillIn('[name="types"]', 'static');
await click('[type="submit"]');
assert.equal(gethostCatalogCount(), count + 1);
});
- test('Users can cancel create new host catalogs', async function (assert) {
+ test('Users can create new dynamic host catalogs', async function (assert) {
+ assert.expect(1);
+ const count = gethostCatalogCount();
+ await visit(urls.newDynamicHostCatalog);
+ await fillIn('[name="name"]', 'random string');
+ await fillIn('[name="description"]', 'random string');
+ await fillIn('[name="types"]', 'aws');
+ await click('[type="submit"]');
+ assert.equal(gethostCatalogCount(), count + 1);
+ });
+
+ test('Users can cancel creation of new static host catalogs', async function (assert) {
assert.expect(2);
const count = gethostCatalogCount();
- await visit(urls.newHostCatalog);
+ await visit(urls.newStaticHostCatalog);
await fillIn('[name="name"]', 'random string');
await click('.rose-form-actions [type="button"]');
assert.equal(currentURL(), urls.hostCatalogs);
assert.equal(gethostCatalogCount(), count);
});
- test('Users can navigate to new host catalogs route with proper authorization', async function (assert) {
+ test('Users can cancel creation of new dynamic host catalogs', async function (assert) {
+ assert.expect(2);
+ const count = gethostCatalogCount();
+ await visit(urls.newDynamicHostCatalog);
+ await fillIn('[name="name"]', 'random string');
+ await click('.rose-form-actions [type="button"]');
+ assert.equal(currentURL(), urls.hostCatalogs);
+ assert.equal(gethostCatalogCount(), count);
+ });
+
+ test('Users can navigate to new static host catalogs route with proper authorization', async function (assert) {
assert.expect(2);
await visit(urls.hostCatalogs);
assert.ok(
@@ -101,7 +128,7 @@ module('Acceptance | host-catalogs | create', function (hooks) {
assert.ok(find(`[href="${urls.newHostCatalog}"]`));
});
- test('Users cannot navigate to new host catalogs route without proper authorization', async function (assert) {
+ test('Users cannot navigate to new static host catalogs route without proper authorization', async function (assert) {
assert.expect(2);
instances.scopes.project.authorized_collection_actions['host-catalogs'] =
[];
@@ -111,10 +138,10 @@ module('Acceptance | host-catalogs | create', function (hooks) {
'host-catalogs'
].includes('create')
);
- assert.notOk(find(`[href="${urls.newHostCatalog}"]`));
+ assert.notOk(find(`[href="${urls.newStaticHostCatalog}"]`));
});
- test('saving a new host catalog with invalid fields displays error messages', async function (assert) {
+ test('saving a new static host catalog with invalid fields displays error messages', async function (assert) {
assert.expect(2);
this.server.post('/host-catalogs', () => {
return new Response(
@@ -135,7 +162,7 @@ module('Acceptance | host-catalogs | create', function (hooks) {
}
);
});
- await visit(urls.newHostCatalog);
+ await visit(urls.newStaticHostCatalog);
await click('[type="submit"]');
assert.ok(
find('[role="alert"]').textContent.trim(),
diff --git a/ui/admin/tests/unit/controllers/scopes/scope/host-catalogs/new-test.js b/ui/admin/tests/unit/controllers/scopes/scope/host-catalogs/new-test.js
new file mode 100644
index 000000000..c872fa28a
--- /dev/null
+++ b/ui/admin/tests/unit/controllers/scopes/scope/host-catalogs/new-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | scopes/scope/host-catalogs/new', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup(
+ 'controller:scopes/scope/host-catalogs/new'
+ );
+ assert.ok(controller);
+ });
+});