Merge branch 'main' into chore-radio-template
This commit is contained in:
67 files changed
+2043
-494
No files matched your search
@@ -0,0 +1,23 @@
|
||||
import ApplicationAdapter from './application';
|
||||
|
||||
export default class HostCatalogAdapter extends ApplicationAdapter {
|
||||
/**
|
||||
* Overrides the default `buildURL` such that on _create_, URLs for records of
|
||||
* type `plugin` get an extra query parameter `?plugin_name`. All other
|
||||
* request types behave as normal.
|
||||
*
|
||||
* @override
|
||||
* @param {string} modelName
|
||||
* @param {string} id
|
||||
* @return {string} url
|
||||
* @return {string} requestType
|
||||
*/
|
||||
buildURL(modelName, id, snapshot, requestType) {
|
||||
let url = super.buildURL(...arguments);
|
||||
if (requestType === 'createRecord') {
|
||||
const pluginName = snapshot.attr('plugin')?.name;
|
||||
if (pluginName) url = `${url}?plugin_name=${pluginName}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,6 @@ export default class GeneratedHostCatalogModel extends BaseModel {
|
||||
})
|
||||
disabled;
|
||||
|
||||
@attr({
|
||||
description: 'Attributes specific to the catalog type',
|
||||
})
|
||||
attributes;
|
||||
|
||||
@attr('number', {
|
||||
description: 'Current version number of this resource.',
|
||||
})
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import Fragment from 'ember-data-model-fragments/fragment';
|
||||
import { attr } from '@ember-data/model';
|
||||
|
||||
export default class FragmentHostAttributesModel extends Fragment {
|
||||
@attr('string', {
|
||||
description: 'The address (DNS or IP name) used to reach the host',
|
||||
})
|
||||
address;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import GeneratedHostSetModel from '../generated/models/host-set';
|
||||
import { fragmentArray } from 'ember-data-model-fragments/attributes';
|
||||
import { types } from './host-catalog';
|
||||
|
||||
export default class HostSetModel extends GeneratedHostSetModel {
|
||||
// =attributes
|
||||
@@ -20,6 +21,14 @@ export default class HostSetModel extends GeneratedHostSetModel {
|
||||
return this.type === 'plugin';
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the host set is an unknown type.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isUnknown() {
|
||||
return this.isPlugin && !types.includes(this.plugin?.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a host-set plugin is AWS or not
|
||||
* @type {boolean}
|
||||
@@ -41,7 +50,9 @@ export default class HostSetModel extends GeneratedHostSetModel {
|
||||
* @type {string}
|
||||
*/
|
||||
get compositeType() {
|
||||
return this.plugin ? this.plugin.name : this.type;
|
||||
if (this.isUnknown) return 'unknown';
|
||||
if (this.isPlugin) return this.plugin.name;
|
||||
return 'static';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,35 @@
|
||||
import GeneratedHostModel from '../generated/models/host';
|
||||
import { fragment } from 'ember-data-model-fragments/attributes';
|
||||
import { attr } from '@ember-data/model';
|
||||
|
||||
export default class HostModel extends GeneratedHostModel {
|
||||
/**
|
||||
* Attributes of this resource, if any, represented as a JSON fragment.
|
||||
* @type {FragmentHostAttributesModel}
|
||||
*/
|
||||
@fragment('fragment-host-attributes', { defaultValue: {} }) attributes;
|
||||
// =attributes
|
||||
|
||||
// Static specific fields
|
||||
@attr('string', {
|
||||
description: 'The address (DNS or IP name) used to reach the host',
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
address;
|
||||
|
||||
// Plugin specific fields
|
||||
@attr({
|
||||
readOnly: true,
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
ip_addresses;
|
||||
|
||||
@attr('string', {
|
||||
description: '',
|
||||
readOnly: true,
|
||||
})
|
||||
external_id;
|
||||
|
||||
// Aws specific
|
||||
@attr({
|
||||
readOnly: true,
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
dns_names;
|
||||
|
||||
/**
|
||||
* True if the host is static.
|
||||
|
||||
@@ -234,11 +234,13 @@ export default class ApplicationSerializer extends RESTSerializer {
|
||||
*/
|
||||
normalizeNestedAttributes(typeClass, hash) {
|
||||
typeClass.attributes.forEach((attribute) => {
|
||||
const { isNestedAttribute } = attribute.options;
|
||||
const attributeValue = hash.attributes?.[attribute.name];
|
||||
if (isNestedAttribute && attributeValue) {
|
||||
hash[attribute.name] = attributeValue;
|
||||
}
|
||||
const {
|
||||
name,
|
||||
options: { isNestedAttribute },
|
||||
} = attribute;
|
||||
const value = hash.attributes?.[name];
|
||||
const isUndefined = value === undefined;
|
||||
if (isNestedAttribute && !isUndefined) hash[name] = value;
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
@@ -261,7 +263,8 @@ export default class ApplicationSerializer extends RESTSerializer {
|
||||
name,
|
||||
options: { isNestedSecret },
|
||||
} = attribute;
|
||||
if (isNestedSecret) hash[name] = null;
|
||||
const value = hash.secrets?.[name];
|
||||
if (isNestedSecret) hash[name] = value || null;
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ApplicationSerializer from './application';
|
||||
import { copy } from 'ember-copy';
|
||||
|
||||
const fieldByType = {
|
||||
aws: ['preferred_endpoints', 'filters'],
|
||||
@@ -69,4 +70,19 @@ export default class HostSetSerializer extends ApplicationSerializer {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily converts `filters` to an array if it is a string. This is a
|
||||
* quirk of the API.
|
||||
*
|
||||
* TODO: remove once API consistently returns arrays.
|
||||
*/
|
||||
normalize(typeClass, hash, ...rest) {
|
||||
const normalizedHash = copy(hash, true);
|
||||
if (typeof normalizedHash?.filters === 'string') {
|
||||
normalizedHash.filters = [normalizedHash.filters];
|
||||
}
|
||||
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'api/adapters/host-catalog';
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from 'api/models/fragment-host-attributes';
|
||||
@@ -270,7 +270,19 @@ export default function () {
|
||||
return hostCatalogs.where({ scopeId });
|
||||
}
|
||||
);
|
||||
this.post('/host-catalogs');
|
||||
this.post(
|
||||
'/host-catalogs',
|
||||
function ({ hostCatalogs }, { queryParams: { plugin_name } }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
if (plugin_name) {
|
||||
attrs.type = 'plugin';
|
||||
attrs.plugin = {
|
||||
name: plugin_name,
|
||||
};
|
||||
}
|
||||
return hostCatalogs.create(attrs);
|
||||
}
|
||||
);
|
||||
this.get('/host-catalogs/:id');
|
||||
this.patch('/host-catalogs/:id');
|
||||
this.del('/host-catalogs/:id');
|
||||
|
||||
@@ -47,19 +47,30 @@ export default factory.extend({
|
||||
case 'aws':
|
||||
return {
|
||||
disable_credential_rotation: datatype.boolean(),
|
||||
tenant_id: datatype.hexaDecimal(6),
|
||||
client_id: datatype.hexaDecimal(6),
|
||||
subscription_id: datatype.hexaDecimal(8),
|
||||
secret_id: datatype.hexaDecimal(6),
|
||||
secret_value: datatype.string(12),
|
||||
region: address.state(),
|
||||
};
|
||||
case 'azure':
|
||||
return {
|
||||
disable_credential_rotation: datatype.boolean(),
|
||||
region: address.state(),
|
||||
tenant_id: datatype.hexaDecimal(6),
|
||||
client_id: datatype.hexaDecimal(6),
|
||||
subscription_id: datatype.hexaDecimal(8),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
secrets() {
|
||||
switch (this.plugin?.name) {
|
||||
case 'aws':
|
||||
return {
|
||||
access_key_id: datatype.hexaDecimal(8),
|
||||
secret_access_key: datatype.string(12),
|
||||
};
|
||||
case 'azure':
|
||||
return {
|
||||
secret_id: datatype.hexaDecimal(6),
|
||||
secret_value: datatype.string(12),
|
||||
};
|
||||
}
|
||||
},
|
||||
withChildren: trait({
|
||||
|
||||
@@ -43,7 +43,7 @@ export default factory.extend({
|
||||
// Azure specific
|
||||
filter() {
|
||||
if (this.plugin?.name === 'azure') {
|
||||
return `${database.column}=${database.collation}`;
|
||||
return `${database.column()}=${database.collation()}`;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
import factory from '../generated/factories/host';
|
||||
import permissions from '../helpers/permissions';
|
||||
import { internet, datatype } from 'faker';
|
||||
|
||||
export default factory.extend({
|
||||
id: (i) => `host-id-${i}`,
|
||||
@@ -18,4 +19,26 @@ export default factory.extend({
|
||||
return this.hostCatalog.plugin;
|
||||
}
|
||||
},
|
||||
ip_addresses() {
|
||||
const addressesAmount = Math.floor(Math.random() * 6) + 1;
|
||||
let result = [];
|
||||
for (let i = 0; i < addressesAmount; ++i) {
|
||||
result.push(internet.ip());
|
||||
}
|
||||
return result;
|
||||
},
|
||||
external_id() {
|
||||
return datatype.uuid();
|
||||
},
|
||||
// Only aws plugins have dns_names
|
||||
dns_names() {
|
||||
if (this.plugin?.name === 'aws') {
|
||||
const dnsNamesAmount = Math.floor(Math.random() * 6) + 1;
|
||||
let result = [];
|
||||
for (let i = 0; i < dnsNamesAmount; i++) {
|
||||
result.push(internet.domainName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Factory } from 'ember-cli-mirage';
|
||||
import { random, date, internet, datatype } from 'faker';
|
||||
import { random, date, datatype, internet } from 'faker';
|
||||
|
||||
/**
|
||||
* GeneratedHostModelFactory
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-cli": "~4.1.0",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Adapter | host catalog', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it generates correct createRecord URLs for static host catalogs', function (assert) {
|
||||
assert.expect(1);
|
||||
const scopeID = 'o_1';
|
||||
const mockSnapshot = {
|
||||
adapterOptions: {
|
||||
scopeID,
|
||||
},
|
||||
attr() {
|
||||
return null;
|
||||
},
|
||||
};
|
||||
const adapter = this.owner.lookup('adapter:host-catalog');
|
||||
const createRecordURL = adapter.buildURL(
|
||||
'host-catalog',
|
||||
null,
|
||||
mockSnapshot,
|
||||
'createRecord'
|
||||
);
|
||||
assert.equal(createRecordURL, '/v1/host-catalogs');
|
||||
});
|
||||
|
||||
test('it generates correct createRecord URLs for dynamic host catalogs with extra query parameter ?plugin_name', function (assert) {
|
||||
assert.expect(1);
|
||||
const scopeID = 'o_1';
|
||||
const mockSnapshot = {
|
||||
adapterOptions: {
|
||||
scopeID,
|
||||
},
|
||||
attr() {
|
||||
return { name: 'aws' };
|
||||
},
|
||||
};
|
||||
const adapter = this.owner.lookup('adapter:host-catalog');
|
||||
const createRecordURL = adapter.buildURL(
|
||||
'host-catalog',
|
||||
null,
|
||||
mockSnapshot,
|
||||
'createRecord'
|
||||
);
|
||||
assert.equal(createRecordURL, '/v1/host-catalogs?plugin_name=aws');
|
||||
});
|
||||
});
|
||||
@@ -183,15 +183,19 @@ module('Unit | Model | host set', function (hooks) {
|
||||
test('get compositeType return expected values', async function (assert) {
|
||||
assert.expect(3);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const modelPlugin = store.createRecord('host-set', {
|
||||
const modelPlugin1 = store.createRecord('host-set', {
|
||||
type: 'plugin',
|
||||
plugin: { name: 'aws' },
|
||||
});
|
||||
const modelPlugin2 = store.createRecord('host-set', {
|
||||
type: 'plugin',
|
||||
plugin: { name: 'Test name' },
|
||||
});
|
||||
const modelStatic = store.createRecord('host-set', {
|
||||
type: 'static',
|
||||
});
|
||||
assert.equal(typeof modelPlugin.compositeType, 'string');
|
||||
assert.equal(modelPlugin.compositeType, 'Test name');
|
||||
assert.equal(modelPlugin1.compositeType, 'aws');
|
||||
assert.equal(modelPlugin2.compositeType, 'unknown');
|
||||
assert.equal(modelStatic.compositeType, 'static');
|
||||
});
|
||||
|
||||
|
||||
@@ -4,14 +4,6 @@ import { setupTest } from 'ember-qunit';
|
||||
module('Unit | Serializer | host catalog', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host-catalog');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const record = store.createRecord('host-catalog', {});
|
||||
@@ -171,4 +163,159 @@ module('Unit | Serializer | host catalog', function (hooks) {
|
||||
};
|
||||
assert.deepEqual(record.serialize(), expectedResult);
|
||||
});
|
||||
|
||||
test('it normalizes an static host catalog as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host-catalog');
|
||||
const hostCatalog = store.createRecord('host-catalog').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
name: 'Host catalog test',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op'],
|
||||
type: 'static',
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(
|
||||
store,
|
||||
hostCatalog,
|
||||
payload
|
||||
);
|
||||
assert.deepEqual(normalized, {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'host-catalog',
|
||||
attributes: {
|
||||
name: 'Host catalog test',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op'],
|
||||
type: 'static',
|
||||
access_key_id: null,
|
||||
secret_access_key: null,
|
||||
secret_id: null,
|
||||
secret_value: null,
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
included: [],
|
||||
});
|
||||
});
|
||||
|
||||
test('it normalizes an aws plugin type host catalog as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host-catalog');
|
||||
const hostCatalog = store.createRecord('host-catalog').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
name: 'Host catalog test',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op'],
|
||||
type: 'plugin',
|
||||
plugin: {
|
||||
id: 'plugin-id-5',
|
||||
name: 'aws',
|
||||
description: 'aws host catalog',
|
||||
},
|
||||
attributes: {
|
||||
disable_credential_rotation: false,
|
||||
region: 'Illinois',
|
||||
},
|
||||
secrets: {
|
||||
access_key_id: '0xF3B0a6f8',
|
||||
secret_access_key: 'zq{2:IVc8@W^',
|
||||
},
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(
|
||||
store,
|
||||
hostCatalog,
|
||||
payload
|
||||
);
|
||||
assert.deepEqual(normalized, {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'host-catalog',
|
||||
attributes: {
|
||||
name: 'Host catalog test',
|
||||
type: 'plugin',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op'],
|
||||
plugin: {
|
||||
id: 'plugin-id-5',
|
||||
name: 'aws',
|
||||
description: 'aws host catalog',
|
||||
},
|
||||
disable_credential_rotation: false,
|
||||
region: 'Illinois',
|
||||
access_key_id: '0xF3B0a6f8',
|
||||
secret_access_key: 'zq{2:IVc8@W^',
|
||||
secret_id: null,
|
||||
secret_value: null,
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
included: [],
|
||||
});
|
||||
});
|
||||
|
||||
test('it normalizes an azure plugin type host catalog as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host-catalog');
|
||||
const hostCatalog = store.createRecord('host-catalog').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
name: 'Host catalog test',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op', 'read', 'update', 'delete'],
|
||||
type: 'plugin',
|
||||
plugin: {
|
||||
id: 'plugin-id-6',
|
||||
name: 'azure',
|
||||
description: 'azure host catalog',
|
||||
},
|
||||
attributes: {
|
||||
disable_credential_rotation: true,
|
||||
tenant_id: 'tenant',
|
||||
client_id: 'client',
|
||||
subscription_id: 'subscription',
|
||||
},
|
||||
secrets: {
|
||||
secret_id: '0xF3B0a6f8',
|
||||
secret_value: 'zq{2:IVc8@W^',
|
||||
},
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(
|
||||
store,
|
||||
hostCatalog,
|
||||
payload
|
||||
);
|
||||
assert.deepEqual(normalized, {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'host-catalog',
|
||||
attributes: {
|
||||
name: 'Host catalog test',
|
||||
type: 'plugin',
|
||||
description: 'Test description',
|
||||
authorized_actions: ['no-op', 'read', 'update', 'delete'],
|
||||
plugin: {
|
||||
id: 'plugin-id-6',
|
||||
name: 'azure',
|
||||
description: 'azure host catalog',
|
||||
},
|
||||
disable_credential_rotation: true,
|
||||
secret_id: '0xF3B0a6f8',
|
||||
secret_value: 'zq{2:IVc8@W^',
|
||||
client_id: 'client',
|
||||
tenant_id: 'tenant',
|
||||
subscription_id: 'subscription',
|
||||
access_key_id: null,
|
||||
secret_access_key: null,
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
included: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,19 +4,92 @@ import { setupTest } from 'ember-qunit';
|
||||
module('Unit | Serializer | host', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let serializer = store.serializerFor('host');
|
||||
|
||||
assert.ok(serializer);
|
||||
test('it serializes host with type static as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const record = store.createRecord('host', {
|
||||
name: 'Host 1',
|
||||
compositeType: 'static',
|
||||
description: 'Description',
|
||||
host_catalog_id: '123',
|
||||
version: 1,
|
||||
address: '188e:68a9:b342:c05c:2595:2f46:499c:759f',
|
||||
});
|
||||
assert.deepEqual(record.serialize(), {
|
||||
name: 'Host 1',
|
||||
description: 'Description',
|
||||
type: 'static',
|
||||
host_catalog_id: '123',
|
||||
version: 1,
|
||||
attributes: {
|
||||
address: '188e:68a9:b342:c05c:2595:2f46:499c:759f',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('host', {});
|
||||
test('it normalizes type static record as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host');
|
||||
const host = store.createRecord('host').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
name: 'host test',
|
||||
type: 'static',
|
||||
authorized_actions: ['no-op', 'read'],
|
||||
address: '10.0.0.1',
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(store, host, payload);
|
||||
assert.deepEqual(normalized, {
|
||||
included: [],
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'host',
|
||||
attributes: {
|
||||
name: 'host test',
|
||||
type: 'static',
|
||||
authorized_actions: ['no-op', 'read'],
|
||||
address: '10.0.0.1',
|
||||
dns_names: [],
|
||||
ip_addresses: [],
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
test('it normalizes type plugin (aws) record as expected', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('host');
|
||||
const host = store.createRecord('host').constructor;
|
||||
const payload = {
|
||||
id: '1',
|
||||
name: 'host test',
|
||||
type: 'plugin',
|
||||
plugin: {
|
||||
name: 'aws',
|
||||
},
|
||||
authorized_actions: ['no-op', 'read'],
|
||||
ip_addresses: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
||||
dns_names: ['test.example.internal', 'test.example.external'],
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(store, host, payload);
|
||||
assert.deepEqual(normalized, {
|
||||
included: [],
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'host',
|
||||
attributes: {
|
||||
name: 'host test',
|
||||
type: 'plugin',
|
||||
authorized_actions: ['no-op', 'read'],
|
||||
ip_addresses: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
||||
dns_names: ['test.example.internal', 'test.example.external'],
|
||||
plugin: { name: 'aws' },
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -28,13 +28,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"core": "*",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-cli": "~4.1.0",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
|
||||
@@ -42,12 +42,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-cli": "~4.1.0",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
|
||||
@@ -36,3 +36,4 @@ toggle-secret: Toggle secret visibility
|
||||
minimize: Minimize
|
||||
fullscreen: Fullscreen
|
||||
clear-all-filters: Clear all filters
|
||||
learn-more: Learn more
|
||||
@@ -30,12 +30,17 @@ titles:
|
||||
label: Label
|
||||
value: Value
|
||||
no-results: No Results
|
||||
choose-a-provider: Choose a provider
|
||||
provider: Provider
|
||||
ip-addresses: Latest IP Addresses
|
||||
descriptions:
|
||||
empty-set: There are no items to display yet. You may be able to add items or try back later.
|
||||
origin-initialization: To get started, please enter your origin URL
|
||||
create-but-not-list: You do not have permission to list {resource}, but you can create new instances.
|
||||
neither-list-nor-create: You do not have permission to list or create {resource}.
|
||||
no-results: We found no matching records.
|
||||
choose-a-provider: 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.
|
||||
provider: This is the provider for this host catalog. The format of the host set filters are specific to each provider.
|
||||
questions:
|
||||
delete-confirm: Are you sure you want to delete this resource?
|
||||
remove-confirm: Are you sure you want to remove this association?
|
||||
|
||||
@@ -118,3 +118,22 @@ callback_url:
|
||||
filter:
|
||||
label: Filter
|
||||
help: A boolean expression defining a filter run against the provided information.
|
||||
tenant_id:
|
||||
label: Tenant ID
|
||||
help: The tenant (directory) ID for your Azure Active Directory application.
|
||||
subscription_id:
|
||||
label: Subscription ID
|
||||
help: The subscription ID for the subscription with read access.
|
||||
access_key_id:
|
||||
label: Access Key ID
|
||||
help: The access key ID found on the Security Credentials page in AWS.
|
||||
secret_access_key:
|
||||
label: Secret Access Key
|
||||
help: The secret access key found on the Security Credentials page in AWS.
|
||||
region:
|
||||
label: Region
|
||||
secret:
|
||||
label: Client secret value
|
||||
help: The client secret value for the client you want Boundary to use
|
||||
disable_credential_rotation:
|
||||
label: Disable credential rotation
|
||||
@@ -78,16 +78,25 @@ 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
|
||||
help:
|
||||
static: Provide a list of hosts and host sets with static addresses
|
||||
dynamic: Automate discovery of target hosts and services on Azure or AWS
|
||||
types:
|
||||
static: Static
|
||||
unknown: Unknown
|
||||
unknown: Plugin
|
||||
aws: AWS
|
||||
azure: Azure
|
||||
dynamic: Dynamic
|
||||
form:
|
||||
azure_client_id:
|
||||
label: Client ID
|
||||
help: The client ID for the client you want Boundary to use.
|
||||
host-set:
|
||||
title: Host Set
|
||||
title_plural: Host Sets
|
||||
@@ -98,6 +107,13 @@ host-set:
|
||||
delete: Delete Host Set
|
||||
create-and-add-host: Create and Add Host
|
||||
add-hosts: Add Existing Host
|
||||
form:
|
||||
filter:
|
||||
label: Filter
|
||||
help: Create a filter to select resources using values such as tag name or tag value. Filter format is specific to each provider
|
||||
preferred_endpoints:
|
||||
label: Preferred Endpoints
|
||||
help: Selects addresses of hosts, in cidr:<valid IPv4/6 CIDR> or dns:<globbed name> format
|
||||
messages:
|
||||
welcome:
|
||||
title: Welcome to Host Sets
|
||||
@@ -112,11 +128,6 @@ host-set:
|
||||
add-none:
|
||||
title: No Hosts Available
|
||||
description: No hosts available for selection.
|
||||
types:
|
||||
static: Static
|
||||
unknown: Unknown
|
||||
aws: AWS
|
||||
azure: Azure
|
||||
host:
|
||||
title: Host
|
||||
title_plural: Hosts
|
||||
@@ -134,11 +145,6 @@ host:
|
||||
add: Add Host
|
||||
create: New Host
|
||||
delete: Delete Host
|
||||
types:
|
||||
static: Static
|
||||
unknown: Unknown
|
||||
aws: AWS
|
||||
azure: Azure
|
||||
session:
|
||||
title: Session
|
||||
title_plural: Sessions
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
border-radius: sizing.rems(xxxs);
|
||||
box-shadow: inset 0px 3px 1px rgba(var(--stark-components), var(--opacity-4));
|
||||
|
||||
&::placeholder {
|
||||
color: var(--ui-gray-subtler-1);
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: var(--failure);
|
||||
border-color: currentColor;
|
||||
|
||||
@@ -32,12 +32,12 @@ $radio-svg: (
|
||||
);
|
||||
|
||||
.rose-form-radio-card {
|
||||
$cardWideWidth: $size-m * 11;
|
||||
$cardWideWidth: $size-m * 10;
|
||||
$cardTileWidth: $size-m * 7.25;
|
||||
$borderWidth: $size-xxxs * 2;
|
||||
|
||||
&.wide {
|
||||
width: ($size-m) * 23;
|
||||
width: ($size-m) * 20;
|
||||
}
|
||||
|
||||
&.tile {
|
||||
@@ -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;
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-composable-helpers": "^5.0.0",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-composable-helpers": "^4.5.0",
|
||||
"ember-focus-trap": "^0.7.0",
|
||||
"ember-named-blocks-polyfill": "^0.2.4",
|
||||
"ember-named-blocks-polyfill": "^0.2.5",
|
||||
"ember-radio-button": "github:yapplabs/ember-radio-button.git#b2ab65f",
|
||||
"ember-uuid": "^2.1.0",
|
||||
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774"
|
||||
@@ -41,7 +41,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"@hashicorp/flight-icons": "^2.0.1",
|
||||
@@ -55,13 +55,13 @@
|
||||
"@storybook/components": "^6.3.12",
|
||||
"@storybook/core-events": "^6.3.0",
|
||||
"@storybook/ember": "^6.3.8",
|
||||
"@storybook/ember-cli-storybook": "^0.4.0",
|
||||
"@storybook/ember-cli-storybook": "^0.5.0",
|
||||
"@storybook/theming": "^6.3.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-ember-modules-api-polyfill": "^2.12.0",
|
||||
"babel-plugin-ember-modules-api-polyfill": "^3.5.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-cli": "~4.1.0",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"cz-conventional-changelog": "^3.1.0",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"git-cz": "^4.3.1",
|
||||
"license-checker": "^25.0.1"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
{{#if @model.isNew}}
|
||||
<form.fieldset>
|
||||
<:title>{{t 'form.type.label'}}</:title>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='types'
|
||||
@selectedValue={{@model.type}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.static'}}
|
||||
@value='static'
|
||||
@helperText={{t 'resources.host-catalog.help.static'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.dynamic'}}
|
||||
@value='plugin'
|
||||
@helperText={{t 'resources.host-catalog.help.dynamic'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
<Rose::Separator />
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
</form.fieldset>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.choose-a-provider'}}</:title>
|
||||
<:description>{{t 'descriptions.choose-a-provider'}}</:description>
|
||||
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value='aws'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/aws-color-16'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value='azure'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/azure-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
{{else}}
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:description>{{t 'descriptions.provider'}}</:description>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value='aws'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/aws-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
{{/if}}
|
||||
|
||||
<form.input
|
||||
@name='region'
|
||||
@type='region'
|
||||
@value={{@model.region}}
|
||||
@label={{t 'form.region.label'}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='access_key_id'
|
||||
@type='access_key_id'
|
||||
@value={{@model.access_key_id}}
|
||||
@label={{t 'form.access_key_id.label'}}
|
||||
@helperText={{t 'form.access_key_id.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='secret_access_key'
|
||||
@type='secret_access_key'
|
||||
@value={{@model.secret_access_key}}
|
||||
@label={{t 'form.secret_access_key.label'}}
|
||||
@helperText={{t 'form.secret_access_key.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.checkbox
|
||||
@name='disable_credential_rotation'
|
||||
@checked={{@model.disable_credential_rotation}}
|
||||
@label={{t 'form.disable_credential_rotation.label'}}
|
||||
@onChange={{fn this.toggleDisableCredentialRotation @model}}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,11 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class FormHostCatalogAwsComponent extends Component {
|
||||
// =actions
|
||||
|
||||
@action
|
||||
toggleDisableCredentialRotation(model) {
|
||||
model.disable_credential_rotation = !model.disable_credential_rotation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
{{#if @model.isNew}}
|
||||
<form.fieldset>
|
||||
<:title>{{t 'form.type.label'}}</:title>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='types'
|
||||
@selectedValue={{@model.type}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.static'}}
|
||||
@value='static'
|
||||
@helperText={{t 'resources.host-catalog.help.static'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.dynamic'}}
|
||||
@value='plugin'
|
||||
@helperText={{t 'resources.host-catalog.help.dynamic'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
<Rose::Separator />
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
</form.fieldset>
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.choose-a-provider'}}</:title>
|
||||
<:description>{{t 'descriptions.choose-a-provider'}}</:description>
|
||||
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value='aws'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/aws-color-16'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value='azure'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/azure-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
{{else}}
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:description>{{t 'descriptions.provider'}}</:description>
|
||||
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value='azure'
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/azure-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
{{/if}}
|
||||
|
||||
<form.input
|
||||
@name='tenant_id'
|
||||
@type='tenant_id'
|
||||
@value={{@model.tenant_id}}
|
||||
@label={{t 'form.tenant_id.label'}}
|
||||
@helperText={{t 'form.tenant_id.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
@link={{doc-url @doc}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='subscription_id'
|
||||
@type='subscription_id'
|
||||
@value={{@model.subscription_id}}
|
||||
@label={{t 'form.subscription_id.label'}}
|
||||
@helperText={{t 'form.subscription_id.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
@link={{doc-url @doc}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='client_id'
|
||||
@type='client_id'
|
||||
@value={{@model.client_id}}
|
||||
@label={{t 'resources.host-catalog.form.azure_client_id.label'}}
|
||||
@helperText={{t 'resources.host-catalog.form.azure_client_id.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
@link={{doc-url @doc}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='secret_value'
|
||||
@type='secret_value'
|
||||
@value={{@model.secret_value}}
|
||||
@label={{t 'form.secret.label'}}
|
||||
@helperText={{t 'form.secret.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
@link={{doc-url @doc}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
</Rose::Form>
|
||||
@@ -1,56 +1,8 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
{{component
|
||||
(concat 'form/host-catalog/' @model.compositeType)
|
||||
model=@model
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
changeType=@changeType
|
||||
doc=@doc
|
||||
}}
|
||||
@@ -0,0 +1,115 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
{{#if @model.isNew}}
|
||||
<form.fieldset>
|
||||
<:title>{{t 'form.type.label'}}</:title>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='types'
|
||||
@selectedValue={{@model.type}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.static'}}
|
||||
@value='static'
|
||||
@helperText={{t 'resources.host-catalog.help.static'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.dynamic'}}
|
||||
@value='plugin'
|
||||
@helperText={{t 'resources.host-catalog.help.dynamic'}}
|
||||
@layout='wide'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
{{#if @model.isPlugin}}
|
||||
<Rose::Separator />
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
</form.fieldset>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.choose-a-provider'}}</:title>
|
||||
<:description>{{t 'descriptions.choose-a-provider'}}</:description>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@changed={{@changeType}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value='aws'
|
||||
@layout='tile'
|
||||
/>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value='azure'
|
||||
@layout='tile'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,247 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:description>{{t 'descriptions.provider'}}</:description>
|
||||
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value={{@model.compositeType}}
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/aws-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'resources.host-set.form.preferred_endpoints.label'}}</:title>
|
||||
<:description>{{t
|
||||
'resources.host-set.form.preferred_endpoints.help'
|
||||
}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.preferred_endpoints}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.preferred_endpoints as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.preferred_endpoints as |endpoint i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@value={{endpoint.value}}
|
||||
@error={{@model.errors.preferred_endpoints}}
|
||||
@contextual={{true}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'preferred_endpoints' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@value={{@model.preferred_endpoint}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'preferred_endpoints'
|
||||
@model.preferred_endpoint
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'resources.host-set.form.filter.label'}}</:title>
|
||||
<:description>{{t 'resources.host-set.form.filter.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.filters}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.filters as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.filters as |filter i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@value={{filter.value}}
|
||||
@error={{@model.errors.filters}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'filters' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input @type='text' @value={{@model.filter}} />
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @addStringItem 'filters' @model.filter)}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,194 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:description>{{t 'descriptions.provider'}}</:description>
|
||||
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value={{@model.compositeType}}
|
||||
@layout='tile'
|
||||
@icon='flight-icons/svg/azure-color-16'
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'resources.host-set.form.preferred_endpoints.label'}}</:title>
|
||||
<:description>{{t
|
||||
'resources.host-set.form.preferred_endpoints.help'
|
||||
}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.preferred_endpoints}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.preferred_endpoints as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.preferred_endpoints as |endpoint i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@value={{endpoint.value}}
|
||||
@error={{@model.errors.preferred_endpoints}}
|
||||
@contextual={{true}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'preferred_endpoints' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@value={{@model.preferred_endpoint}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'preferred_endpoints'
|
||||
@model.preferred_endpoint
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
|
||||
<form.textarea
|
||||
@name='filter'
|
||||
@type='filter'
|
||||
@value={{@model.filter}}
|
||||
@label={{t 'resources.host-set.form.filter.label'}}
|
||||
@helperText={{t 'resources.host-set.form.filter.help'}}
|
||||
@linkText={{t 'form. tiltes.learn-more'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.filter}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.filter as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -1,63 +1,8 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
{{component
|
||||
(concat 'form/host-set/' @model.compositeType)
|
||||
model=@model
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
removeItemByIndex=@removeItemByIndex
|
||||
addStringItem=@addStringItem
|
||||
}}
|
||||
@@ -0,0 +1,57 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,97 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@error={{@model.errors.name}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@error={{@model.errors.description}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.aws'}}
|
||||
@value={{@model.compositeType}}
|
||||
@layout='tile'
|
||||
@icon={{concat 'flight-icons/svg/' @model.compositeType '-color-16'}}
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.ip-addresses'}}</:title>
|
||||
<:body>
|
||||
{{#each @model.ip_addresses as |ip_address|}}
|
||||
|
||||
<form.input
|
||||
@value={{ip_address}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
{{/each}}
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,97 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@error={{@model.errors.name}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@error={{@model.errors.description}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.provider'}}</:title>
|
||||
<:body>
|
||||
<form.radioGroup
|
||||
@name='provider'
|
||||
@selectedValue={{@model.compositeType}}
|
||||
@disabled={{true}}
|
||||
as |radioGroup|
|
||||
>
|
||||
<radioGroup.card
|
||||
@label={{t 'resources.host-catalog.types.azure'}}
|
||||
@value={{@model.compositeType}}
|
||||
@layout='tile'
|
||||
@icon={{concat 'flight-icons/svg/' @model.compositeType '-color-16'}}
|
||||
/>
|
||||
</form.radioGroup>
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
<form.fieldset>
|
||||
<:title>{{t 'titles.ip-addresses'}}</:title>
|
||||
<:body>
|
||||
{{#each @model.ip_addresses as |ip_address|}}
|
||||
|
||||
<form.input
|
||||
@value={{ip_address}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
{{/each}}
|
||||
</:body>
|
||||
</form.fieldset>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -1,82 +1,18 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@error={{@model.errors.name}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@error={{@model.errors.description}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.input
|
||||
@name='address'
|
||||
@type='text'
|
||||
@value={{@model.attributes.address}}
|
||||
@label={{t 'form.address.label'}}
|
||||
@error={{@model.errors.name}}
|
||||
@helperText={{t 'form.address.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
{{#if @model.compositeType}}
|
||||
{{component
|
||||
(concat 'form/host/' @model.compositeType)
|
||||
model=@model
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
}}
|
||||
{{else}}
|
||||
{{! create-and-add-host cancel route doesn't
|
||||
have a model and this else part is required to prevent
|
||||
erroring out here. This has been noted in the tech debt doc to further investigate }}
|
||||
{{component
|
||||
(concat 'form/host/' 'static')
|
||||
model=@model
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,82 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@error={{@model.errors.name}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name='description'
|
||||
@type='description'
|
||||
@value={{@model.description}}
|
||||
@label={{t 'form.description.label'}}
|
||||
@error={{@model.errors.description}}
|
||||
@helperText={{t 'form.description.help'}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.input
|
||||
@name='address'
|
||||
@type='text'
|
||||
@value={{@model.address}}
|
||||
@label={{t 'form.address.label'}}
|
||||
@error={{@model.errors.address}}
|
||||
@helperText={{t 'form.address.help'}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.address}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.address as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
@@ -34,9 +34,7 @@
|
||||
</row.cell>
|
||||
<row.cell>{{hostSet.name}}</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t
|
||||
(concat 'resources.host-set.types.' hostSet.type)
|
||||
}}</Rose::Badge>
|
||||
<HostCatalogTypeBadge @model={{hostSet}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<code>{{hostSet.host_catalog_id}}</code>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{{#if @model.isStatic}}
|
||||
<Rose::Badge>
|
||||
{{t (concat 'resources.host-catalog.types.' @model.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{else if @model.isUnknown}}
|
||||
<Rose::Badge>
|
||||
{{t (concat 'resources.host-catalog.types.' @model.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{else}}
|
||||
<Rose::Badge
|
||||
@icon={{concat 'flight-icons/svg/' @model.compositeType '-color-16'}}
|
||||
>
|
||||
{{t (concat 'resources.host-catalog.types.' @model.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Controller from '@ember/controller';
|
||||
|
||||
export default class ScopesScopeHostCatalogsNewController extends Controller {
|
||||
// =attributes
|
||||
|
||||
queryParams = ['type'];
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetRoute extends Route {
|
||||
// =methods
|
||||
@@ -49,4 +50,30 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetRoute exte
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a string item to array `property` on the passed `filter`.
|
||||
|
||||
* @param {hostSetModel} hostSet
|
||||
* @param {string} property
|
||||
* @param {string} value
|
||||
*/
|
||||
@action
|
||||
async addStringItem(hostSet, property, value) {
|
||||
const array = hostSet.get(property);
|
||||
array.addObject({ value });
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from array `property` at `index` on the
|
||||
* passed `hostSet`.
|
||||
* @param {hostSetModel} hostSet
|
||||
* @param {string} property
|
||||
* @param {number} index
|
||||
*/
|
||||
@action
|
||||
async removeItemByIndex(hostSet, property, index) {
|
||||
const array = hostSet.get(property);
|
||||
array.removeAt(index);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,22 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeHostCatalogsHostCatalogHostSetsNewRoute extends Route {
|
||||
// =methods
|
||||
// =services
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
/**
|
||||
* Creates a new unsaved host set in current host catalog scope.
|
||||
* @return {HostSetModel}
|
||||
*/
|
||||
model() {
|
||||
const { id: host_catalog_id } = this.modelFor(
|
||||
const { id: host_catalog_id, compositeType } = this.modelFor(
|
||||
'scopes.scope.host-catalogs.host-catalog'
|
||||
);
|
||||
return this.store.createRecord('host-set', {
|
||||
type: 'static',
|
||||
compositeType,
|
||||
host_catalog_id,
|
||||
});
|
||||
}
|
||||
@@ -47,4 +51,29 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsNewRoute extends
|
||||
model: model,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a string item to array `property` on the passed `filter`.
|
||||
|
||||
* @param {hostSetModel} hostSet
|
||||
* @param {string} property
|
||||
* @param {string} value
|
||||
*/
|
||||
@action
|
||||
async addStringItem(hostSet, property, value) {
|
||||
const array = hostSet.get(property);
|
||||
array.addObject({ value });
|
||||
}
|
||||
/**
|
||||
* Removes an item from array `property` at `index` on the
|
||||
* passed `hostSet`.
|
||||
* @param {hostSetModel} hostSet
|
||||
* @param {string} property
|
||||
* @param {number} index
|
||||
*/
|
||||
@action
|
||||
async removeItemByIndex(hostSet, property, index) {
|
||||
const array = hostSet.get(property);
|
||||
array.removeAt(index);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,54 @@
|
||||
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
|
||||
|
||||
/**
|
||||
* Creates a new unsaved host catalog belonging to the current scope.
|
||||
* Also rollback/destroy any new, unsaved instances from this route before
|
||||
* creating another, but reuse name/description if available.
|
||||
* @return {HostCatalogModel}
|
||||
*/
|
||||
model() {
|
||||
model({ type: compositeType = 'static' }) {
|
||||
const scopeModel = this.modelFor('scopes.scope');
|
||||
let name, description, disable_credential_rotation;
|
||||
if (this.currentModel?.isNew) {
|
||||
({ name, description } = this.currentModel);
|
||||
this.currentModel.rollbackAttributes();
|
||||
}
|
||||
if (compositeType === 'azure') {
|
||||
disable_credential_rotation = true;
|
||||
}
|
||||
return this.store.createRecord('host-catalog', {
|
||||
type: 'static',
|
||||
scopeModel,
|
||||
compositeType,
|
||||
name,
|
||||
description,
|
||||
disable_credential_rotation,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update type of host catalog
|
||||
* @param {string} type
|
||||
*/
|
||||
@action
|
||||
changeType(type) {
|
||||
if (type === 'plugin') type = 'aws';
|
||||
this.router.replaceWith({ queryParams: { type } });
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,9 +14,9 @@
|
||||
>
|
||||
{{t 'resources.host-set.actions.add-hosts'}}
|
||||
</dropdown.link>
|
||||
<dropdown.separator />
|
||||
{{/if}}
|
||||
{{#if (can 'delete model' @model)}}
|
||||
<dropdown.separator />
|
||||
<dropdown.button
|
||||
@style='danger'
|
||||
@disabled={{@model.canSave}}
|
||||
|
||||
+4
-2
@@ -8,7 +8,9 @@
|
||||
<row.headerCell>{{t 'form.name.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.type.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.id.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'titles.actions'}}</row.headerCell>
|
||||
{{#if @model.isStatic}}
|
||||
<row.headerCell>{{t 'titles.actions'}}</row.headerCell>
|
||||
{{/if}}
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
@@ -24,7 +26,7 @@
|
||||
<p>{{host.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{host.type}}</Rose::Badge>
|
||||
<HostCatalogTypeBadge @model={{host}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
|
||||
+2
@@ -2,4 +2,6 @@
|
||||
@model={{@model}}
|
||||
@submit={{route-action 'save' @model}}
|
||||
@cancel={{route-action 'cancel' @model}}
|
||||
@removeItemByIndex={{route-action 'removeItemByIndex' @model}}
|
||||
@addStringItem={{route-action 'addStringItem' @model}}
|
||||
/>
|
||||
@@ -25,21 +25,7 @@
|
||||
<p>{{hostSet.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
{{#if hostSet.isStatic}}
|
||||
<Rose::Badge>
|
||||
{{t (concat 'resources.host-set.types.' hostSet.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{else}}
|
||||
<Rose::Badge
|
||||
@icon={{concat
|
||||
'flight-icons/svg/'
|
||||
hostSet.compositeType
|
||||
'-color-16'
|
||||
}}
|
||||
>
|
||||
{{t (concat 'resources.host-set.types.' hostSet.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
<HostCatalogTypeBadge @model={{hostSet}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
|
||||
@@ -4,4 +4,6 @@
|
||||
@model={{@model}}
|
||||
@submit={{route-action 'save' @model}}
|
||||
@cancel={{route-action 'cancel' @model}}
|
||||
@removeItemByIndex={{route-action 'removeItemByIndex' @model}}
|
||||
@addStringItem={{route-action 'addStringItem' @model}}
|
||||
/>
|
||||
@@ -27,21 +27,7 @@
|
||||
<p>{{host.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
{{#if host.isStatic}}
|
||||
<Rose::Badge>
|
||||
{{t (concat 'resources.host.types.' host.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{else}}
|
||||
<Rose::Badge
|
||||
@icon={{concat
|
||||
'flight-icons/svg/'
|
||||
host.compositeType
|
||||
'-color-16'
|
||||
}}
|
||||
>
|
||||
{{t (concat 'resources.host.types.' host.compositeType)}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
<HostCatalogTypeBadge @model={{host}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@@ -53,7 +39,7 @@
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<code>{{host.attributes.address}}</code>
|
||||
<code>{{host.address}}</code>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
@@ -56,40 +56,7 @@
|
||||
<p>{{hostCatalog.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
{{#if hostCatalog.isStatic}}
|
||||
<Rose::Badge>
|
||||
{{t
|
||||
(concat
|
||||
'resources.host-catalog.types.'
|
||||
hostCatalog.compositeType
|
||||
)
|
||||
}}
|
||||
</Rose::Badge>
|
||||
{{else if hostCatalog.isUnknown}}
|
||||
<Rose::Badge>
|
||||
{{t
|
||||
(concat
|
||||
'resources.host-catalog.types.'
|
||||
hostCatalog.compositeType
|
||||
)
|
||||
}}
|
||||
</Rose::Badge>
|
||||
{{else}}
|
||||
<Rose::Badge
|
||||
@icon={{concat
|
||||
'flight-icons/svg/'
|
||||
hostCatalog.compositeType
|
||||
'-color-16'
|
||||
}}
|
||||
>
|
||||
{{t
|
||||
(concat
|
||||
'resources.host-catalog.types.'
|
||||
hostCatalog.compositeType
|
||||
)
|
||||
}}
|
||||
</Rose::Badge>
|
||||
{{/if}}
|
||||
<HostCatalogTypeBadge @model={{hostCatalog}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
@model={{@model}}
|
||||
@submit={{route-action 'save' @model}}
|
||||
@cancel={{route-action 'cancel' @model}}
|
||||
@changeType={{route-action 'changeType'}}
|
||||
@doc='host-catalog.set-up-cloud-hosts'
|
||||
/>
|
||||
</page.body>
|
||||
|
||||
|
||||
@@ -38,9 +38,7 @@
|
||||
<p>{{hostSet.model.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t
|
||||
(concat 'resources.host-set.types.' hostSet.model.type)
|
||||
}}</Rose::Badge>
|
||||
<HostCatalogTypeBadge @model={{hostSet.model}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
|
||||
@@ -53,6 +53,7 @@ module.exports = function (environment) {
|
||||
'group.add-members': '/groups/add-members',
|
||||
'host-catalog': '/host-catalogs',
|
||||
'host-catalog.new': '/host-catalogs/new',
|
||||
'host-catalog.set-up-cloud-hosts': '/host-catalog-set-up-cloud-hosts',
|
||||
'host-set': '/host-sets',
|
||||
'host-set.new': '/host-sets/new',
|
||||
'host-set.add-hosts': '/host-sets/add-hosts',
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
"posttest": "ember coverage-merge && yarn clean:coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-named-blocks-polyfill": "^0.2.4"
|
||||
"ember-named-blocks-polyfill": "^0.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/render-modifiers": "^2.0.2",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
@@ -46,7 +46,7 @@
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"clipboard": "^2.0.8",
|
||||
"core": "*",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-a11y-testing": "^4.2.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-cli": "~4.1.0",
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Canonical reference for changes, improvements, and bugfixes for Boundary Desktop.
|
||||
|
||||
## v1.4.2 [CLI 0.7.5] (2022.02.17)
|
||||
|
||||
### New
|
||||
|
||||
- Support dynamic host catalogs. ([PR](https://github.com/hashicorp/boundary-ui/pull/981))
|
||||
|
||||
## v1.4.1 [CLI 0.7.3] (2021.12.16)
|
||||
|
||||
### New
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
<code>{{host.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>{{host.attributes.address}}</row.cell>
|
||||
<row.cell>
|
||||
{{#if host.isStatic}}
|
||||
{{host.address}}
|
||||
{{else}}
|
||||
{{t 'resources.host-catalog.types.dynamic'}}
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.7.3
|
||||
0.7.5
|
||||
@@ -50,13 +50,13 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-named-blocks-polyfill": "^0.2.4"
|
||||
"ember-named-blocks-polyfill": "^0.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@doyensec/electronegativity": "^1.9.1",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/render-modifiers": "^2.0.2",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@ember/test-helpers": "^2.6.0",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
"@glimmer/tracking": "^1.0.4",
|
||||
"@playwright/test": "^1.15.0",
|
||||
@@ -67,7 +67,7 @@
|
||||
"core": "*",
|
||||
"cross-env": "^7.0.3",
|
||||
"cross-os": "^1.4.0",
|
||||
"doctoc": "^2.0.1",
|
||||
"doctoc": "^2.1.0",
|
||||
"ember-a11y-testing": "^4.2.0",
|
||||
"ember-auto-import": "^1.12.0",
|
||||
"ember-autofocus-modifier": "^2.0.0",
|
||||
|
||||
@@ -2943,10 +2943,10 @@
|
||||
ember-cli-htmlbars "^5.7.1"
|
||||
ember-destroyable-polyfill "^2.0.3"
|
||||
|
||||
"@ember/test-helpers@^2.4.2":
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-2.4.2.tgz#e5be97e316dc502d7da933461135fbcb9254726e"
|
||||
integrity sha512-++k/dXZ0IeOQLSm0Yu5QuCRe9UoptuckMhaXHY37VLb1varLHRuP8908kigVNt9c5waiocaK4jPjDBkKYRLlfA==
|
||||
"@ember/test-helpers@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-2.6.0.tgz#d687515c6ab49ba72717fc62046970ef4a72ea9c"
|
||||
integrity sha512-N5sr3layWk60wB3maCy+/5hFHQRcTh8aqxcZTSs3Od9QkuHdWBtRgMGLP/35mXpJlgWuu3xqLpt6u3dGHc8gCg==
|
||||
dependencies:
|
||||
"@ember/test-waiters" "^3.0.0"
|
||||
broccoli-debug "^0.6.5"
|
||||
@@ -4888,15 +4888,15 @@
|
||||
dependencies:
|
||||
lodash "^4.17.15"
|
||||
|
||||
"@storybook/ember-cli-storybook@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/ember-cli-storybook/-/ember-cli-storybook-0.4.0.tgz#d0d0d326fa99a19602071e91d93b0bbd907493ec"
|
||||
integrity sha512-sJyetdQRtM8tO3pjxaRt1Y1nuWRCRAp3mPLgqNS7+6Pv/bISsSgkg0bziqXq1DeDLLOZYe1kqYschaVifTy89A==
|
||||
"@storybook/ember-cli-storybook@^0.5.0":
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@storybook/ember-cli-storybook/-/ember-cli-storybook-0.5.0.tgz#b97fc212e6920871f0d6ac4348d663c335ff61b4"
|
||||
integrity sha512-TleCWq4SgtgeutdSQ2UWEEI5h37au9vX8U+LXN1dbnSBNnNpmdSa0PxXhFhJNZaMZsMq8XzAQowG+H0U7BxIeg==
|
||||
dependencies:
|
||||
broccoli-funnel "^2.0.2"
|
||||
broccoli-merge-trees "^3.0.2"
|
||||
broccoli-funnel "^3.0.8"
|
||||
broccoli-merge-trees "^4.2.0"
|
||||
cheerio "^1.0.0-rc.2"
|
||||
ember-cli-addon-docs-yuidoc "^0.2.3"
|
||||
ember-cli-addon-docs-yuidoc "^1.0.0"
|
||||
ember-cli-babel "^7.23.0"
|
||||
ember-cli-htmlbars "^5.3.1"
|
||||
|
||||
@@ -6416,11 +6416,6 @@ ansistyles@~0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539"
|
||||
integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=
|
||||
|
||||
any-promise@^1.1.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||
|
||||
anymatch@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
|
||||
@@ -6932,13 +6927,6 @@ babel-plugin-ember-data-packages-polyfill@^0.1.2:
|
||||
dependencies:
|
||||
"@ember-data/rfc395-data" "^0.0.4"
|
||||
|
||||
babel-plugin-ember-modules-api-polyfill@^2.12.0:
|
||||
version "2.13.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.13.4.tgz#cf62bc9bfd808c48d810d5194f4329e9453bd603"
|
||||
integrity sha512-uxQPkEQAzCYdwhZk16O9m1R4xtCRNy4oEUTBrccOPfzlIahRZJic/JeP/ZEL0BC6Mfq6r55eOg6gMF/zdFoCvA==
|
||||
dependencies:
|
||||
ember-rfc176-data "^0.3.13"
|
||||
|
||||
babel-plugin-ember-modules-api-polyfill@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-3.5.0.tgz#27b6087fac75661f779f32e60f94b14d0e9f6965"
|
||||
@@ -10105,10 +10093,10 @@ dir-glob@^3.0.1:
|
||||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
doctoc@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/doctoc/-/doctoc-2.0.1.tgz#d5aee2bce65a438ff8717d9e51df3d540caa3b78"
|
||||
integrity sha512-JsxnSVZtLCThKehjFPBDhP1+ZLmdfXQynZH/0ABAwrnd1Zf3AV6LigC9oWJyaZ+c6RXCDnlGUNJ7I+1v8VaaRg==
|
||||
doctoc@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/doctoc/-/doctoc-2.1.0.tgz#e7cbcd1f9e65519c295461423b2e7195d9e0d7ab"
|
||||
integrity sha512-0darEVEuWKLyIlpGOzE5cILf/pgUu25qUs6YwCqLqfxb8+3b9Cl4iakA8vwYrBQOkJ5SwpHKEPVMu2KOMrTA7A==
|
||||
dependencies:
|
||||
"@textlint/markdown-to-ast" "~6.1.7"
|
||||
anchor-markdown-header "~0.5.7"
|
||||
@@ -10555,16 +10543,17 @@ ember-can@^3.1.0:
|
||||
ember-cli-htmlbars "^4.2.1"
|
||||
ember-inflector "^3.0.1"
|
||||
|
||||
ember-cli-addon-docs-yuidoc@^0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-addon-docs-yuidoc/-/ember-cli-addon-docs-yuidoc-0.2.4.tgz#dd8f5cf4982e8492b255fb677e9d771925e27dce"
|
||||
integrity sha512-asyGxagV+VKK+edc5iOW8JI8Css/d8mEE7ndWKqYa8Ub4eFwVfI6SLr9gHZc8f7q9BK+M5a/RSWHSnTTL5/3Zw==
|
||||
ember-cli-addon-docs-yuidoc@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-addon-docs-yuidoc/-/ember-cli-addon-docs-yuidoc-1.0.0.tgz#0bc750c3950d77fbcce645855063013b295ee6be"
|
||||
integrity sha512-q7tNVbD4niPgXEQ1Exfeh7Mfiwi3sbT5IG8vXgAumpJgATouTJrk3MGeZjInR7x6CV0AKDiExF/BdMwAshTmrg==
|
||||
dependencies:
|
||||
broccoli-caching-writer "^3.0.3"
|
||||
ember-cli-babel "^7.7.3"
|
||||
fs-extra "^5.0.0"
|
||||
json-api-serializer "^1.11.0"
|
||||
lodash "^4.17.5"
|
||||
ember-cli-babel "^7.22.1"
|
||||
ember-cli-htmlbars "^5.3.1"
|
||||
fs-extra "^9.0.1"
|
||||
json-api-serializer "^2.6.0"
|
||||
lodash "^4.17.20"
|
||||
yuidocjs "^0.10.2"
|
||||
|
||||
ember-cli-app-version@^5.0.0:
|
||||
@@ -11056,10 +11045,10 @@ ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2, ember-co
|
||||
fs-extra "^9.1.0"
|
||||
semver "^5.4.1"
|
||||
|
||||
ember-composable-helpers@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-composable-helpers/-/ember-composable-helpers-4.5.0.tgz#94febbdf4348e64f45f7a6f993f326e32540a61e"
|
||||
integrity sha512-XjpDLyVPsLCy6kd5dIxZonOECCO6AA5sY5Hr6tYUbJg3s5ghFAiFWaNcYraYC+fL2yPJQAswwpfwGlQORUJZkw==
|
||||
ember-composable-helpers@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-composable-helpers/-/ember-composable-helpers-5.0.0.tgz#055bab3a3e234ab2917499b1465e968c253ca885"
|
||||
integrity sha512-gyUrjiSju4QwNrsCLbBpP0FL6VDFZaELNW7Kbcp60xXhjvNjncYgzm4zzYXhT+i1lLA6WEgRZ3lOGgyBORYD0w==
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
broccoli-funnel "2.0.1"
|
||||
@@ -11389,10 +11378,10 @@ ember-modifier@^2.1.1, ember-modifier@^2.1.2:
|
||||
ember-destroyable-polyfill "^2.0.2"
|
||||
ember-modifier-manager-polyfill "^1.2.0"
|
||||
|
||||
ember-named-blocks-polyfill@^0.2.4:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/ember-named-blocks-polyfill/-/ember-named-blocks-polyfill-0.2.4.tgz#f5f30711ee89244927b55aae7fa9630edaadc974"
|
||||
integrity sha512-PsohC7ejjS7V++6i/JSy0pl1hXLV3IS3Qs+O7SrjIPYcg1UEmUwqgPiDmXqNgy0p2dc5TK5bIJTtX8wofCI63Q==
|
||||
ember-named-blocks-polyfill@^0.2.5:
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/ember-named-blocks-polyfill/-/ember-named-blocks-polyfill-0.2.5.tgz#d5841406277026a221f479c815cfbac6cdcaeecb"
|
||||
integrity sha512-OVMxzkfqJrEvmiky7gFzmuTaImCGm7DOudHWTdMBPO7E+dQSunrcRsJMgO9ZZ56suqBIz/yXbEURrmGS+avHxA==
|
||||
dependencies:
|
||||
ember-cli-babel "^7.19.0"
|
||||
ember-cli-version-checker "^5.1.1"
|
||||
@@ -11454,7 +11443,7 @@ ember-resolver@^8.0.3:
|
||||
ember-cli-version-checker "^5.1.2"
|
||||
resolve "^1.20.0"
|
||||
|
||||
ember-rfc176-data@^0.3.13, ember-rfc176-data@^0.3.15, ember-rfc176-data@^0.3.17:
|
||||
ember-rfc176-data@^0.3.15, ember-rfc176-data@^0.3.17:
|
||||
version "0.3.17"
|
||||
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.17.tgz#d4fc6c33abd6ef7b3440c107a28e04417b49860a"
|
||||
integrity sha512-EVzTTKqxv9FZbEh6Ktw56YyWRAA0MijKvl7H8C06wVF+8f/cRRz3dXxa4nkwjzyVwx4rzKGuIGq77hxJAQhWWw==
|
||||
@@ -14387,7 +14376,7 @@ hmac-drbg@^1.0.1:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoek@2.x.x, hoek@4.x.x, hoek@6.x.x, hoek@~4.2.0:
|
||||
hoek@2.x.x, hoek@6.x.x, hoek@~4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
|
||||
integrity sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==
|
||||
@@ -15547,13 +15536,6 @@ isbinaryfile@^4.0.8:
|
||||
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf"
|
||||
integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==
|
||||
|
||||
isemail@3.x.x:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c"
|
||||
integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==
|
||||
dependencies:
|
||||
punycode "2.x.x"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -16193,15 +16175,6 @@ jest@^27.4.7:
|
||||
import-local "^3.0.2"
|
||||
jest-cli "^27.4.7"
|
||||
|
||||
joi@^12.0.0:
|
||||
version "12.0.0"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-12.0.0.tgz#46f55e68f4d9628f01bbb695902c8b307ad8d33a"
|
||||
integrity sha512-z0FNlV4NGgjQN1fdtHYXf5kmgludM65fG/JlXzU6+rwkt9U5UWuXVYnXa2FpK0u6+qBuCmrm5byPNuiiddAHvQ==
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
isemail "3.x.x"
|
||||
topo "2.x.x"
|
||||
|
||||
jpeg-js@^0.4.2:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b"
|
||||
@@ -16355,17 +16328,12 @@ jsesc@~0.5.0:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
|
||||
|
||||
json-api-serializer@^1.11.0:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/json-api-serializer/-/json-api-serializer-1.15.1.tgz#241ea66dfc5c629ae46d8315c6ee4232b81bb6b7"
|
||||
integrity sha512-dp7d/TLWudViXADFnmdiq80krYZ+zA0WeB1771O1Is8HWdeySZofhp/TPWHCzgFPmGkgwI7oTEgjgZ6Dcxr/2w==
|
||||
json-api-serializer@^2.6.0:
|
||||
version "2.6.6"
|
||||
resolved "https://registry.yarnpkg.com/json-api-serializer/-/json-api-serializer-2.6.6.tgz#fa5d283b913e0ea25653f4d04f981dc44d66dd4f"
|
||||
integrity sha512-l7/e2O5/0+GU38RTMowRUKxRlT8zFc1oryAYBxqK54sFZnvJOJI2bo4XbbxnkTtvSzwkyv5DoBUuFm0hvG3avg==
|
||||
dependencies:
|
||||
into-stream "^3.1.0"
|
||||
joi "^12.0.0"
|
||||
lodash "^4.5.1"
|
||||
stream-to-array "^2.3.0"
|
||||
through2 "^2.0.3"
|
||||
unique-stream "^2.2.1"
|
||||
setimmediate "^1.0.5"
|
||||
|
||||
json-buffer@3.0.0:
|
||||
version "3.0.0"
|
||||
@@ -17296,7 +17264,7 @@ lodash.without@~4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
|
||||
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
|
||||
|
||||
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1, lodash@^4.7.0, lodash@~4.17.10:
|
||||
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1, lodash@^4.7.0, lodash@~4.17.10:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
@@ -20269,16 +20237,16 @@ punycode@1.3.2:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
||||
|
||||
punycode@2.x.x, punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
punycode@^1.2.4, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
pupa@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
|
||||
@@ -21885,7 +21853,7 @@ set-value@^2.0.0, set-value@^2.0.1, set-value@^4.0.1:
|
||||
is-plain-object "^2.0.4"
|
||||
is-primitive "^3.0.1"
|
||||
|
||||
setimmediate@^1.0.4:
|
||||
setimmediate@^1.0.4, setimmediate@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
||||
@@ -22509,13 +22477,6 @@ stream-shift@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
|
||||
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
|
||||
|
||||
stream-to-array@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353"
|
||||
integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=
|
||||
dependencies:
|
||||
any-promise "^1.1.0"
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
@@ -23256,15 +23217,7 @@ throttleit@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf"
|
||||
integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8=
|
||||
|
||||
through2-filter@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
|
||||
integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
|
||||
dependencies:
|
||||
through2 "~2.0.0"
|
||||
xtend "~4.0.0"
|
||||
|
||||
through2@^2.0.0, through2@^2.0.3, through2@~2.0.0:
|
||||
through2@^2.0.0:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
|
||||
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
|
||||
@@ -23445,13 +23398,6 @@ toidentifier@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
topo@2.x.x:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
||||
integrity sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
tough-cookie@^4.0.0, tough-cookie@~2.2.0, tough-cookie@~2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
|
||||
@@ -23837,14 +23783,6 @@ unique-slug@^2.0.0:
|
||||
dependencies:
|
||||
imurmurhash "^0.1.4"
|
||||
|
||||
unique-stream@^2.2.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
|
||||
integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
|
||||
dependencies:
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
through2-filter "^3.0.0"
|
||||
|
||||
unique-string@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
|
||||
@@ -24847,7 +24785,7 @@ xmlhttprequest-ssl@^1.6.2:
|
||||
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"
|
||||
integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==
|
||||
|
||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
|
||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
Reference in new issue
Block a user