diff --git a/addons/api/app/mirage/factories/credential-library.js b/addons/api/app/mirage/factories/credential-library.js
index 222e26c0a..a0e7a96f1 100644
--- a/addons/api/app/mirage/factories/credential-library.js
+++ b/addons/api/app/mirage/factories/credential-library.js
@@ -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 {
diff --git a/ui/admin/app/components/form/auth-method/ldap/index.hbs b/ui/admin/app/components/form/auth-method/ldap/index.hbs
index a2ade405b..32fc75f68 100644
--- a/ui/admin/app/components/form/auth-method/ldap/index.hbs
+++ b/ui/admin/app/components/form/auth-method/ldap/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/auth-method/oidc/index.hbs b/ui/admin/app/components/form/auth-method/oidc/index.hbs
index 912b81836..8bb777a49 100644
--- a/ui/admin/app/components/form/auth-method/oidc/index.hbs
+++ b/ui/admin/app/components/form/auth-method/oidc/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs b/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
index 562fdc664..ee1e2c963 100644
--- a/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
+++ b/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
@@ -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 @@
-
- <:fieldset as |F|>
-
- {{t 'resources.credential-library.form.extensions.label'}}
-
-
- {{t 'resources.credential-library.form.extensions.help'}}
-
+ <:row as |R|>
+
+ {{t 'form.key.label'}}
+
+
- {{#if @model.errors.extensions}}
-
- {{#each @model.errors.extensions as |error|}}
- {{error.message}}
- {{/each}}
-
+
+ {{t 'form.value.label'}}
+
+
+
+ {{#if R.canDelete}}
+
{{/if}}
-
- <:field as |F|>
-
- <:key as |K|>
-
-
- <:value as |V|>
-
-
-
-
-
-
+
+
{{#if (can 'save model' @model)}}
- {{#if @errors}}
+
+ {{#if (get @model.errors @name)}}
- {{#each @errors as |error|}}
+ {{#each (get @model.errors @name) as |error|}}
{{error.message}}
{{/each}}
diff --git a/ui/admin/app/components/form/host-catalog/aws/index.hbs b/ui/admin/app/components/form/host-catalog/aws/index.hbs
index ac7bc46e7..10085d870 100644
--- a/ui/admin/app/components/form/host-catalog/aws/index.hbs
+++ b/ui/admin/app/components/form/host-catalog/aws/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/host-set/aws/index.hbs b/ui/admin/app/components/form/host-set/aws/index.hbs
index fbb571a98..0d69e486e 100644
--- a/ui/admin/app/components/form/host-set/aws/index.hbs
+++ b/ui/admin/app/components/form/host-set/aws/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/host-set/azure/index.hbs b/ui/admin/app/components/form/host-set/azure/index.hbs
index a065889f3..849800c6f 100644
--- a/ui/admin/app/components/form/host-set/azure/index.hbs
+++ b/ui/admin/app/components/form/host-set/azure/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/host-set/gcp/index.hbs b/ui/admin/app/components/form/host-set/gcp/index.hbs
index a5e5661f8..8b63b07b1 100644
--- a/ui/admin/app/components/form/host-set/gcp/index.hbs
+++ b/ui/admin/app/components/form/host-set/gcp/index.hbs
@@ -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}}
>
diff --git a/ui/admin/app/components/form/storage-bucket/aws/index.hbs b/ui/admin/app/components/form/storage-bucket/aws/index.hbs
index 2fa206ef9..71ec0d282 100644
--- a/ui/admin/app/components/form/storage-bucket/aws/index.hbs
+++ b/ui/admin/app/components/form/storage-bucket/aws/index.hbs
@@ -4,6 +4,7 @@
}}
{{! role_tags }}
-
- <:fieldset as |F|>
-
- {{t 'resources.storage-bucket.form.role_tags.label'}}
-
-
- {{t 'resources.storage-bucket.form.role_tags.help'}}
-
-
- {{#if @model.errors.role_tags}}
-
- {{#each @model.errors.role_tags as |error|}}
- {{error.message}}
- {{/each}}
-
+ <:row as |R|>
+
+
+
+
+
+
+ {{#if R.canDelete}}
+
{{/if}}
-
- <:field as |F|>
-
- <:key as |K|>
-
-
- <:value as |V|>
-
-
-
-
-
+
+
{{/if}}
{{! worker_filter }}
diff --git a/ui/admin/app/components/form/storage-bucket/index.hbs b/ui/admin/app/components/form/storage-bucket/index.hbs
index 2456aaf0d..078dc2177 100644
--- a/ui/admin/app/components/form/storage-bucket/index.hbs
+++ b/ui/admin/app/components/form/storage-bucket/index.hbs
@@ -5,6 +5,7 @@
{{#if @model.type}}
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: '' }];
+ }
}
/**
diff --git a/ui/admin/app/controllers/scopes/scope/storage-buckets/index.js b/ui/admin/app/controllers/scopes/scope/storage-buckets/index.js
index b1265646c..7e6b7b8f0 100644
--- a/ui/admin/app/controllers/scopes/scope/storage-buckets/index.js
+++ b/ui/admin/app/controllers/scopes/scope/storage-buckets/index.js
@@ -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);
+ }
+ }
}
diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
index d2dbaebd1..85b603f19 100644
--- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
+++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
@@ -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);
diff --git a/ui/admin/app/routes/scopes/scope/storage-buckets/new.js b/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
index 26bc24b88..3823e4c86 100644
--- a/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
+++ b/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
@@ -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;
}
diff --git a/ui/admin/app/templates/scopes/scope/storage-buckets/storage-bucket/index.hbs b/ui/admin/app/templates/scopes/scope/storage-buckets/storage-bucket/index.hbs
index 5f4f2f75c..7eab0c9d2 100644
--- a/ui/admin/app/templates/scopes/scope/storage-buckets/storage-bucket/index.hbs
+++ b/ui/admin/app/templates/scopes/scope/storage-buckets/storage-bucket/index.hbs
@@ -42,6 +42,7 @@
+
<:row as |R|>
@@ -221,7 +231,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
{{#if R.canDelete}}
-
+
{{/if}}
<: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`
-
+
<:row as |R|>
@@ -246,7 +260,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
{{#if R.canDelete}}
-
+
{{/if}}
<: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);