chore: 🤖 migrate oidc fields to keyvalue component (#3160)

This commit is contained in:
Dharini committed 2026-06-03 16:36:29 -07:00
1 parent 8b870556a6
commit 71ec7b465a
6 files changed
+202 -175

No files matched your search

@@ -146,113 +146,109 @@
</Hds::Form::TextInput::Field>
{{/unless}}
{{! Signing Algorithms }}
<Form::Field::ListWrapper
@layout='horizontal'
@isOptional={{true}}
{{! Signing algorithms }}
<Form::Field::KeyValue
@name='signing_algorithms'
@data={{@model.signing_algorithms}}
@onAdd={{fn this.addRow 'signing_algorithms' this.createEmptyValue}}
@onRemove={{fn this.removeRow 'signing_algorithms' this.createEmptyValue}}
@onUpdate={{fn this.updateRow 'signing_algorithms'}}
@legend={{t 'form.signing_algorithms.label'}}
@helperText={{t 'form.signing_algorithms.help'}}
@errors={{@model.errors.signing_algorithms}}
@disabled={{form.disabled}}
>
<:fieldset as |F|>
<F.Legend>
{{t 'form.signing_algorithms.label'}}
</F.Legend>
<F.HelperText>
{{t 'form.signing_algorithms.help'}}
</F.HelperText>
{{#if @model.errors.signing_algorithms}}
<F.Error as |E|>
{{#each @model.errors.signing_algorithms as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</:fieldset>
<:field as |F|>
<F.Select
@name='signing_algorithms'
@model={{@model}}
@selectOptions={{this.signingAlgorithms}}
@width='100%'
/>
</:field>
</Form::Field::ListWrapper>
{{! Allowed Audiences }}
<Form::Field::ListWrapper
@layout='horizontal'
@isOptional={{true}}
@disabled={{form.disabled}}
>
<:fieldset as |F|>
<F.Legend>
{{t 'form.allowed_audiences.label'}}
</F.Legend>
<F.HelperText>
{{t 'form.allowed_audiences.help'}}
</F.HelperText>
{{#if @model.errors.allowed_audiences}}
<F.Error as |E|>
{{#each @model.errors.allowed_audiences as |error|}}
<E.Message>{{error.message}}</E.Message>
<:row as |R|>
<R.Field as |F|>
<F.Select
data-test-value-input
{{on 'change' (fn R.updateRow 'value')}}
>
<option disabled hidden selected value=''>
{{t 'titles.choose-an-option'}}
</option>
{{#each this.signingAlgorithms as |algorithm|}}
<option
value={{algorithm}}
selected={{eq R.rowData.value algorithm}}
>
{{algorithm}}
</option>
{{/each}}
</F.Error>
</F.Select>
</R.Field>
{{#if R.canDelete}}
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
{{/if}}
</:fieldset>
</:row>
</Form::Field::KeyValue>
<:field as |F|>
<F.TextInput
@name='allowed_audiences'
@options={{@model.allowed_audiences}}
@model={{@model}}
/>
</:field>
</Form::Field::ListWrapper>
{{! Allowed audiences }}
<Form::Field::KeyValue
@name='allowed_audiences'
@data={{@model.allowed_audiences}}
@onAdd={{fn this.addRow 'allowed_audiences' this.createEmptyValue}}
@onRemove={{fn this.removeRow 'allowed_audiences' this.createEmptyValue}}
@onUpdate={{fn this.updateRow 'allowed_audiences'}}
@legend={{t 'form.allowed_audiences.label'}}
@helperText={{t 'form.allowed_audiences.help'}}
@errors={{@model.errors.allowed_audiences}}
@disabled={{form.disabled}}
@isOptional={{true}}
>
<:row as |R|>
<R.Field as |F|>
<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}}
</:row>
</Form::Field::KeyValue>
{{! Claims Scopes }}
<Form::Field::ListWrapper
@layout='horizontal'
@isOptional={{true}}
<Form::Field::KeyValue
@name='claims_scopes'
@data={{@model.claims_scopes}}
@onAdd={{fn this.addRow 'claims_scopes' this.createEmptyValue}}
@onRemove={{fn this.removeRow 'claims_scopes' this.createEmptyValue}}
@onUpdate={{fn this.updateRow 'claims_scopes'}}
@legend={{t 'form.claims_scopes.label'}}
@helperText={{t 'form.claims_scopes.help'}}
@errors={{@model.errors.claims_scopes}}
@disabled={{form.disabled}}
@isOptional={{true}}
>
<:fieldset as |F|>
<F.Legend>
{{t 'form.claims_scopes.label'}}
</F.Legend>
<F.HelperText>
{{t 'form.claims_scopes.help'}}
</F.HelperText>
{{#if @model.errors.claims_scopes}}
<F.Error as |E|>
{{#each @model.errors.claims_scopes as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
<:row as |R|>
<R.Field as |F|>
<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.TextInput
@name='claims_scopes'
@options={{@model.claims_scopes}}
@model={{@model}}
/>
</:field>
</Form::Field::ListWrapper>
</:row>
</Form::Field::KeyValue>
{{! Account Claim Maps }}
<Form::Field::KeyValue
@name='account_claim_maps'
@data={{@model.account_claim_maps}}
@onAdd={{this.addAccountClaimMap}}
@onRemove={{this.removeAccountClaimMap}}
@onUpdate={{this.updateAccountClaimMap}}
@onAdd={{fn this.addRow 'account_claim_maps' this.createEmptyKeyValue}}
@onRemove={{fn
this.removeRow
'account_claim_maps'
this.createEmptyKeyValue
}}
@onUpdate={{fn this.updateRow 'account_claim_maps'}}
@legend={{t 'form.account_claim_maps.label'}}
@helperText={{t 'form.account_claim_maps.help'}}
@errors={{@model.errors.account_claim_maps}}
@@ -293,37 +289,31 @@
</Form::Field::KeyValue>
{{! Certificates }}
<Form::Field::ListWrapper
@layout='horizontal'
@isOptional={{true}}
<Form::Field::KeyValue
@name='idp_ca_certs'
@data={{@model.idp_ca_certs}}
@onAdd={{fn this.addRow 'idp_ca_certs' this.createEmptyValue}}
@onRemove={{fn this.removeRow 'idp_ca_certs' this.createEmptyValue}}
@onUpdate={{fn this.updateRow '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}}
>
<:fieldset as |F|>
<F.Legend>
{{t 'form.idp_ca_certs.label'}}
</F.Legend>
<F.HelperText>
{{t 'form.idp_ca_certs.help'}}
</F.HelperText>
{{#if @model.errors.idp_ca_certs}}
<F.Error as |E|>
{{#each @model.errors.idp_ca_certs as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
<:row as |R|>
<R.Field as |F|>
<F.Textarea
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.Textarea
@name='idp_ca_certs'
@options={{@model.idp_ca_certs}}
@model={{@model}}
/>
</:field>
</Form::Field::ListWrapper>
</:row>
</Form::Field::KeyValue>
<Hds::Form::TextInput::Field
name='max_age'
@@ -9,6 +9,11 @@ import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class FormAuthMethodOidcComponent extends Component {
// For fields with just a value property
createEmptyValue = () => ({ value: '' });
// For fields with key and value properties
createEmptyKeyValue = () => ({ key: '', value: '' });
// =attributes
/**
@@ -55,45 +60,6 @@ export default class FormAuthMethodOidcComponent extends Component {
//actions
/**
* Adds a new empty row to account claim maps
*/
@action
addAccountClaimMap() {
this.args.model.account_claim_maps = [
...this.args.model.account_claim_maps,
{ key: '', value: '' },
];
}
/**
* Removes a row from account claim maps
* @param {Object} rowData - The row to remove
*/
@action
removeAccountClaimMap(rowData) {
let rows = this.args.model.account_claim_maps.filter(
(item) => item !== rowData,
);
// Ensure at least one empty row exists for editing
if (rows.length === 0) {
rows = [{ key: '', value: '' }];
}
this.args.model.account_claim_maps = rows;
}
/**
* Updates the account claim maps in the model
*/
@action
updateAccountClaimMap(rowData, property, { target: { value } }) {
rowData[property] = value;
this.args.model.account_claim_maps = [
...this.args.model.account_claim_maps,
];
}
/**
* @param {string} value
*/
@@ -128,4 +94,34 @@ export default class FormAuthMethodOidcComponent extends Component {
this.args.model.prompts = [...removeSelection];
}
}
/**
* Adds a new empty row to account claim maps
*/
@action
addRow(field, emptyRow) {
this.args.model[field] = [...this.args.model[field], emptyRow()];
}
/**
* Removes a row from account claim maps
*/
@action
removeRow(field, emptyRow, rowData) {
let rows = this.args.model[field].filter((item) => item !== rowData);
// Ensure at least one empty row exists for editing
if (rows.length === 0) {
rows = [emptyRow()];
}
this.args.model[field] = rows;
}
/**
* Updates the account claim maps in the model
*/
@action
updateRow(field, rowData, property, { target: { value } }) {
rowData[property] = value;
this.args.model[field] = [...this.args.model[field]];
}
}
@@ -153,6 +153,26 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller {
(item) => item.key?.trim(),
);
}
if (authMethod.claims_scopes) {
authMethod.claims_scopes = authMethod.claims_scopes.filter((item) =>
item.value?.trim(),
);
}
if (authMethod.allowed_audiences) {
authMethod.allowed_audiences = authMethod.allowed_audiences.filter(
(item) => item.value?.trim(),
);
}
if (authMethod.signing_algorithms) {
authMethod.signing_algorithms = authMethod.signing_algorithms.filter(
(item) => item.value?.trim(),
);
}
if (authMethod.idp_ca_certs) {
authMethod.idp_ca_certs = authMethod.idp_ca_certs.filter((item) =>
item.value?.trim(),
);
}
await authMethod.save();
if (this.abilities.can('read model', authMethod)) {
await this.router.transitionTo(
@@ -296,19 +316,32 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller {
edit(authMethod) {
if (authMethod.claims_scopes) {
authMethod.claims_scopes = structuredClone(authMethod.claims_scopes);
// Ensure at least one empty row exists for editing
if (authMethod.claims_scopes.length === 0) {
authMethod.claims_scopes = [{ value: '' }];
}
}
if (authMethod.signing_algorithms) {
authMethod.signing_algorithms = structuredClone(
authMethod.signing_algorithms,
);
if (authMethod.signing_algorithms.length === 0) {
authMethod.signing_algorithms = [{ value: '' }];
}
}
if (authMethod.allowed_audiences) {
authMethod.allowed_audiences = structuredClone(
authMethod.allowed_audiences,
);
if (authMethod.allowed_audiences.length === 0) {
authMethod.allowed_audiences = [{ value: '' }];
}
}
if (authMethod.idp_ca_certs) {
authMethod.idp_ca_certs = structuredClone(authMethod.idp_ca_certs);
if (authMethod.idp_ca_certs.length === 0) {
authMethod.idp_ca_certs = [{ value: '' }];
}
}
if (authMethod.account_claim_maps) {
authMethod.account_claim_maps = structuredClone(
@@ -49,9 +49,13 @@ export default class ScopesScopeAuthMethodsNewRoute extends Route {
});
record.scopeModel = scopeModel;
// if the auth method type is OIDC, initialize account_claim_maps with an empty row
// If the auth-method is of type OIDC, initialize the keyValue fields with an empty object.
if (params.type === TYPE_AUTH_METHOD_OIDC) {
record.account_claim_maps = [{ key: '', value: '' }];
record.claims_scopes = [{ value: '' }];
record.allowed_audiences = [{ value: '' }];
record.signing_algorithms = [{ value: '' }];
record.idp_ca_certs = [{ value: '' }];
}
return record;
@@ -9,34 +9,41 @@ export const FIELD_CLIENT_ID = '[name=client_id]';
export const FIELD_CLIENT_ID_VALUE = 'Client id value';
export const FIELD_CLIENT_SECRET = '[name=client_secret]';
export const FIELD_CLIENT_SECRET_VALUE = 'Client secret value';
export const FIELD_SIGNING_ALGORITHMS = '[name=signing_algorithms] select';
export const FIELD_SIGNING_ALGORITHMS =
'[name=signing_algorithms] [data-test-value-input]';
export const FIELD_SIGNING_ALGORITHMS_VALUE = 'RS384';
export const FIELD_SIGNING_ALGORITHMS_ADD_BTN = '[data-test-add-option-button]';
export const FIELD_SIGNING_ALGORITHMS_ADD_BTN =
'[name=signing_algorithms] [data-test-add-button]';
export const FIELD_SIGNING_ALGORITHMS_DELETE_BTN =
'[name=signing_algorithms] tbody td:last-child button[aria-label=Remove]';
export const FIELD_ALLOWED_AUDIENCES = '[name=allowed_audiences] input';
'[name=signing_algorithms] [data-test-delete-button]';
export const FIELD_ALLOWED_AUDIENCES =
'[name=allowed_audiences] [data-test-value-input]';
export const FIELD_ALLOWED_AUDIENCES_VALUE = 'Allowed audiences';
export const FIELD_ALLOWED_AUDIENCES_ADD_BTN =
'[name=allowed_audiences] button';
'[name=allowed_audiences] [data-test-add-button]';
export const FIELD_ALLOWED_AUDIENCES_DELETE_BTN =
'[name=allowed_audiences] tbody td:last-child button[aria-label=Remove]';
export const FIELD_CLAIMS_SCOPES = '[name=claims_scopes] input';
'[name=allowed_audiences] [data-test-delete-button]';
export const FIELD_CLAIMS_SCOPES =
'[name=claims_scopes] [data-test-value-input]';
export const FIELD_CLAIMS_SCOPES_VALUE = 'Claim scopes';
export const FIELD_CLAIMS_SCOPES_ADD_BTN = '[name=claims_scopes] button';
export const FIELD_CLAIMS_SCOPES_ADD_BTN =
'[name=claims_scopes] [data-test-add-button]';
export const FIELD_CLAIMS_SCOPES_DELETE_BTN =
'[name=claims_scopes] tbody td:last-child button[aria-label=Remove]';
'[name=claims_scopes] [data-test-delete-button]';
export const FIELD_ACCOUNT_CLAIM_MAPS_FROM_CLAIM =
'[name=account_claim_maps] [data-test-key-input]';
export const FIELD_ACCOUNT_CLAIM_MAPS_FROM_CLAIM_VALUE = 'from_claim';
export const FIELD_ACCOUNT_CLAIM_MAPS_TO_CLAIM =
'[name=account_claim_maps] [data-test-value-input]';
export const FIELD_ACCOUNT_CLAIM_MAPS_TO_CLAIM_VALUE = 'email';
export const FIELD_ACCOUNT_CLAIM_MAPS_DELETE_BTN = '[data-test-delete-button]';
export const FIELD_IDP_CERTS = '[name=idp_ca_certs] textarea';
export const FIELD_ACCOUNT_CLAIM_MAPS_DELETE_BTN =
'[name=account_claim_maps] [data-test-delete-button]';
export const FIELD_IDP_CERTS = '[name=idp_ca_certs] [data-test-value-input]';
export const FIELD_IDP_CERTS_VALUE = 'IDP certificates';
export const FIELD_IDP_CERTS_ADD_BTN = '[name=idp_ca_certs] button';
export const FIELD_IDP_CERTS_ADD_BTN =
'[name=idp_ca_certs] [data-test-add-button]';
export const FIELD_IDP_CERTS_DELETE_BTN =
'[name=idp_ca_certs] tbody td:last-child button[aria-label=Remove]';
'[name=idp_ca_certs] [data-test-delete-button]';
export const FIELD_MAX_AGE = '[name=max_age]';
export const FIELD_MAX_AGE_VALUE = '5';
export const FIELD_API_URL_PREFIX = '[name=api_url_prefix]';
@@ -132,7 +132,6 @@ module('Acceptance | auth-methods | update', function (hooks) {
selectors.FIELD_SIGNING_ALGORITHMS,
selectors.FIELD_SIGNING_ALGORITHMS_VALUE,
);
await click(selectors.FIELD_SIGNING_ALGORITHMS_ADD_BTN);
// Remove all allowed audiences
const allowedAudiencesList = findAll(
@@ -147,7 +146,6 @@ module('Acceptance | auth-methods | update', function (hooks) {
selectors.FIELD_ALLOWED_AUDIENCES,
selectors.FIELD_ALLOWED_AUDIENCES_VALUE,
);
await click(selectors.FIELD_ALLOWED_AUDIENCES_ADD_BTN);
// Remove all claims scopes
const claimsScopeList = await Promise.all(
@@ -162,7 +160,6 @@ module('Acceptance | auth-methods | update', function (hooks) {
selectors.FIELD_CLAIMS_SCOPES,
selectors.FIELD_CLAIMS_SCOPES_VALUE,
);
await click(selectors.FIELD_CLAIMS_SCOPES_ADD_BTN);
// Remove all claim maps
const claimMaps = await Promise.all(