Skip to content

Commit 21aa8d2

Browse files
committed
More robust detection of column index
1 parent 94fcc4a commit 21aa8d2

File tree

7 files changed

+189
-17
lines changed

7 files changed

+189
-17
lines changed

cypress/e2e/date.cy.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
describe('Test date component', () => {
22

33
beforeEach(() => {
4+
cy.visit('/date');
5+
});
6+
7+
afterEach(() => {
48
const valuesFile = './cypress/yaml/date/values.yaml';
59
cy.exec(`rm -f ${valuesFile}`);
6-
7-
cy.visit('/date');
810
});
911

1012
it('date attributes', () => {

cypress/e2e/datetime.cy.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
describe('Test datetime component', () => {
22

33
beforeEach(() => {
4+
cy.visit('/datetime');
5+
});
6+
7+
afterEach(() => {
48
const valuesFile = './cypress/yaml/datetime/values.yaml';
59
cy.exec(`rm -f ${valuesFile}`);
6-
7-
cy.visit('/datetime');
810
});
911

1012
it('datetime attributes', () => {
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
describe('Conditional Choices in Tables within Pages', () => {
2+
beforeEach(() => {
3+
cy.visit('/pages_conditional_tables');
4+
});
5+
6+
afterEach(() => {
7+
cy.exec('rm -f ./cypress/yaml/pages_conditional_tables/values.yaml');
8+
cy.clearOPFS();
9+
});
10+
11+
const prefix = 'pages_component.page1.products_table';
12+
13+
it('should have correct nested field names', () => {
14+
cy.get(`select[name="${prefix}._1.category"]`).should('exist');
15+
cy.get(`select[name="${prefix}._1.product"]`).should('exist');
16+
cy.get(`input[name="${prefix}._1.quantity"]`).should('exist');
17+
18+
cy.get(`select[name="${prefix}._2.category"]`).should('exist');
19+
cy.get(`select[name="${prefix}._2.product"]`).should('exist');
20+
cy.get(`input[name="${prefix}._2.quantity"]`).should('exist');
21+
22+
cy.get(`select[name="${prefix}._3.category"]`).should('exist');
23+
cy.get(`select[name="${prefix}._3.product"]`).should('exist');
24+
cy.get(`input[name="${prefix}._3.quantity"]`).should('exist');
25+
});
26+
27+
it('should show fruit choices when category is fruits in column 1', () => {
28+
cy.get(`select[name="${prefix}._1.category"]`).select('some fruits');
29+
30+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
31+
const values = [...$options].map(o => o.value).filter(v => v !== '');
32+
expect(values).to.deep.equal(['apple', 'banana', 'orange']);
33+
});
34+
});
35+
36+
it('should show vegetable choices when category is vegetables in column 1', () => {
37+
cy.get(`select[name="${prefix}._1.category"]`).select('some vegetables');
38+
cy.wait(500);
39+
40+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
41+
const values = [...$options].map(o => o.value).filter(v => v !== '');
42+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
43+
});
44+
});
45+
46+
it('should maintain independent choices across different table columns', () => {
47+
cy.get(`select[name="${prefix}._1.category"]`).select('some fruits');
48+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
49+
const values = [...$options].map(o => o.value).filter(v => v !== '');
50+
expect(values).to.deep.equal(['apple', 'banana', 'orange']);
51+
});
52+
53+
cy.get(`select[name="${prefix}._2.category"]`).select('some vegetables');
54+
cy.get(`select[name="${prefix}._2.product"] option`).then($options => {
55+
const values = [...$options].map(o => o.value).filter(v => v !== '');
56+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
57+
});
58+
59+
// Column 1 should still show fruits
60+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
61+
const values = [...$options].map(o => o.value).filter(v => v !== '');
62+
expect(values).to.deep.equal(['apple', 'banana', 'orange']);
63+
});
64+
});
65+
66+
it('should update product choices when category is changed', () => {
67+
cy.get(`select[name="${prefix}._1.category"]`).select('some fruits');
68+
cy.get(`select[name="${prefix}._1.product"]`).select('apple');
69+
70+
cy.get(`select[name="${prefix}._1.category"]`).select('some vegetables');
71+
cy.wait(500);
72+
73+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
74+
const values = [...$options].map(o => o.value).filter(v => v !== '');
75+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
76+
});
77+
78+
cy.get(`select[name="${prefix}._1.product"]`).should('have.value', '');
79+
});
80+
81+
it('should test all three columns independently', () => {
82+
cy.get(`select[name="${prefix}._1.category"]`).select('some vegetables');
83+
cy.wait(500);
84+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
85+
const values = [...$options].map(o => o.value).filter(v => v !== '');
86+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
87+
});
88+
89+
cy.get(`select[name="${prefix}._2.category"]`).select('some vegetables');
90+
cy.wait(500);
91+
cy.get(`select[name="${prefix}._2.product"] option`).then($options => {
92+
const values = [...$options].map(o => o.value).filter(v => v !== '');
93+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
94+
});
95+
96+
cy.get(`select[name="${prefix}._3.category"]`).select('some vegetables');
97+
cy.wait(500);
98+
cy.get(`select[name="${prefix}._3.product"] option`).then($options => {
99+
const values = [...$options].map(o => o.value).filter(v => v !== '');
100+
expect(values).to.deep.equal(['carrot', 'broccoli', 'lettuce']);
101+
});
102+
});
103+
104+
it('should work with pre-filled values on initial render', () => {
105+
cy.get(`select[name="${prefix}._1.category"]`).select('some fruits');
106+
cy.get(`select[name="${prefix}._1.product"]`).select('banana');
107+
cy.get(`input[name="${prefix}._1.quantity"]`).type('5');
108+
109+
cy.get('button[name="save"]').click();
110+
cy.get('.notification > p').should('be.visible');
111+
112+
cy.visit('/pages_conditional_tables');
113+
114+
cy.get(`select[name="${prefix}._1.category"]`).should('have.value', 'some fruits');
115+
cy.get(`select[name="${prefix}._1.product"]`).should('have.value', 'banana');
116+
cy.get(`select[name="${prefix}._1.product"] option`).then($options => {
117+
const values = [...$options].map(o => o.value).filter(v => v !== '');
118+
expect(values).to.deep.equal(['apple', 'banana', 'orange']);
119+
});
120+
});
121+
});

