1 parent
9b403b3159
commit
6397cd80a6
22 files changed
+531
-405
No files matched your search
@@ -81,7 +81,7 @@ export default class GeneratedCredentialLibraryModel extends BaseModel {
|
||||
})
|
||||
credential_type;
|
||||
|
||||
@attr('object', {
|
||||
@attr('object-as-array', {
|
||||
for: 'vault-generic',
|
||||
description: 'It indicates the credential mapping overrides.',
|
||||
})
|
||||
|
||||
@@ -13,15 +13,12 @@ export const options = {
|
||||
key_type: ['ed25519', 'ecdsa', 'rsa'],
|
||||
credential_types: ['ssh_private_key', 'username_password'],
|
||||
mapping_overrides: {
|
||||
username_password: {
|
||||
username_attribute: 'Username',
|
||||
password_attribute: 'Password',
|
||||
},
|
||||
ssh_private_key: {
|
||||
private_key_attribute: 'Private Key',
|
||||
private_key_passphrase_attribute: 'Private Key Passphrase',
|
||||
username_attribute: 'Username',
|
||||
},
|
||||
username_password: ['username_attribute', 'password_attribute'],
|
||||
ssh_private_key: [
|
||||
'private_key_attribute',
|
||||
'private_key_passphrase_attribute',
|
||||
'username_attribute',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -32,32 +32,9 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer {
|
||||
return super.serialize(...arguments);
|
||||
}
|
||||
}
|
||||
serializeAttribute(snapshot, json) {
|
||||
const value = super.serializeAttribute(...arguments);
|
||||
const { credential_type, type, credential_mapping_overrides, isNew } =
|
||||
snapshot.record;
|
||||
if (
|
||||
type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC &&
|
||||
credential_mapping_overrides &&
|
||||
credential_type &&
|
||||
!isNew
|
||||
) {
|
||||
// API expects to send null to fields if it is undefined or deleted
|
||||
json.credential_mapping_overrides = Object.keys(
|
||||
options.mapping_overrides[credential_type],
|
||||
).reduce((obj, key) => {
|
||||
if (credential_mapping_overrides[key]) {
|
||||
obj[key] = credential_mapping_overrides[key];
|
||||
} else {
|
||||
obj[key] = null;
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
serializeVaultGeneric() {
|
||||
serializeVaultGeneric(snapshot) {
|
||||
const { isNew } = snapshot;
|
||||
const serialized = super.serialize(...arguments);
|
||||
|
||||
if (serialized.attributes) {
|
||||
@@ -66,7 +43,22 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer {
|
||||
if (!serialized.attributes?.http_method?.match(/post/i)) {
|
||||
serialized.attributes.http_request_body = null;
|
||||
}
|
||||
const { credential_type, credential_mapping_overrides } = serialized;
|
||||
|
||||
// API expects to send null to fields if it is undefined or deleted
|
||||
if (credential_mapping_overrides && !isNew) {
|
||||
serialized.credential_mapping_overrides = options.mapping_overrides[
|
||||
credential_type
|
||||
].reduce((obj, key) => {
|
||||
if (credential_mapping_overrides[key]) {
|
||||
obj[key] = credential_mapping_overrides[key];
|
||||
} else {
|
||||
obj[key] = null;
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@ export default class AccountValueMapArrayTransform extends Transform {
|
||||
deserialize(serialized) {
|
||||
const accountValues = serialized || [];
|
||||
return accountValues.map((accountValueString) => ({
|
||||
from: accountValueString.split('=')[0],
|
||||
to: accountValueString.split('=')[1],
|
||||
key: accountValueString.split('=')[0],
|
||||
value: accountValueString.split('=')[1],
|
||||
}));
|
||||
}
|
||||
|
||||
serialize(deserialized) {
|
||||
const accountValues = deserialized || [];
|
||||
return accountValues.map(({ from, to }) => `${from}=${to}`);
|
||||
return accountValues.map(({ key, value }) => `${key}=${value}`);
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ module('Unit | Serializer | application', function (hooks) {
|
||||
type: TYPE_AUTH_METHOD_OIDC, //has both string and array `for` option
|
||||
name: 'OIDC Auth Method',
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
account_claim_maps: [{ key: 'foo', value: 'bar' }],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
|
||||
@@ -45,7 +45,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
name: 'OIDC Auth Method',
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
account_claim_maps: [{ key: 'foo', value: 'bar' }],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
@@ -96,7 +96,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
name: 'LDAP Auth Method',
|
||||
state: 'baz',
|
||||
account_attribute_maps: [{ from: 'foo', to: 'bar' }],
|
||||
account_attribute_maps: [{ key: 'foo', value: 'bar' }],
|
||||
urls: [{ value: 'ldap://ldap.example.com' }],
|
||||
use_token_groups: false,
|
||||
start_tls: true,
|
||||
@@ -160,7 +160,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
name: 'OIDC Auth Method',
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
account_claim_maps: [{ key: 'foo', value: 'bar' }],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
@@ -210,7 +210,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
name: 'LDAP Auth Method',
|
||||
state: 'baz',
|
||||
account_attribute_maps: [{ from: 'foo', to: 'bar' }],
|
||||
account_attribute_maps: [{ key: 'foo', value: 'bar' }],
|
||||
urls: [{ value: 'ldap://ldap.example.com' }],
|
||||
use_token_groups: false,
|
||||
start_tls: true,
|
||||
@@ -410,8 +410,8 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
prompts,
|
||||
} = record;
|
||||
assert.deepEqual(account_claim_maps, [
|
||||
{ from: 'from', to: 'to' },
|
||||
{ from: 'foo', to: 'bar' },
|
||||
{ key: 'from', value: 'to' },
|
||||
{ key: 'foo', value: 'bar' },
|
||||
]);
|
||||
assert.deepEqual(claims_scopes, [{ value: 'profile' }, { value: 'email' }]);
|
||||
assert.deepEqual(allowed_audiences, [
|
||||
@@ -481,8 +481,8 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
certificates: recordCertificates,
|
||||
} = record;
|
||||
assert.deepEqual(account_attribute_maps, [
|
||||
{ from: 'from', to: 'to' },
|
||||
{ from: 'foo', to: 'bar' },
|
||||
{ key: 'from', value: 'to' },
|
||||
{ key: 'foo', value: 'bar' },
|
||||
]);
|
||||
assert.deepEqual(urls, [{ value: ldapUrl }]);
|
||||
assert.deepEqual(recordCertificates, [
|
||||
|
||||
@@ -24,7 +24,9 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
http_method: 'GET',
|
||||
version: 1,
|
||||
credential_type: 'ssh_private_key',
|
||||
credential_mapping_overrides: { username_attribute: 'user' },
|
||||
credential_mapping_overrides: [
|
||||
{ key: 'username_attribute', value: 'user' },
|
||||
],
|
||||
});
|
||||
const snapshot = record._createSnapshot();
|
||||
const serializedRecord = serializer.serialize(snapshot);
|
||||
@@ -61,7 +63,9 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
http_method: 'GET',
|
||||
version: 1,
|
||||
credential_type: 'ssh_private_key',
|
||||
credential_mapping_overrides: {},
|
||||
credential_mapping_overrides: [
|
||||
{ key: 'private_key_attribute', value: 'test' },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -75,7 +79,7 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
description: 'Description',
|
||||
credential_type: 'ssh_private_key',
|
||||
credential_mapping_overrides: {
|
||||
private_key_attribute: null,
|
||||
private_key_attribute: 'test',
|
||||
private_key_passphrase_attribute: null,
|
||||
username_attribute: null,
|
||||
},
|
||||
@@ -116,7 +120,7 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
name: null,
|
||||
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||
credential_type: null,
|
||||
credential_mapping_overrides: {},
|
||||
credential_mapping_overrides: null,
|
||||
});
|
||||
assert.deepEqual(serializedVaultSSHCertificateRecord, {
|
||||
attributes: {
|
||||
@@ -157,7 +161,7 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
name: null,
|
||||
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||
credential_type: null,
|
||||
credential_mapping_overrides: {},
|
||||
credential_mapping_overrides: null,
|
||||
},
|
||||
'http_request_body attribute is not expected',
|
||||
);
|
||||
@@ -177,7 +181,7 @@ module('Unit | Serializer | credential library', function (hooks) {
|
||||
name: null,
|
||||
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||
credential_type: null,
|
||||
credential_mapping_overrides: {},
|
||||
credential_mapping_overrides: null,
|
||||
},
|
||||
'http_request_body attribute is expected',
|
||||
);
|
||||
|
||||
@@ -13,16 +13,16 @@ module('Unit | Transform | account value map array', function (hooks) {
|
||||
const transform = this.owner.lookup('transform:account-value-map-array');
|
||||
const deserialized = transform.deserialize(['oid=sub', 'full_name=name']);
|
||||
assert.deepEqual(deserialized, [
|
||||
{ from: 'oid', to: 'sub' },
|
||||
{ from: 'full_name', to: 'name' },
|
||||
{ key: 'oid', value: 'sub' },
|
||||
{ key: 'full_name', value: 'name' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('it serializes an array of account claims', function (assert) {
|
||||
const transform = this.owner.lookup('transform:account-value-map-array');
|
||||
const serialized = transform.serialize([
|
||||
{ from: 'oid', to: 'sub' },
|
||||
{ from: 'full_name', to: 'name' },
|
||||
{ key: 'oid', value: 'sub' },
|
||||
{ key: 'full_name', value: 'name' },
|
||||
]);
|
||||
assert.deepEqual(serialized, ['oid=sub', 'full_name=name']);
|
||||
});
|
||||
|
||||
@@ -382,124 +382,45 @@
|
||||
}}</F.HelperText>
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
<Hds::Form::Fieldset @isOptional={{true}} as |F|>
|
||||
<F.Legend>{{t
|
||||
'resources.auth-method.form.account_attribute_maps.label'
|
||||
}}</F.Legend>
|
||||
<F.HelperText>{{t
|
||||
'resources.auth-method.form.account_attribute_maps.help'
|
||||
}}</F.HelperText>
|
||||
{{#let (unique-id) (unique-id) as |fromHeaderID toHeaderID|}}
|
||||
<F.Control>
|
||||
<Hds::Table class='list-wrapper-field' name='account_attribute_maps'>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{fromHeaderID}}>{{t
|
||||
'resources.auth-method.titles.from-attr'
|
||||
}}</H.Th>
|
||||
<H.Th id={{toHeaderID}}>{{t
|
||||
'resources.auth-method.titles.to-attr'
|
||||
}}</H.Th>
|
||||
<H.Th>{{t 'titles.actions'}}</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
<:body as |B|>
|
||||
{{#each @model.account_attribute_maps as |attrMap i|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{attrMap.from}}
|
||||
@type='text'
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{fromHeaderID}}
|
||||
{{on 'input' (set-from-event attrMap 'from')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Form::Select::Field
|
||||
@value={{attrMap.to}}
|
||||
@width='100%'
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{toHeaderID}}
|
||||
{{on 'change' (set-from-event attrMap 'to')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Options>
|
||||
{{#each this.toAttributes as |toAttrOption|}}
|
||||
<option
|
||||
value={{toAttrOption}}
|
||||
selected={{eq toAttrOption attrMap.to}}
|
||||
>{{toAttrOption}}</option>
|
||||
{{/each}}
|
||||
</F.Options>
|
||||
</Hds::Form::Select::Field>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{form.disabled}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'account_attribute_maps' i)
|
||||
}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newFromAttribute}}
|
||||
@type='text'
|
||||
@isOptional={{true}}
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{fromHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newFromAttribute')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Form::Select::Field
|
||||
@value={{this.newToAttribute}}
|
||||
@width='100%'
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{toHeaderID}}
|
||||
{{on 'change' (set-from-event this 'newToAttribute')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Options>
|
||||
{{#each this.toAttributes as |toAttrOption|}}
|
||||
<option
|
||||
value={{toAttrOption}}
|
||||
selected={{eq toAttrOption this.newToAttribute}}
|
||||
>{{toAttrOption}}</option>
|
||||
{{/each}}
|
||||
</F.Options>
|
||||
</Hds::Form::Select::Field>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
disabled={{or form.disabled (not this.newFromAttribute)}}
|
||||
{{on 'click' this.addAttributeMap}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
</F.Control>
|
||||
{{/let}}
|
||||
{{#if @model.errors.account_attribute_maps}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.account_attribute_maps as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Fieldset>
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.auth-method.form.account_attribute_maps.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.auth-method.form.account_attribute_maps.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.account_attribute_maps}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.account_attribute_maps as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@name='account_attribute_maps'
|
||||
@options={{@model.account_attribute_maps}}
|
||||
@model={{@model}}
|
||||
@keyLabel={{t 'form.from_claim.label'}}
|
||||
@valueLabel={{t 'form.to_claim.label'}}
|
||||
@width='100%'
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.select @selectOptions={{this.toAttributes}} />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
<div class='ldap-section'>
|
||||
<p class='hds-typography-display-300 hds-font-weight-bold'>{{t
|
||||
|
||||
@@ -247,138 +247,45 @@
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{! Account Claim Maps }}
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'form.account_claim_maps.label'}}</:title>
|
||||
<:description>{{t 'form.account_claim_maps.help'}}</:description>
|
||||
<:body>
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'form.account_claim_maps.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'form.account_claim_maps.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.account_claim_maps}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.account_claim_maps as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t 'form.from_claim.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.to_claim.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'titles.actions'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.account_claim_maps as |claimMap i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='from_claim'
|
||||
@value={{claimMap.from}}
|
||||
@error={{@model.errors.account_claim_maps}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.label>{{t 'form.from_claim.label'}}</field.label>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
|
||||
<Hds::Form::Select::Field
|
||||
@value={{claimMap.to}}
|
||||
@isInvalid={{@model.errors.account_claim_maps}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' (set-from-event claimMap 'to')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label class='sr-only'>{{t 'form.to_claim.label'}}</F.Label>
|
||||
<F.Options>
|
||||
{{#each this.toClaims as |toClaimOption|}}
|
||||
<option
|
||||
value={{toClaimOption}}
|
||||
selected={{eq toClaimOption claimMap.to}}
|
||||
>{{toClaimOption}}</option>
|
||||
{{/each}}
|
||||
</F.Options>
|
||||
</Hds::Form::Select::Field>
|
||||
|
||||
</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 'account_claim_maps' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='from_claim'
|
||||
@value={{this.newFromClaim}}
|
||||
@label={{t 'resources.auth-method.titles.new-from-claim'}}
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
|
||||
<Hds::Form::Select::Field
|
||||
@value={{this.newToClaim}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' (set-from-event this 'newToClaim')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label class='sr-only'>{{t
|
||||
'resources.auth-method.titles.new-to-claim'
|
||||
}}</F.Label>
|
||||
<F.Options>
|
||||
{{#each this.toClaims as |toClaimOption|}}
|
||||
<option
|
||||
value={{toClaimOption}}
|
||||
selected={{eq toClaimOption this.newToClaim}}
|
||||
>{{toClaimOption}}</option>
|
||||
{{/each}}
|
||||
</F.Options>
|
||||
</Hds::Form::Select::Field>
|
||||
|
||||
</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
|
||||
@addAccountMapItem
|
||||
'account_claim_maps'
|
||||
this.newFromClaim
|
||||
this.newToClaim
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@name='account_claim_maps'
|
||||
@options={{@model.account_claim_maps}}
|
||||
@model={{@model}}
|
||||
@keyLabel={{t 'form.from_claim.label'}}
|
||||
@valueLabel={{t 'form.to_claim.label'}}
|
||||
@width='100%'
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.select @selectOptions={{this.toClaims}} />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{! Certificates }}
|
||||
<Form::Field::ListWrapper
|
||||
|
||||
@@ -169,14 +169,23 @@
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.SelectText
|
||||
<F.KeyValue
|
||||
@name='credential_mapping_overrides'
|
||||
@selectOptions={{this.mappingOverrides}}
|
||||
@model={{@model}}
|
||||
@disabled={{form.disabled}}
|
||||
@removeDuplicates={{true}}
|
||||
@width='400px'
|
||||
/>
|
||||
@width='100%'
|
||||
@showNewRow={{this.showNewRow}}
|
||||
>
|
||||
<:newKey as |N|>
|
||||
<N.select @selectOptions={{this.selectOptions}} />
|
||||
</:newKey>
|
||||
<:key as |K|>
|
||||
<K.select @selectOptions={{this.mappingOverrides}} />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
{{/if}}
|
||||
|
||||
@@ -17,6 +17,7 @@ export default class FormCredentialLibraryVaultGenericComponent extends Componen
|
||||
httpMethodOptions = options.http_method;
|
||||
|
||||
credentialTypes = options.credential_types;
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
@@ -35,12 +36,46 @@ export default class FormCredentialLibraryVaultGenericComponent extends Componen
|
||||
return options.mapping_overrides[this.args.model.credential_type];
|
||||
}
|
||||
|
||||
get allowedEntries() {
|
||||
return this.mappingOverrides.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the previously selected key value pair when toggling between credential types on a new form
|
||||
*/
|
||||
@action
|
||||
selectCredentialType({ target: { value } }) {
|
||||
this.args.model.credential_mapping_overrides = {};
|
||||
this.args.model.credential_mapping_overrides = [];
|
||||
this.args.model.credential_type = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents users from selecting duplicate keys from the select list if the arg is set to true
|
||||
* @type {array}
|
||||
*/
|
||||
|
||||
get selectOptions() {
|
||||
const previouslySelectedKeys =
|
||||
this.args.model.credential_mapping_overrides || [];
|
||||
if (previouslySelectedKeys.length) {
|
||||
return this.mappingOverrides.filter((key) =>
|
||||
previouslySelectedKeys.every((obj) => obj.key !== key),
|
||||
);
|
||||
} else {
|
||||
return this.mappingOverrides;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if we need to show an empty row to the users to enter more key/value pairs based on removeDuplicates arg,
|
||||
* by default it is true
|
||||
* @type {object}
|
||||
*/
|
||||
@action
|
||||
showNewRow() {
|
||||
return (
|
||||
this.args.model.credential_mapping_overrides?.length !==
|
||||
this.allowedEntries
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,14 @@
|
||||
@options={{@model.critical_options}}
|
||||
@model={{@model}}
|
||||
@disabled={{form.disabled}}
|
||||
/>
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |K|>
|
||||
<K.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
@@ -297,7 +304,14 @@
|
||||
@name='extensions'
|
||||
@options={{@model.extensions}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
'form/field/list-wrapper/textarea' disabled=@disabled
|
||||
)
|
||||
Select=(component 'form/field/list-wrapper/select' disabled=@disabled)
|
||||
SelectText=(component
|
||||
'form/field/list-wrapper/select-text' disabled=@disabled
|
||||
)
|
||||
)
|
||||
to='field'
|
||||
}}
|
||||
|
||||
@@ -2,16 +2,26 @@
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
{{#let (unique-id) (unique-id) as |keyHeaderID valueHeaderID|}}
|
||||
|
||||
{{#let (unique-id) (unique-id) as |keyHeaderID valueHeaderID|}}
|
||||
<Hds::Table class='list-wrapper-field' name={{@name}}>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{keyHeaderID}}>{{t 'form.key.label'}}</H.Th>
|
||||
<H.Th id={{valueHeaderID}}>{{t 'form.value.label'}}</H.Th>
|
||||
<H.Th id={{keyHeaderID}}>
|
||||
{{#if @keyLabel}}
|
||||
{{@keyLabel}}
|
||||
{{else}}
|
||||
{{t 'form.key.label'}}
|
||||
{{/if}}</H.Th>
|
||||
<H.Th id={{valueHeaderID}}>
|
||||
{{#if @valueLabel}}
|
||||
{{@valueLabel}}
|
||||
{{else}}
|
||||
{{t 'form.value.label'}}
|
||||
{{/if}}
|
||||
</H.Th>
|
||||
<H.Th>
|
||||
{{t 'titles.actions'}}
|
||||
|
||||
</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
@@ -19,23 +29,49 @@
|
||||
{{#each this.options as |option index|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.key}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event option 'key')}}
|
||||
/>
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=option.key
|
||||
ariaLabel=keyHeaderID
|
||||
setContext=(set-from-event option 'key')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=option.key
|
||||
ariaLabel=keyHeaderID
|
||||
setContext=(set-from-event option 'key')
|
||||
width=@width
|
||||
)
|
||||
)
|
||||
to='key'
|
||||
}}
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.value}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event option 'value')}}
|
||||
/>
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=option.value
|
||||
ariaLabel=valueHeaderID
|
||||
setContext=(set-from-event option 'value')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=option.value
|
||||
ariaLabel=valueHeaderID
|
||||
width=@width
|
||||
setContext=(set-from-event option 'value')
|
||||
)
|
||||
)
|
||||
to='value'
|
||||
}}
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
@@ -53,40 +89,114 @@
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
{{#if this.showNewRow}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{#if (has-block 'newKey')}}
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=this.newOptionKey
|
||||
ariaLabel=keyHeaderID
|
||||
setContext=(set-from-event this 'newOptionKey')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=this.newOptionKey
|
||||
ariaLabel=keyHeaderID
|
||||
width=@width
|
||||
setContext=(set-from-event this 'newOptionKey')
|
||||
)
|
||||
)
|
||||
to='newKey'
|
||||
}}
|
||||
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionKey}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionKey')}}
|
||||
/>
|
||||
</B.Td>
|
||||
{{else}}
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=this.newOptionKey
|
||||
ariaLabel=keyHeaderID
|
||||
setContext=(set-from-event this 'newOptionKey')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=this.newOptionKey
|
||||
ariaLabel=keyHeaderID
|
||||
width=@width
|
||||
setContext=(set-from-event this 'newOptionKey')
|
||||
)
|
||||
)
|
||||
to='key'
|
||||
}}
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionValue}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionValue')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
{{#if (has-block 'newValue')}}
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=this.newOptionValue
|
||||
ariaLabel=valueHeaderID
|
||||
setContext=(set-from-event this 'newOptionValue')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=this.newOptionValue
|
||||
ariaLabel=valueHeaderID
|
||||
width=@width
|
||||
setContext=(set-from-event this 'newOptionValue')
|
||||
)
|
||||
)
|
||||
to='newValue'
|
||||
}}
|
||||
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionKey)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{else}}
|
||||
{{yield
|
||||
(hash
|
||||
text=(component
|
||||
'form/field/list-wrapper/key-value/text'
|
||||
disabled=@disabled
|
||||
value=this.newOptionValue
|
||||
ariaLabel=valueHeaderID
|
||||
setContext=(set-from-event this 'newOptionValue')
|
||||
)
|
||||
select=(component
|
||||
'form/field/list-wrapper/key-value/select'
|
||||
disabled=@disabled
|
||||
value=this.newOptionValue
|
||||
ariaLabel=valueHeaderID
|
||||
width=@width
|
||||
setContext=(set-from-event this 'newOptionValue')
|
||||
)
|
||||
)
|
||||
to='value'
|
||||
}}
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionKey)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/if}}
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
|
||||
{{/let}}
|
||||
@@ -29,6 +29,20 @@ export default class MappingListComponent extends Component {
|
||||
get options() {
|
||||
return this.args?.options || this.args?.model?.[this.args.name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if we need to show an empty row to the users to enter more key/value pairs based on removeDuplicates arg,
|
||||
* by default it is true
|
||||
* @type {object}
|
||||
*/
|
||||
get showNewRow() {
|
||||
if (this.args.showNewRow) {
|
||||
return this.args.showNewRow();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
@@ -49,6 +63,7 @@ export default class MappingListComponent extends Component {
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const existingArray = this.args.model[field] ?? [];
|
||||
|
||||
const newArray = [
|
||||
...existingArray,
|
||||
{ key: this.newOptionKey, value: this.newOptionValue },
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<Hds::Form::Select::Base
|
||||
@value={{@value}}
|
||||
@width={{@width}}
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{@ariaLabel}}
|
||||
{{on 'change' @setContext}}
|
||||
as |F|
|
||||
>
|
||||
<F.Options>
|
||||
<option hidden selected value=''>
|
||||
{{t 'titles.choose-an-option'}}
|
||||
</option>
|
||||
{{#each @selectOptions as |selectOption|}}
|
||||
<option value={{selectOption}} selected={{eq selectOption @value}}>
|
||||
{{selectOption}}
|
||||
</option>
|
||||
{{/each}}
|
||||
</F.Options>
|
||||
</Hds::Form::Select::Base>
|
||||
@@ -0,0 +1,6 @@
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{@value}}
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{@ariaLabel}}
|
||||
{{on 'input' @setContext}}
|
||||
/>
|
||||
@@ -95,7 +95,14 @@
|
||||
@disabled={{form.disabled}}
|
||||
@addOption={{this.addWorkerTag}}
|
||||
@removeOptionByIndex={{this.removeWorkerTagByIndex}}
|
||||
/>
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
|
||||
@@ -128,10 +128,16 @@ module('Acceptance | auth-methods | create', function (hooks) {
|
||||
await fillIn(CLAIMS_SCOPES_INPUT_SELECTOR, 'claims_scopes');
|
||||
await click(CLAIMS_SCOPES_BTN_SELECTOR, 'claims_scopes');
|
||||
|
||||
await fillIn('[name="from_claim"]', 'from_claim');
|
||||
await select('form fieldset:nth-of-type(4) select', 'email');
|
||||
await fillIn(
|
||||
'[name="account_claim_maps"] tbody td:nth-of-type(1) input',
|
||||
'from_claim',
|
||||
);
|
||||
await select(
|
||||
'[name="account_claim_maps"] tbody td:nth-of-type(2) select',
|
||||
'email',
|
||||
);
|
||||
|
||||
await click('form fieldset:nth-of-type(4) [title="Add"]');
|
||||
await click('[name="account_claim_maps"] button');
|
||||
|
||||
await fillIn(IDP_CERTS_INPUT_SELECTOR, 'certificates');
|
||||
await click(IDP_CERTS_BTN_SELECTOR);
|
||||
|
||||
@@ -164,14 +164,23 @@ module('Acceptance | auth-methods | update', function (hooks) {
|
||||
|
||||
// Remove all claim maps
|
||||
const claimMaps = await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(4) [title="Remove"]'),
|
||||
findAll('[name="account_claim_maps"] [data-test-remove-button]'),
|
||||
);
|
||||
for (const element of claimMaps) {
|
||||
await click(element);
|
||||
}
|
||||
await fillIn('[name="from_claim"]', 'from_claim');
|
||||
await select('form fieldset:nth-of-type(4) select', 'email');
|
||||
await click('form fieldset:nth-of-type(4) [title="Add"]');
|
||||
|
||||
await fillIn(
|
||||
'[name="account_claim_maps"] tbody td:nth-of-type(1) input',
|
||||
'from_claim',
|
||||
);
|
||||
|
||||
await select(
|
||||
'[name="account_claim_maps"] tbody td:nth-of-type(2) select',
|
||||
'email',
|
||||
);
|
||||
|
||||
await click('[name="account_claim_maps"] button');
|
||||
|
||||
// Remove all certificates
|
||||
const certificatesList = findAll(IDP_CERTS_REMOVE_BTN_SELECTOR);
|
||||
@@ -179,15 +188,15 @@ module('Acceptance | auth-methods | update', function (hooks) {
|
||||
for (const element of certificatesList) {
|
||||
await click(element);
|
||||
}
|
||||
|
||||
await fillIn(IDP_CERTS_INPUT_SELECTOR, 'certificates');
|
||||
await click(IDP_CERTS_BTN_SELECTOR);
|
||||
await fillIn('[name="max_age"]', '5');
|
||||
await fillIn('[name="api_url_prefix"]', 'api_url_prefix');
|
||||
await click(TOGGLE_SELECTOR);
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
await click('.rose-form-actions [type="submit"]');
|
||||
|
||||
const authMethod = this.server.schema.authMethods.findBy({ name });
|
||||
|
||||
assert.strictEqual(authMethod.name, name);
|
||||
assert.strictEqual(authMethod.description, 'description');
|
||||
assert.strictEqual(authMethod.attributes.issuer, 'issuer');
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { click, render, select } from '@ember/test-helpers';
|
||||
import { click, findAll, render, select } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import { setupIntl } from 'ember-intl/test-support';
|
||||
|
||||
@@ -55,7 +55,14 @@ module('Integration | Component | list-wrapper', function (hooks) {
|
||||
await render(hbs`
|
||||
<Form::Field::ListWrapper>
|
||||
<:field as |F|>
|
||||
<F.KeyValue @options={{this.options}}></F.KeyValue>
|
||||
<F.KeyValue @options={{this.options}}>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
`);
|
||||
@@ -165,42 +172,56 @@ module('Integration | Component | list-wrapper', function (hooks) {
|
||||
});
|
||||
|
||||
test('it renders multiple options with select and text input as key value pair', async function (assert) {
|
||||
this.options = {
|
||||
username_attribute: 'user',
|
||||
password_attribute: 'pass',
|
||||
};
|
||||
this.options = [
|
||||
{
|
||||
key: 'username_attribute',
|
||||
value: 'user',
|
||||
},
|
||||
{
|
||||
key: 'password_attribute',
|
||||
value: 'pass',
|
||||
},
|
||||
];
|
||||
|
||||
this.selectOptions = ['username_attribute', 'password_attribute'];
|
||||
|
||||
this.selectOptions = {
|
||||
username_attribute: 'User Key',
|
||||
password_attribute: 'Pass Key',
|
||||
};
|
||||
await render(hbs`
|
||||
<Form::Field::ListWrapper>
|
||||
<:field as |F|>
|
||||
<F.SelectText @name="credential_mapping_overrides" @options={{this.options}} @removeDuplicates='true' @selectOptions={{this.selectOptions}}></F.SelectText>
|
||||
<F.KeyValue @name="credential_mapping_overrides">
|
||||
<:key as |K|>
|
||||
<K.select @selectOptions={{this.selectOptions}}/>
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text/>
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
`);
|
||||
|
||||
assert.dom('tbody tr').exists({ count: 2 });
|
||||
assert
|
||||
.dom('.list-wrapper-field tbody tr:last-child input')
|
||||
.hasValue('pass');
|
||||
assert
|
||||
.dom('.list-wrapper-field tbody tr:last-child select')
|
||||
.hasValue('password_attribute');
|
||||
assert.dom('tbody tr').exists({ count: 1 });
|
||||
});
|
||||
|
||||
test('it does not render new rows when the select option limit is reached by passing in @removeDuplicates', async function (assert) {
|
||||
this.options = { username_attribute: 'user', password_attribute: 'pass' };
|
||||
this.selectOptions = {
|
||||
username_attribute: 'User Key',
|
||||
password_attribute: 'Pass Key',
|
||||
};
|
||||
test('it does not render new rows when the select option limit is reached when showNewRow is passed', async function (assert) {
|
||||
this.options = [
|
||||
{ key: 'username_attribute', value: 'user' },
|
||||
{ key: 'password_attribute', value: 'pass' },
|
||||
];
|
||||
|
||||
this.selectOptions = ['username_attribute', 'password_attribute'];
|
||||
this.showNewRow = () => false;
|
||||
await render(hbs`
|
||||
<Form::Field::ListWrapper>
|
||||
<:field as |F|>
|
||||
<F.SelectText @name="credential_mapping_overrides" @options={{this.options}} @selectOptions={{this.selectOptions}} @removeDuplicates='true'></F.SelectText>
|
||||
<F.KeyValue @name="credential_mapping_overrides" @options={{this.options}} @showNewRow={{this.showNewRow}}>
|
||||
<:key as |K|>
|
||||
<K.select @selectOptions={{this.selectOptions}}/>
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text/>
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
`);
|
||||
@@ -208,20 +229,77 @@ module('Integration | Component | list-wrapper', function (hooks) {
|
||||
assert.dom('tbody tr').exists({ count: 2 });
|
||||
});
|
||||
|
||||
test('it does render unlimited new rows when @removeDuplicates is not passed', async function (assert) {
|
||||
this.options = { username_attribute: 'user', password_attribute: 'pass' };
|
||||
this.selectOptions = {
|
||||
username_attribute: 'User Key',
|
||||
password_attribute: 'Pass Key',
|
||||
};
|
||||
test('it does render unlimited new rows when @showNewRow is not passed', async function (assert) {
|
||||
this.options = [
|
||||
{
|
||||
key: 'username_attribute',
|
||||
value: 'user',
|
||||
},
|
||||
{
|
||||
key: 'password_attribute',
|
||||
value: 'pass',
|
||||
},
|
||||
];
|
||||
this.selectOptions = ['username_attribute', 'password_attribute'];
|
||||
await render(hbs`
|
||||
<Form::Field::ListWrapper>
|
||||
<:field as |F|>
|
||||
<F.SelectText @name="credential_mapping_overrides" @options={{this.options}} @selectOptions={{this.selectOptions}}></F.SelectText>
|
||||
<F.KeyValue @name="credential_mapping_overrides" @options={{this.options}} >
|
||||
<:key as |K|>
|
||||
<K.text/>
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text/>
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
`);
|
||||
|
||||
assert.dom('tbody tr').exists({ count: 3 });
|
||||
});
|
||||
|
||||
test('it renders `newKey` and `newValue` named blocks when passed instead of key and value blocks', async function (assert) {
|
||||
this.options = ['option1', 'option2', 'option3'];
|
||||
this.selectOptionsNewValue = [
|
||||
'username_attribute_new_val',
|
||||
'password_attribute_new_val',
|
||||
];
|
||||
|
||||
this.selectOptionsNewKey = [
|
||||
'username_attribute_new_key',
|
||||
'password_attribute_new_key',
|
||||
];
|
||||
await render(hbs`
|
||||
<Form::Field::ListWrapper>
|
||||
<:field as |F|>
|
||||
<F.KeyValue @name="credential_mapping_overrides">
|
||||
<:key as |K|>
|
||||
<K.select @selectOptions = {{this.options}}/>
|
||||
</:key>
|
||||
<:newKey as |N|>
|
||||
<N.select @selectOptions= {{this.selectOptionsNewKey}}/>
|
||||
</:newKey>
|
||||
<:newValue as |S|>
|
||||
<S.select @selectOptions= {{this.selectOptionsNewValue}}/>
|
||||
</:newValue>
|
||||
<:value as |V|>
|
||||
<V.select @selectOptions = {{this.options}}/>
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
`);
|
||||
|
||||
assert.strictEqual(
|
||||
findAll('.list-wrapper-field tbody td:nth-of-type(1) select option')
|
||||
.length,
|
||||
3,
|
||||
);
|
||||
assert.strictEqual(
|
||||
findAll('.list-wrapper-field tbody td:nth-of-type(2) select option')
|
||||
.length,
|
||||
3,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user