Chore migrate credential library storage bucket (#3282)
This commit is contained in:
1 parent
0e223ded8f
commit
e38d3afa58
22 files changed
+177
-102
No files matched your search
@@ -48,6 +48,9 @@ export default factory.extend({
|
||||
critical_options: {
|
||||
[faker.word.noun()]: faker.word.words(2),
|
||||
},
|
||||
extensions: {
|
||||
[faker.word.noun()]: faker.word.words(2),
|
||||
},
|
||||
};
|
||||
case TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP:
|
||||
return {
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
@data={{@model.certificates}}
|
||||
@legend={{t 'resources.auth-method.form.certificates.label'}}
|
||||
@helperText={{t 'resources.auth-method.form.certificates.help'}}
|
||||
@errors={{@model.errors.certificates}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -406,7 +405,6 @@
|
||||
@data={{@model.account_attribute_maps}}
|
||||
@legend={{t 'resources.auth-method.form.account_attribute_maps.label'}}
|
||||
@helperText={{t 'resources.auth-method.form.account_attribute_maps.help'}}
|
||||
@errors={{@model.errors.account_attribute_maps}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -154,7 +154,6 @@
|
||||
@data={{@model.signing_algorithms}}
|
||||
@legend={{t 'form.signing_algorithms.label'}}
|
||||
@helperText={{t 'form.signing_algorithms.help'}}
|
||||
@errors={{@model.errors.signing_algorithms}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -191,7 +190,6 @@
|
||||
@data={{@model.allowed_audiences}}
|
||||
@legend={{t 'form.allowed_audiences.label'}}
|
||||
@helperText={{t 'form.allowed_audiences.help'}}
|
||||
@errors={{@model.errors.allowed_audiences}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -217,7 +215,6 @@
|
||||
@data={{@model.claims_scopes}}
|
||||
@legend={{t 'form.claims_scopes.label'}}
|
||||
@helperText={{t 'form.claims_scopes.help'}}
|
||||
@errors={{@model.errors.claims_scopes}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -243,7 +240,6 @@
|
||||
@data={{@model.account_claim_maps}}
|
||||
@legend={{t 'form.account_claim_maps.label'}}
|
||||
@helperText={{t 'form.account_claim_maps.help'}}
|
||||
@errors={{@model.errors.account_claim_maps}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -288,7 +284,6 @@
|
||||
@data={{@model.idp_ca_certs}}
|
||||
@legend={{t 'form.idp_ca_certs.label'}}
|
||||
@helperText={{t 'form.idp_ca_certs.help'}}
|
||||
@errors={{@model.errors.idp_ca_certs}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -232,7 +232,6 @@
|
||||
@data={{@model.critical_options}}
|
||||
@legend={{t 'resources.credential-library.form.critical_options.label'}}
|
||||
@helperText={{t 'resources.credential-library.form.critical_options.help'}}
|
||||
@errors={{@model.errors.critical_options}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -262,43 +261,40 @@
|
||||
|
||||
</Form::Field::KeyValue>
|
||||
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
<Form::Field::KeyValue
|
||||
@name='extensions'
|
||||
@model={{@model}}
|
||||
@properties={{array 'key' 'value'}}
|
||||
@data={{@model.extensions}}
|
||||
@legend={{t 'resources.credential-library.form.extensions.label'}}
|
||||
@helperText={{t 'resources.credential-library.form.extensions.help'}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.credential-library.form.extensions.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.credential-library.form.extensions.help'}}
|
||||
</F.HelperText>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.Label>{{t 'form.key.label'}}</F.Label>
|
||||
<F.TextInput
|
||||
data-test-key-input
|
||||
@value={{R.rowData.key}}
|
||||
{{on 'input' (fn R.updateRow 'key')}}
|
||||
/>
|
||||
</R.Field>
|
||||
|
||||
{{#if @model.errors.extensions}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.extensions as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
<R.Field as |F|>
|
||||
<F.Label>{{t 'form.value.label'}}</F.Label>
|
||||
<F.TextInput
|
||||
data-test-value-input
|
||||
@value={{R.rowData.value}}
|
||||
{{on 'input' (fn R.updateRow 'value')}}
|
||||
/>
|
||||
</R.Field>
|
||||
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@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>
|
||||
</:row>
|
||||
</Form::Field::KeyValue>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
data-test-add-button
|
||||
@onClick={{this.handleAdd}}
|
||||
/>
|
||||
{{#if @errors}}
|
||||
|
||||
{{#if (get @model.errors @name)}}
|
||||
<F.Error as |E|>
|
||||
{{#each @errors as |error|}}
|
||||
{{#each (get @model.errors @name) as |error|}}
|
||||
<E.Message data-test-error-message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
|
||||
@@ -279,7 +279,6 @@
|
||||
@data={{@model.role_tags}}
|
||||
@legend={{t 'resources.storage-bucket.form.role_tags.label'}}
|
||||
@helperText={{t 'resources.storage-bucket.form.role_tags.help'}}
|
||||
@errors={{@model.errors.role_tags}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
@data={{@model.preferred_endpoints}}
|
||||
@legend={{t 'resources.host-set.form.preferred_endpoints.label'}}
|
||||
@helperText={{t 'resources.host-set.form.preferred_endpoints.help'}}
|
||||
@errors={{@model.errors.preferred_endpoints}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -94,7 +93,6 @@
|
||||
@data={{@model.filters}}
|
||||
@legend={{t 'resources.host-set.form.filter.label'}}
|
||||
@helperText={{t 'resources.host-set.form.filter.aws.help'}}
|
||||
@errors={{@model.errors.filters}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
@data={{@model.preferred_endpoints}}
|
||||
@legend={{t 'resources.host-set.form.preferred_endpoints.label'}}
|
||||
@helperText={{t 'resources.host-set.form.preferred_endpoints.help'}}
|
||||
@errors={{@model.errors.preferred_endpoints}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
@data={{@model.preferred_endpoints}}
|
||||
@legend={{t 'resources.host-set.form.preferred_endpoints.label'}}
|
||||
@helperText={{t 'resources.host-set.form.preferred_endpoints.help'}}
|
||||
@errors={{@model.errors.preferred_endpoints}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
@@ -93,7 +92,6 @@
|
||||
@data={{@model.filters}}
|
||||
@legend={{t 'resources.host-set.form.filter.label'}}
|
||||
@helperText={{t 'resources.host-set.form.filter.gcp.help'}}
|
||||
@errors={{@model.errors.filters}}
|
||||
@disabled={{form.disabled}}
|
||||
@isOptional={{true}}
|
||||
>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
}}
|
||||
|
||||
<Rose::Form
|
||||
@edit={{@edit}}
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@@ -417,42 +418,42 @@
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
{{! role_tags }}
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
<Form::Field::KeyValue
|
||||
@model={{@model}}
|
||||
@name='role_tags'
|
||||
@properties={{array 'key' 'value'}}
|
||||
@data={{@model.role_tags}}
|
||||
@isOptional={{true}}
|
||||
@legend={{t 'resources.storage-bucket.form.role_tags.label'}}
|
||||
@helperText={{t 'resources.storage-bucket.form.role_tags.help'}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.storage-bucket.form.role_tags.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.storage-bucket.form.role_tags.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.role_tags}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.role_tags as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput
|
||||
data-test-key-input
|
||||
@value={{R.rowData.key}}
|
||||
{{on 'input' (fn R.updateRow 'key')}}
|
||||
disabled={{form.disabled}}
|
||||
/>
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput
|
||||
data-test-value-input
|
||||
@value={{R.rowData.value}}
|
||||
{{on 'input' (fn R.updateRow 'value')}}
|
||||
disabled={{form.disabled}}
|
||||
/>
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton
|
||||
data-test-delete-button
|
||||
@onClick={{R.removeRow}}
|
||||
disabled={{form.disabled}}
|
||||
/>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@name='role_tags'
|
||||
@options={{@model.role_tags}}
|
||||
@model={{@model}}
|
||||
>
|
||||
<:key as |K|>
|
||||
<K.text />
|
||||
</:key>
|
||||
<:value as |V|>
|
||||
<V.text />
|
||||
</:value>
|
||||
</F.KeyValue>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
</:row>
|
||||
</Form::Field::KeyValue>
|
||||
{{/if}}
|
||||
|
||||
{{! worker_filter }}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
{{#if @model.type}}
|
||||
<this.storageBucketFormComponent
|
||||
@model={{@model}}
|
||||
@edit={{@edit}}
|
||||
@submit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@updateScope={{this.updateScope}}
|
||||
|
||||
+11
@@ -79,6 +79,13 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
credentialLibrary.critical_options =
|
||||
credentialLibrary.critical_options.filter((item) => item.key?.trim());
|
||||
}
|
||||
|
||||
if (credentialLibrary.extensions) {
|
||||
credentialLibrary.extensions = credentialLibrary.extensions.filter(
|
||||
(item) => item.key?.trim(),
|
||||
);
|
||||
}
|
||||
|
||||
await credentialLibrary.save();
|
||||
if (this.abilities.can('read model', credentialLibrary)) {
|
||||
await this.router.transitionTo(
|
||||
@@ -130,6 +137,10 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
if (credentialLibrary.critical_options?.length === 0) {
|
||||
credentialLibrary.critical_options = [{ key: '', value: '' }];
|
||||
}
|
||||
|
||||
if (credentialLibrary.extensions?.length === 0) {
|
||||
credentialLibrary.extensions = [{ key: '', value: '' }];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,10 @@ import { action } from '@ember/object';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { TYPE_CREDENTIAL_STATIC } from 'api/models/storage-bucket';
|
||||
import {
|
||||
TYPE_CREDENTIAL_STATIC,
|
||||
TYPE_CREDENTIAL_DYNAMIC,
|
||||
} from 'api/models/storage-bucket';
|
||||
|
||||
export default class ScopesScopeStorageBucketsIndexController extends Controller {
|
||||
// =services
|
||||
@@ -45,6 +48,17 @@ export default class ScopesScopeStorageBucketsIndexController extends Controller
|
||||
return this.intl.t(description, { resource });
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates one empty role_tags row for storage bucket when the field is empty.
|
||||
* @param {storageBucketModel} bucket
|
||||
*/
|
||||
generateAwsRoleTagsRowIfEmpty(bucket) {
|
||||
// If role_tags is an empty array, add an empty row
|
||||
if (!bucket.role_tags || bucket.role_tags.length === 0) {
|
||||
bucket.role_tags = [{ key: '', value: '' }];
|
||||
}
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
@@ -60,6 +74,13 @@ export default class ScopesScopeStorageBucketsIndexController extends Controller
|
||||
if (!storageBucket.role_arn) {
|
||||
storageBucket.credentialType = TYPE_CREDENTIAL_STATIC;
|
||||
}
|
||||
|
||||
if (storageBucket.role_tags) {
|
||||
storageBucket.role_tags = storageBucket.role_tags.filter((item) =>
|
||||
item.key?.trim(),
|
||||
);
|
||||
}
|
||||
|
||||
await storageBucket.save();
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.storage-buckets.storage-bucket',
|
||||
@@ -105,6 +126,10 @@ export default class ScopesScopeStorageBucketsIndexController extends Controller
|
||||
@action
|
||||
changeCredentialType(storageBucket, credentialType) {
|
||||
storageBucket.credentialType = credentialType;
|
||||
|
||||
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
|
||||
this.generateAwsRoleTagsRowIfEmpty(storageBucket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,4 +142,15 @@ export default class ScopesScopeStorageBucketsIndexController extends Controller
|
||||
queryParams: { compositeType: pluginType },
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
edit(storageBucket) {
|
||||
if (storageBucket.role_tags) {
|
||||
storageBucket.role_tags = structuredClone(storageBucket.role_tags);
|
||||
}
|
||||
|
||||
if (storageBucket.credentialType === TYPE_CREDENTIAL_DYNAMIC) {
|
||||
this.generateAwsRoleTagsRowIfEmpty(storageBucket);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -77,9 +77,10 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
name,
|
||||
description,
|
||||
};
|
||||
// if the type is vault-ssh-certificate, initialize critical_options with an empty row
|
||||
// if the type is vault-ssh-certificate, initialize critical_options and extensions with an empty row
|
||||
if (resolvedType === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE) {
|
||||
attrs.critical_options = [{ key: '', value: '' }];
|
||||
attrs.extensions = [{ key: '', value: '' }];
|
||||
}
|
||||
|
||||
return this.store.createRecord('credential-library', attrs);
|
||||
|
||||
@@ -53,7 +53,8 @@ export default class ScopesScopeStorageBucketsNewRoute extends Route {
|
||||
bucket_name,
|
||||
bucket_prefix,
|
||||
region,
|
||||
worker_filter;
|
||||
worker_filter,
|
||||
role_tags;
|
||||
|
||||
if (this.currentModel?.isNew) {
|
||||
({
|
||||
@@ -64,6 +65,7 @@ export default class ScopesScopeStorageBucketsNewRoute extends Route {
|
||||
bucket_prefix,
|
||||
region,
|
||||
worker_filter,
|
||||
role_tags,
|
||||
} = this.currentModel);
|
||||
this.currentModel.rollbackAttributes();
|
||||
}
|
||||
@@ -78,6 +80,7 @@ export default class ScopesScopeStorageBucketsNewRoute extends Route {
|
||||
bucket_prefix,
|
||||
region,
|
||||
worker_filter,
|
||||
role_tags: role_tags || [{ key: '', value: '' }],
|
||||
});
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<page.body>
|
||||
<Form::StorageBucket
|
||||
@model={{@model}}
|
||||
@edit={{fn this.storageBuckets.edit @model}}
|
||||
@submit={{fn this.storageBuckets.save @model}}
|
||||
@cancel={{fn this.storageBuckets.cancel @model}}
|
||||
@scopes={{this.scopes}}
|
||||
|
||||
@@ -193,7 +193,6 @@ module('Acceptance | credential-libraries | create', function (hooks) {
|
||||
await fillIn(selectors.FIELD_CRIT_OPTS_VALUE, 'co_value');
|
||||
await fillIn(selectors.FIELD_EXT_KEY, 'ext_key');
|
||||
await fillIn(selectors.FIELD_EXT_VALUE, 'ext_value');
|
||||
await click(selectors.FIELD_EXT_BTN);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
assert.strictEqual(getCredentialLibraryCount(), count + 1);
|
||||
|
||||
@@ -37,11 +37,8 @@ export const FIELD_CRIT_OPTS_KEY =
|
||||
export const FIELD_CRIT_OPTS_VALUE =
|
||||
'[name="critical_options"] [data-test-value-input]';
|
||||
|
||||
export const FIELD_EXT_KEY =
|
||||
'[name="extensions"] tbody td:nth-of-type(1) input';
|
||||
export const FIELD_EXT_VALUE =
|
||||
'[name="extensions"] tbody td:nth-of-type(2) input';
|
||||
export const FIELD_EXT_BTN = '[name="extensions"] button';
|
||||
export const FIELD_EXT_KEY = '[name="extensions"] [data-test-key-input]';
|
||||
export const FIELD_EXT_VALUE = '[name="extensions"] [data-test-value-input]';
|
||||
|
||||
export const MANAGE_DROPDOWN_CRED_LIB =
|
||||
'[data-test-manage-credential-library-dropdown] button:first-child';
|
||||
|
||||
@@ -357,7 +357,6 @@ module('Acceptance | credential-libraries | update', function (hooks) {
|
||||
await fillIn(selectors.FIELD_CRIT_OPTS_VALUE, 'co_value');
|
||||
await fillIn(selectors.FIELD_EXT_KEY, 'ext_key');
|
||||
await fillIn(selectors.FIELD_EXT_VALUE, 'ext_value');
|
||||
await click(selectors.FIELD_EXT_BTN);
|
||||
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
|
||||
@@ -249,6 +249,14 @@ module('Acceptance | storage-buckets | create', function (hooks) {
|
||||
|
||||
await click(selectors.FIELD_DYNAMIC_CREDENTIAL);
|
||||
await fillIn(selectors.FIELD_ROLE_ARN, selectors.FIELD_ROLE_ARN_VALUE);
|
||||
await fillIn(
|
||||
selectors.FIELD_ROLE_TAG_KEY,
|
||||
selectors.FIELD_ROLE_TAG_KEY_VALUE,
|
||||
);
|
||||
await fillIn(
|
||||
selectors.FIELD_ROLE_TAG_VALUE,
|
||||
selectors.FIELD_ROLE_TAG_VALUE_TEXT,
|
||||
);
|
||||
await waitFor(commonSelectors.CODE_EDITOR_CM);
|
||||
|
||||
const editorElement = find(commonSelectors.CODE_EDITOR_CODE);
|
||||
@@ -266,6 +274,10 @@ module('Acceptance | storage-buckets | create', function (hooks) {
|
||||
});
|
||||
|
||||
assert.strictEqual(storageBucket.name, commonSelectors.FIELD_NAME_VALUE);
|
||||
assert.deepEqual(storageBucket.attributes.role_tags, {
|
||||
env: selectors.FIELD_ROLE_TAG_VALUE_TEXT,
|
||||
});
|
||||
|
||||
//for dynamic credentials, there should be no secret field
|
||||
assert.notOk(storageBucket.secret);
|
||||
assert.strictEqual(getStorageBucketCount(), storageBucketCount + 1);
|
||||
|
||||
@@ -29,6 +29,13 @@ export const FIELD_SECRET_KEY_EDIT_BTN =
|
||||
'[data-test-secret-access-key] [type=button]';
|
||||
export const FIELD_WORKER_FILTER = '[name=worker_filter]';
|
||||
export const FIELD_WORKER_FILTER_ERROR = '[data-test-worker-filter-error]';
|
||||
export const FIELD_ROLE_TAG_KEY = '[name=role_tags] [data-test-key-input]';
|
||||
export const FIELD_ROLE_TAG_VALUE = '[name=role_tags] [data-test-value-input]';
|
||||
export const FIELD_ROLE_TAG_KEY_VALUE = 'env';
|
||||
export const FIELD_ROLE_TAG_VALUE_TEXT = 'dev';
|
||||
export const FIELD_ROLE_TAG_ADD_BTN = '[name=role_tags] [data-test-add-button]';
|
||||
export const FIELD_ROLE_TAG_DELETE_BTN =
|
||||
'[name=role_tags] [data-test-delete-button]';
|
||||
export const READONLY_WORKER_FILTER = '[data-test-worker-filter]';
|
||||
|
||||
export const TOAST = '[role=alert] div';
|
||||
|
||||
@@ -203,16 +203,26 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
assert.dom('[data-test-delete-button]').doesNotExist();
|
||||
});
|
||||
|
||||
test('it displays error messages in footer', async function (assert) {
|
||||
this.set('data', [{ key: '', value: '' }]);
|
||||
this.set('errors', [
|
||||
{ message: 'Key is required' },
|
||||
{ message: 'Value must be unique' },
|
||||
]);
|
||||
test('it displays error messages in footer (model errors)', async function (assert) {
|
||||
const model = {
|
||||
tags: [{ key: '', value: '' }],
|
||||
errors: {
|
||||
tags: [
|
||||
{ message: 'Key is required' },
|
||||
{ message: 'Value must be unique' },
|
||||
],
|
||||
},
|
||||
};
|
||||
this.set('model', model);
|
||||
this.set('properties', ['key', 'value']);
|
||||
|
||||
// With errors
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}} @errors={{this.errors}}>
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{this.properties}}
|
||||
@data={{this.model.tags}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} />
|
||||
@@ -221,7 +231,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
@@ -235,9 +245,13 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
.hasText('Value must be unique');
|
||||
|
||||
// Without errors
|
||||
this.set('errors', undefined);
|
||||
this.set('model', { ...model, errors: {} });
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}} @errors={{this.errors}}>
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{this.properties}}
|
||||
@data={{this.model.tags}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} />
|
||||
@@ -246,7 +260,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
@@ -322,6 +336,12 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
test('custom handlers take precedence over default handlers', async function (assert) {
|
||||
const model = {
|
||||
tags: [{ key: '', value: '' }],
|
||||
errors: {
|
||||
tags: [
|
||||
{ message: 'Key is required' },
|
||||
{ message: 'Value must be unique' },
|
||||
],
|
||||
},
|
||||
};
|
||||
this.set('model', model);
|
||||
|
||||
|
||||
Reference in new issue
Block a user