cypress/e2e/time.cy.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
describe('Test time component', () => {
22

33
beforeEach(() => {
4+
cy.visit('/time');
5+
});
6+
7+
afterEach(() => {
48
const valuesFile = './cypress/yaml/time/values.yaml';
59
cy.exec(`rm -f ${valuesFile}`);
6-
7-
cy.visit('/time');
810
});
911

1012
it('time attributes', () => {

cypress/yaml/conditional_tables/config.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
meta:
22
title: Conditional Choices in Tables Test
3-
store: false
4-
53
form:
64
products_table:
75
type: table
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
meta:
2+
title: Conditional Choices in Tables Test
3+
form:
4+
pages_component:
5+
type: pages
6+
label: Multi-step Form
7+
headers:
8+
- "Produce page"
9+
children:
10+
page1:
11+
label: "Produce page"
12+
children:
13+
products_table:
14+
type: table
15+
label: Product Selection
16+
repeat: 3
17+
children:
18+
category:
19+
type: dropdown
20+
label: Category
21+
empty_label: "Select a category"
22+
choices:
23+
- "some fruits"
24+
- "some vegetables"
25+
product:
26+
type: dropdown
27+
label: Product
28+
empty_label: "Select a product"
29+
conditional_choices:
30+
- visible: "@.category == 'some fruits'"
31+
choices:
32+
- apple
33+
- banana
34+
- orange
35+
- visible: "@.category == 'some vegetables'"
36+
choices:
37+
- carrot
38+
- broccoli
39+
- lettuce
40+
quantity:
41+
type: numberinput
42+
label: Quantity

js_src/components/DropdownComponent.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,21 +223,26 @@ export class DropdownComponent extends BaseComponent {
223223
/**
224224
* Extract table column context from field name
225225
*
226-
* Parses field names in the format "tableName.columnIndex.fieldName"
227-
* where columnIndex is underscore-prefixed (e.g., "_1", "_2", "_3")
226+
* Finds the last segment matching ._<integer> in the dotted path,
227+
* supporting both simple ("table._1.field") and nested paths
228+
* ("page.outer_table._3.inner_table._2.field").
228229
*
229230
* @returns {Object|null} {tableName, columnIndex} or null if not in a table
230231
*/
231232
#getColumnContext() {
232-
// Parse this.config.name format: "tableName._columnIndex.fieldName"
233233
const parts = this.config.name.split('.');
234-
if (parts.length === 3 && /^_\d+$/.test(parts[1])) {
235-
return {
236-
tableName: parts[0],
237-
columnIndex: parts[1]
238-
};
234+
let colIdx = -1;
235+
for (let i = parts.length - 1; i >= 0; i--) {
236+
if (/^_\d+$/.test(parts[i])) {
237+
colIdx = i;
238+
break;
239+
}
239240
}
240-
return null;
241+
if (colIdx < 1) return null;
242+
return {
243+
tableName: parts.slice(0, colIdx).join('.'),
244+
columnIndex: parts[colIdx]
245+
};
241246
}
242247

243248
/**

0 commit comments

Comments
 (0)