Skip to content

Commit 5089a09

Browse files
committed
chore: πŸ€– yield rows to consumers
fix: πŸ› remove extra footer and undo file change chore: πŸ€– lock file fix: πŸ› test fix: πŸ› remove comment
1 parent b41a7f1 commit 5089a09

File tree

8 files changed

+361
-333
lines changed

8 files changed

+361
-333
lines changed

β€Žpnpm-lock.yamlβ€Ž

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žui/admin/app/components/form/auth-method/oidc/index.hbsβ€Ž

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,42 @@
256256
@errors={{@model.errors.account_claim_maps}}
257257
@disabled={{form.disabled}}
258258
@isOptional={{true}}
259-
@keyFieldType='text'
260-
@valueFieldType='select'
261-
@valueFieldOptions={{this.toClaims}}
262-
@keyLabel={{t 'form.from_claim.label'}}
263-
@valueLabel={{t 'form.to_claim.label'}}
264-
/>
259+
>
260+
<:row as |R|>
261+
<R.Field as |F|>
262+
<F.Label>{{t 'form.from_claim.label'}}</F.Label>
263+
<F.TextInput
264+
data-test-key-input
265+
@value={{R.rowData.key}}
266+
@isInvalid={{@model.errors.account_claim_maps}}
267+
{{on 'input' (fn R.updateAndNotify 'key')}}
268+
/>
269+
</R.Field>
270+
271+
<R.Field as |F|>
272+
<F.Label>{{t 'form.to_claim.label'}}</F.Label>
273+
<F.Select
274+
data-test-value-input
275+
@isInvalid={{@model.errors.account_claim_maps}}
276+
{{on 'change' (fn R.updateAndNotify 'value')}}
277+
>
278+
<option disabled hidden selected value=''>
279+
{{t 'titles.choose-an-option'}}
280+
</option>
281+
{{#each this.toClaims as |claim|}}
282+
<option value={{claim}} selected={{eq R.rowData.value claim}}>
283+
{{claim}}
284+
</option>
285+
{{/each}}
286+
</F.Select>
287+
</R.Field>
288+
289+
{{#if (R.hasData)}}
290+
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
291+
{{/if}}
292+
</:row>
293+
294+
</Form::Field::KeyValue>
265295

266296
{{! Certificates }}
267297
<Form::Field::ListWrapper

β€Žui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbsβ€Ž

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,34 @@
234234
@errors={{@model.errors.critical_options}}
235235
@disabled={{form.disabled}}
236236
@isOptional={{true}}
237-
@keyFieldType='text'
238-
@valueFieldType='text'
239-
/>
237+
>
238+
<:row as |R|>
239+
<R.Field as |F|>
240+
<F.Label>{{t 'form.key.label'}}</F.Label>
241+
<F.TextInput
242+
data-test-key-input
243+
@value={{R.rowData.key}}
244+
@isInvalid={{@model.errors.critical_options}}
245+
{{on 'input' (fn R.updateAndNotify 'key')}}
246+
/>
247+
</R.Field>
248+
249+
<R.Field as |F|>
250+
<F.Label>{{t 'form.value.label'}}</F.Label>
251+
<F.TextInput
252+
data-test-value-input
253+
@value={{R.rowData.value}}
254+
@isInvalid={{@model.errors.critical_options}}
255+
{{on 'input' (fn R.updateAndNotify 'value')}}
256+
/>
257+
</R.Field>
258+
259+
{{#if (R.hasData)}}
260+
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
261+
{{/if}}
262+
</:row>
263+
264+
</Form::Field::KeyValue>
240265

241266
<Form::Field::ListWrapper
242267
@layout='horizontal'

β€Žui/admin/app/components/form/field/key-value/index.hbsβ€Ž

Lines changed: 15 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,31 @@
33
SPDX-License-Identifier: BUSL-1.1
44
}}
55
<Hds::Form::KeyValueInputs
6+
name={{@name}}
67
@data={{this.data}}
78
@isRequired={{@isRequired}}
89
@isOptional={{@isOptional}}
910
disabled={{@disabled}}
1011
>
1112
<:header as |H|>
12-
{{#if @legend}}
13-
<H.Legend data-test-legend>{{@legend}}</H.Legend>
14-
{{/if}}
13+
<H.Legend data-test-legend>{{@legend}}</H.Legend>
1514
{{#if @helperText}}
1615
<H.HelperText data-test-helper-text>{{@helperText}}</H.HelperText>
1716
{{/if}}
1817
</:header>
19-
<:row as |R|>
20-
<R.Field as |F|>
21-
<F.Label>{{or @keyLabel (t 'form.key.label')}}</F.Label>
22-
{{#if (eq @keyFieldType 'select')}}
23-
<F.Select
24-
name={{@name}}
25-
disabled={{@disabled}}
26-
data-test-key-input
27-
@isInvalid={{@errors}}
28-
{{on 'change' (fn this.updateKey R.rowData)}}
29-
>
30-
<option disabled hidden selected value=''>
31-
{{t 'titles.choose-an-option'}}
32-
</option>
33-
{{#each @keyFieldOptions as |selectOption|}}
34-
<option
35-
value={{selectOption}}
36-
selected={{eq R.rowData.key selectOption}}
37-
>
38-
{{selectOption}}
39-
</option>
40-
{{/each}}
41-
</F.Select>
42-
{{else if (eq @keyFieldType 'textarea')}}
43-
<F.Textarea
44-
name={{@name}}
45-
@value={{R.rowData.key}}
46-
disabled={{@disabled}}
47-
data-test-key-input
48-
@isInvalid={{@errors}}
49-
{{on 'input' (fn this.updateKey R.rowData)}}
50-
/>
51-
{{else}}
52-
{{! Default to text input }}
53-
<F.TextInput
54-
name={{@name}}
55-
@value={{R.rowData.key}}
56-
disabled={{@disabled}}
57-
data-test-key-input
58-
@isInvalid={{@errors}}
59-
{{on 'input' (fn this.updateKey R.rowData)}}
60-
/>
61-
{{/if}}
62-
</R.Field>
63-
64-
{{#unless this.hideValueField}}
65-
<R.Field as |F|>
66-
<F.Label>{{or @valueLabel (t 'form.value.label')}}</F.Label>
67-
{{#if (eq @valueFieldType 'select')}}
68-
<F.Select
69-
name={{@name}}
70-
disabled={{@disabled}}
71-
data-test-value-input
72-
@isInvalid={{@errors}}
73-
{{on 'change' (fn this.updateValue R.rowData)}}
74-
>
75-
<option disabled hidden selected value=''>
76-
{{t 'titles.choose-an-option'}}
77-
</option>
78-
{{#each @valueFieldOptions as |selectOption|}}
79-
<option
80-
value={{selectOption}}
81-
selected={{eq R.rowData.value selectOption}}
82-
>
83-
{{selectOption}}
84-
</option>
85-
{{/each}}
86-
</F.Select>
87-
{{else if (eq @valueFieldType 'textarea')}}
88-
<F.Textarea
89-
name={{@name}}
90-
@value={{R.rowData.value}}
91-
disabled={{@disabled}}
92-
data-test-value-input
93-
@isInvalid={{@errors}}
94-
{{on 'input' (fn this.updateValue R.rowData)}}
95-
/>
96-
{{else}}
97-
{{! Default to text input }}
98-
<F.TextInput
99-
name={{@name}}
100-
@value={{R.rowData.value}}
101-
disabled={{@disabled}}
102-
data-test-value-input
103-
@isInvalid={{@errors}}
104-
{{on 'input' (fn this.updateValue R.rowData)}}
105-
/>
106-
{{/if}}
107-
</R.Field>
108-
{{/unless}}
10918

110-
<R.DeleteRowButton
111-
data-test-delete-button
112-
onclick={{fn this.removeRow R.rowData}}
113-
/>
19+
<:row as |R|>
20+
{{yield
21+
(hash
22+
Field=R.Field
23+
DeleteRowButton=R.DeleteRowButton
24+
rowData=R.rowData
25+
hasData=(fn this.hasData R.rowData)
26+
removeRow=(fn this.removeRow R.rowData)
27+
updateAndNotify=(fn this.updateAndNotify R.rowData)
28+
)
29+
to='row'
30+
}}
11431
</:row>
11532
<:footer as |F|>
11633

@@ -124,7 +41,7 @@
12441
<F.AddRowButton
12542
@text={{t 'actions.add'}}
12643
data-test-add-button
127-
onclick={{this.addNewRow}}
44+
@onClick={{this.addNewRow}}
12845
/>
12946
</:footer>
13047
</Hds::Form::KeyValueInputs>

β€Žui/admin/app/components/form/field/key-value/index.jsβ€Ž

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,13 @@ import { action } from '@ember/object';
1010
export default class FormFieldKeyValueComponent extends Component {
1111
// =properties
1212

13-
@tracked data = this.args.data?.length
14-
? [...this.args.data]
15-
: [this.createEmptyRow()];
16-
17-
/**
18-
* Determine if the value field should be shown
19-
* Defaults to false (show the value field by default)
20-
* @type {boolean}
21-
*/
22-
get hideValueField() {
23-
return this.args.hideValueField ?? false;
24-
}
25-
26-
createEmptyRow() {
27-
const row = { key: '' };
28-
if (!this.hideValueField) {
29-
row.value = '';
30-
}
31-
return row;
32-
}
13+
@tracked data = this.args.data?.length ? [...this.args.data] : [{}];
3314

3415
// =actions
3516

36-
/**
37-
* Updates the key value for a specific row and triggers change notification
38-
* @param {Object} rowData
39-
* @param {Event} event
40-
*/
41-
@action
42-
updateKey(rowData, { target: { value } }) {
43-
this.updateRowProperty(rowData, 'key', value);
44-
}
45-
46-
/**
47-
* Updates the value field for a specific row and triggers change notification
48-
* @param {Object} rowData
49-
* @param {Event} event
50-
*/
51-
@action
52-
updateValue(rowData, { target: { value } }) {
53-
this.updateRowProperty(rowData, 'value', value);
54-
}
55-
5617
@action
5718
addNewRow() {
58-
this.data = [...this.data, this.createEmptyRow()];
19+
this.data = [...this.data, {}];
5920
this.notifyChange();
6021
}
6122

@@ -65,31 +26,48 @@ export default class FormFieldKeyValueComponent extends Component {
6526

6627
// Ensure at least one row exists
6728
if (this.data.length === 0) {
68-
this.data = [this.createEmptyRow()];
29+
this.data = [{}];
6930
}
7031
this.notifyChange();
7132
}
7233

7334
/**
74-
* Helper method to update a property on a row
35+
* Action to update row data from input events and notify consumer
7536
* @param {Object} rowData - The row object to update
7637
* @param {string} property - The property name to update
7738
* @param {string} value - The new value
7839
*/
79-
updateRowProperty(rowData, property, value) {
40+
@action
41+
updateAndNotify(rowData, property, { target: { value } }) {
8042
rowData[property] = value;
8143
this.data = [...this.data];
8244
this.notifyChange();
8345
}
8446

8547
/**
86-
* Notifies parent component of data changes with filtered results
48+
* Checks if a row has any non-empty data
49+
* @param {Object} rowData - The row object to check
50+
* @returns {boolean} - True if the row has any non-empty values
51+
*/
52+
@action
53+
hasData(rowData) {
54+
if (!this.data.includes(rowData)) return false;
55+
56+
return Object.values(rowData).some(
57+
(value) => value != null && value !== '',
58+
);
59+
}
60+
61+
/**
62+
* Notifies consumer of data changes with filtered results
8763
*/
8864
notifyChange() {
89-
if (this.args.onChange) {
90-
// Filter out entries with empty/whitespace keys
91-
const filteredData = this.data.filter((item) => item.key?.trim());
92-
this.args.onChange(filteredData);
93-
}
65+
if (!this.args.onChange) return;
66+
67+
// Filter out rows where the 'key' property is empty or missing
68+
const filteredData = this.data.filter(
69+
(item) => item.key != null && item.key !== '',
70+
);
71+
this.args.onChange(filteredData);
9472
}
9573
}

β€Žui/admin/tests/acceptance/auth-methods/selectors.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ export const FIELD_CLAIMS_SCOPES_ADD_BTN = '[name=claims_scopes] button';
2626
export const FIELD_CLAIMS_SCOPES_DELETE_BTN =
2727
'[name=claims_scopes] tbody td:last-child button[aria-label=Remove]';
2828
export const FIELD_ACCOUNT_CLAIM_MAPS_FROM_CLAIM =
29-
'[name=account_claim_maps][data-test-key-input]';
29+
'[name=account_claim_maps] [data-test-key-input]';
3030
export const FIELD_ACCOUNT_CLAIM_MAPS_FROM_CLAIM_VALUE = 'from_claim';
3131
export const FIELD_ACCOUNT_CLAIM_MAPS_TO_CLAIM =
32-
'[name=account_claim_maps][data-test-value-input]';
32+
'[name=account_claim_maps] [data-test-value-input]';
3333
export const FIELD_ACCOUNT_CLAIM_MAPS_TO_CLAIM_VALUE = 'email';
3434
export const FIELD_ACCOUNT_CLAIM_MAPS_DELETE_BTN = '[data-test-delete-button]';
3535
export const FIELD_IDP_CERTS = '[name=idp_ca_certs] textarea';

β€Žui/admin/tests/acceptance/credential-library/selectors.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ export const TYPE_VAULT_LDAP = '[value="vault-ldap"]';
3333
export const TYPE_VAULT_GENERIC = '[value="vault-generic"]';
3434

3535
export const FIELD_CRIT_OPTS_KEY =
36-
'[name="critical_options"][data-test-key-input]';
36+
'[name="critical_options"] [data-test-key-input]';
3737
export const FIELD_CRIT_OPTS_VALUE =
38-
'[name="critical_options"][data-test-value-input]';
38+
'[name="critical_options"] [data-test-value-input]';
3939

4040
export const FIELD_EXT_KEY =
4141
'[name="extensions"] tbody td:nth-of-type(1) input';

0 commit comments

Comments
Β (0)