@inseefr/lunatic 3.5.1 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/components/FilterDescription/FilterDescription.d.ts +5 -7
  2. package/components/FilterDescription/FilterDescription.js +10 -3
  3. package/components/FilterDescription/FilterDescription.js.map +1 -1
  4. package/components/InputNumber/InputNumber.js +2 -2
  5. package/components/InputNumber/InputNumber.js.map +1 -1
  6. package/components/InputNumber/InputNumberThousand.d.ts +2 -1
  7. package/components/InputNumber/InputNumberThousand.js +9 -6
  8. package/components/InputNumber/InputNumberThousand.js.map +1 -1
  9. package/components/library.d.ts +2 -4
  10. package/components/shared/HOC/slottableComponent.d.ts +2 -0
  11. package/components/shared/HOC/slottableComponent.js.map +1 -1
  12. package/esm/components/FilterDescription/FilterDescription.d.ts +5 -7
  13. package/esm/components/FilterDescription/FilterDescription.js +8 -1
  14. package/esm/components/FilterDescription/FilterDescription.js.map +1 -1
  15. package/esm/components/InputNumber/InputNumber.js +2 -2
  16. package/esm/components/InputNumber/InputNumber.js.map +1 -1
  17. package/esm/components/InputNumber/InputNumberThousand.d.ts +2 -1
  18. package/esm/components/InputNumber/InputNumberThousand.js +9 -6
  19. package/esm/components/InputNumber/InputNumberThousand.js.map +1 -1
  20. package/esm/components/library.d.ts +2 -4
  21. package/esm/components/shared/HOC/slottableComponent.d.ts +2 -0
  22. package/esm/components/shared/HOC/slottableComponent.js.map +1 -1
  23. package/esm/type.source.d.ts +5 -1
  24. package/esm/use-lunatic/commons/fill-components/fill-component.spec.d.ts +1 -0
  25. package/esm/use-lunatic/commons/fill-components/fill-component.spec.js +485 -0
  26. package/esm/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -0
  27. package/esm/use-lunatic/commons/fill-components/fill-components.d.ts +3 -3
  28. package/esm/use-lunatic/commons/fill-components/fill-components.js +29 -5
  29. package/esm/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
  30. package/esm/use-lunatic/props/getComponentTypeProps.d.ts +4 -4
  31. package/esm/use-lunatic/props/getComponentTypeProps.js +1 -1
  32. package/esm/use-lunatic/props/getComponentTypeProps.js.map +1 -1
  33. package/esm/use-lunatic/props/propOptions.d.ts +1 -1
  34. package/esm/use-lunatic/props/propOptions.js +5 -3
  35. package/esm/use-lunatic/props/propOptions.js.map +1 -1
  36. package/esm/use-lunatic/props/propOptions.spec.js +100 -2
  37. package/esm/use-lunatic/props/propOptions.spec.js.map +1 -1
  38. package/esm/use-lunatic/reducer/reducerInitializer.d.ts +2 -1
  39. package/esm/use-lunatic/reducer/reducerInitializer.js +3 -3
  40. package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  41. package/esm/use-lunatic/replace-component-sequence.d.ts +1 -1
  42. package/esm/use-lunatic/type.d.ts +3 -0
  43. package/esm/use-lunatic/use-lunatic.js +3 -1
  44. package/esm/use-lunatic/use-lunatic.js.map +1 -1
  45. package/esm/utils/number.d.ts +4 -0
  46. package/esm/utils/number.js +10 -0
  47. package/esm/utils/number.js.map +1 -1
  48. package/esm/utils/number.spec.js +44 -1
  49. package/esm/utils/number.spec.js.map +1 -1
  50. package/package.json +8 -2
  51. package/src/components/FilterDescription/FilterDescription.tsx +24 -13
  52. package/src/components/InputNumber/InputNumber.tsx +2 -0
  53. package/src/components/InputNumber/InputNumberThousand.tsx +9 -4
  54. package/src/components/shared/HOC/slottableComponent.tsx +2 -0
  55. package/src/stories/behaviour/paste/test.stories.jsx +5 -0
  56. package/src/stories/filter-description/filter-description.stories.jsx +7 -3
  57. package/src/stories/loop/roster-for-loop.stories.jsx +1 -4
  58. package/src/stories/loop/source-roster.json +65 -2
  59. package/src/stories/utils/default-arg-types.js +1 -1
  60. package/src/stories/utils/orchestrator.jsx +3 -3
  61. package/src/type.source.ts +6 -1
  62. package/src/use-lunatic/commons/fill-components/fill-component.spec.ts +581 -0
  63. package/src/use-lunatic/commons/fill-components/fill-components.ts +39 -7
  64. package/src/use-lunatic/props/getComponentTypeProps.ts +15 -11
  65. package/src/use-lunatic/props/propOptions.spec.ts +140 -2
  66. package/src/use-lunatic/props/propOptions.ts +8 -3
  67. package/src/use-lunatic/reducer/reducerInitializer.tsx +4 -2
  68. package/src/use-lunatic/type.ts +5 -0
  69. package/src/use-lunatic/use-lunatic.ts +3 -0
  70. package/src/utils/number.spec.ts +45 -1
  71. package/src/utils/number.ts +18 -0
  72. package/tsconfig.build.tsbuildinfo +1 -1
  73. package/type.source.d.ts +5 -1
  74. package/use-lunatic/commons/fill-components/fill-component.spec.d.ts +1 -0
  75. package/use-lunatic/commons/fill-components/fill-component.spec.js +487 -0
  76. package/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -0
  77. package/use-lunatic/commons/fill-components/fill-components.d.ts +3 -3
  78. package/use-lunatic/commons/fill-components/fill-components.js +26 -5
  79. package/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
  80. package/use-lunatic/props/getComponentTypeProps.d.ts +4 -4
  81. package/use-lunatic/props/getComponentTypeProps.js +1 -1
  82. package/use-lunatic/props/getComponentTypeProps.js.map +1 -1
  83. package/use-lunatic/props/propOptions.d.ts +1 -1
  84. package/use-lunatic/props/propOptions.js +5 -3
  85. package/use-lunatic/props/propOptions.js.map +1 -1
  86. package/use-lunatic/props/propOptions.spec.js +100 -2
  87. package/use-lunatic/props/propOptions.spec.js.map +1 -1
  88. package/use-lunatic/reducer/reducerInitializer.d.ts +2 -1
  89. package/use-lunatic/reducer/reducerInitializer.js +3 -3
  90. package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  91. package/use-lunatic/replace-component-sequence.d.ts +1 -1
  92. package/use-lunatic/type.d.ts +3 -0
  93. package/use-lunatic/use-lunatic.js +3 -1
  94. package/use-lunatic/use-lunatic.js.map +1 -1
  95. package/utils/number.d.ts +4 -0
  96. package/utils/number.js +11 -0
  97. package/utils/number.js.map +1 -1
  98. package/utils/number.spec.js +43 -0
  99. package/utils/number.spec.js.map +1 -1
  100. package/src/stories/loop/source-with-header.json +0 -128
@@ -0,0 +1,581 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { FillComponentArgs, fillComponents } from './fill-components';
3
+ import { LunaticComponentDefinition } from '../../type';
4
+ import { LunaticVariablesStore } from '../variables/lunatic-variables-store';
5
+
6
+ const defaultMockVariables = LunaticVariablesStore.makeFromObject({
7
+ TESTTEXTE: 'Some test value',
8
+ });
9
+
10
+ const defaultMockState = {
11
+ handleChanges: vi.fn(),
12
+ executeExpression: (expression: any) => expression.value,
13
+ goToPage: vi.fn(),
14
+ goNextPage: vi.fn(),
15
+ goPreviousPage: vi.fn(),
16
+ logger: vi.fn(),
17
+ pager: { page: 1, maxPage: 1 },
18
+ variables: defaultMockVariables,
19
+ };
20
+
21
+ // in every test, filledComponents is forced to any type since the function
22
+ // fillComponent does not handle types well, returning object forced as any
23
+ describe('fillComponents', () => {
24
+ it('should fill an Input component correctly', () => {
25
+ const components = [
26
+ {
27
+ componentType: 'Input',
28
+ response: {
29
+ name: 'TESTINPUT',
30
+ },
31
+ conditionFilter: {
32
+ type: 'VTL',
33
+ value: 'true',
34
+ },
35
+ id: 'kfxn6f16',
36
+ page: '1',
37
+ label: {
38
+ type: 'VTL|MD',
39
+ value: '"Input label"',
40
+ },
41
+ mandatory: true,
42
+ maxLength: 15,
43
+ },
44
+ ];
45
+
46
+ const mockVariables = LunaticVariablesStore.makeFromObject({
47
+ TESTINPUT: 'Some test value',
48
+ });
49
+
50
+ const mockState = {
51
+ ...defaultMockState,
52
+ variables: mockVariables,
53
+ };
54
+
55
+ const filledComponents = fillComponents(
56
+ components as LunaticComponentDefinition[],
57
+ mockState as unknown as FillComponentArgs
58
+ ) as any;
59
+
60
+ const input = filledComponents[0];
61
+
62
+ expect(input.componentType).toBe('Input');
63
+ expect(input.id).toBe('kfxn6f16');
64
+ expect(input.label).toBe('"Input label"');
65
+ expect(input.response.name).toBe('TESTINPUT');
66
+ expect(input.required).toBe(true);
67
+ expect(input.maxLength).toBe(15);
68
+ expect(input.conditionFilter).toBe(true);
69
+ });
70
+
71
+ it('should fill a Radio component correctly with options', () => {
72
+ const components = [
73
+ {
74
+ id: 'radio',
75
+ componentType: 'Radio',
76
+ mandatory: false,
77
+ page: '1',
78
+ label: {
79
+ value: '"Radio label"',
80
+ type: 'VTL|MD',
81
+ },
82
+ conditionFilter: {
83
+ type: 'VTL',
84
+ value: '"true"',
85
+ },
86
+ options: [
87
+ {
88
+ value: '1',
89
+ description: {
90
+ value: '"Déclaration oui"',
91
+ type: 'VTL|MD',
92
+ },
93
+ label: {
94
+ value: '"oui"',
95
+ type: 'VTL|MD',
96
+ },
97
+ },
98
+ {
99
+ value: '2',
100
+ description: {
101
+ value: '"Déclaration non"',
102
+ type: 'VTL|MD',
103
+ },
104
+ label: {
105
+ value: '"non"',
106
+ type: 'VTL|MD',
107
+ },
108
+ },
109
+ ],
110
+ response: {
111
+ name: 'TESTRADIO',
112
+ },
113
+ },
114
+ ];
115
+
116
+ const mockVariables = LunaticVariablesStore.makeFromObject({
117
+ TESTRADIO: '1',
118
+ });
119
+
120
+ const mockState = {
121
+ ...defaultMockState,
122
+ variables: mockVariables,
123
+ };
124
+
125
+ const filledComponents = fillComponents(
126
+ components as LunaticComponentDefinition[],
127
+ mockState as unknown as FillComponentArgs
128
+ ) as any;
129
+
130
+ const radio = filledComponents[0];
131
+
132
+ expect(radio.componentType).toBe('Radio');
133
+ expect(radio.id).toBe('radio');
134
+ expect(radio.label).toBe('"Radio label"');
135
+ expect(radio.options).toHaveLength(2);
136
+ expect(radio.options[0].label).toBe('"oui"');
137
+ expect(radio.options[1].label).toBe('"non"');
138
+ expect(radio.conditionFilter).toBe(true);
139
+ expect(radio.response.name).toBe('TESTRADIO');
140
+ });
141
+
142
+ it('should fill a Question component with a child Input correctly', () => {
143
+ const components = [
144
+ {
145
+ id: 'question-m8ilvkbt',
146
+ componentType: 'Question',
147
+ page: '1',
148
+ label: {
149
+ value: '"Question label"',
150
+ type: 'VTL|MD',
151
+ },
152
+ conditionFilter: {
153
+ type: 'VTL',
154
+ value: 'true',
155
+ },
156
+ components: [
157
+ {
158
+ id: 'm8ilvkbt',
159
+ componentType: 'Input',
160
+ page: '1',
161
+ maxLength: 249,
162
+ response: {
163
+ name: 'TESTTEXTE',
164
+ },
165
+ },
166
+ ],
167
+ },
168
+ ];
169
+
170
+ const mockVariables = LunaticVariablesStore.makeFromObject({
171
+ TESTTEXTE: 'some value',
172
+ });
173
+
174
+ const mockState = {
175
+ ...defaultMockState,
176
+ variables: mockVariables,
177
+ };
178
+
179
+ const filledComponents = fillComponents(
180
+ components as LunaticComponentDefinition[],
181
+ mockState as unknown as FillComponentArgs
182
+ ) as any;
183
+
184
+ const question = filledComponents[0];
185
+
186
+ expect(question.componentType).toBe('Question');
187
+ expect(question.id).toBe('question-m8ilvkbt');
188
+ expect(question.label).toBe('"Question label"');
189
+ expect(question.conditionFilter).toBe(true);
190
+ expect(question.components.length).toBe(1);
191
+
192
+ const input = question.components[0];
193
+ expect(input.componentType).toBe('Input');
194
+ expect(input.id).toBe('m8ilvkbt');
195
+ expect(input.maxLength).toBe(249);
196
+ expect(input.response.name).toBe('TESTTEXTE');
197
+ });
198
+
199
+ it('should fill multiple components correctly', () => {
200
+ const components = [
201
+ {
202
+ id: 'input1',
203
+ componentType: 'Input',
204
+ page: '1',
205
+ maxLength: 100,
206
+ response: {
207
+ name: 'TESTINPUT',
208
+ },
209
+ label: {
210
+ type: 'VTL|MD',
211
+ value: '"Input label"',
212
+ },
213
+ conditionFilter: {
214
+ type: 'VTL',
215
+ value: 'true',
216
+ },
217
+ },
218
+ {
219
+ id: 'radio1',
220
+ componentType: 'Radio',
221
+ page: '1',
222
+ label: {
223
+ type: 'VTL|MD',
224
+ value: '"Radio label"',
225
+ },
226
+ options: [
227
+ { value: 'yes', label: { value: '"Yes"', type: 'VTL|MD' } },
228
+ { value: 'no', label: { value: '"No"', type: 'VTL|MD' } },
229
+ ],
230
+ response: {
231
+ name: 'TESTRADIO',
232
+ },
233
+ conditionFilter: {
234
+ type: 'VTL',
235
+ value: 'true',
236
+ },
237
+ },
238
+ ];
239
+
240
+ const mockVariables = LunaticVariablesStore.makeFromObject({
241
+ TESTINPUT: 'Filled input',
242
+ TESTRADIO: 'yes',
243
+ });
244
+
245
+ const mockState = {
246
+ ...defaultMockState,
247
+ variables: mockVariables,
248
+ };
249
+
250
+ const filledComponents = fillComponents(
251
+ components as LunaticComponentDefinition[],
252
+ mockState as unknown as FillComponentArgs
253
+ ) as any;
254
+
255
+ expect(filledComponents).toHaveLength(2);
256
+
257
+ const input = filledComponents[0];
258
+ expect(input.componentType).toBe('Input');
259
+ expect(input.response.name).toBe('TESTINPUT');
260
+ expect(input.maxLength).toBe(100);
261
+
262
+ const radio = filledComponents[1];
263
+ expect(radio.componentType).toBe('Radio');
264
+ expect(radio.response.name).toBe('TESTRADIO');
265
+ expect(radio.options[0].label).toBe('"Yes"');
266
+ expect(radio.options[1].label).toBe('"No"');
267
+ });
268
+
269
+ it('should filter out FilterDescription components if disableFiltersDescription is true', () => {
270
+ const components = [
271
+ {
272
+ id: 'filter-desc',
273
+ componentType: 'FilterDescription',
274
+ page: '1',
275
+ label: {
276
+ type: 'VTL|MD',
277
+ value: '"filter description"',
278
+ },
279
+ },
280
+ {
281
+ id: 'input1',
282
+ componentType: 'Input',
283
+ page: '1',
284
+ maxLength: 100,
285
+ response: {
286
+ name: 'TESTINPUT',
287
+ },
288
+ label: {
289
+ type: 'VTL|MD',
290
+ value: '"Input label"',
291
+ },
292
+ conditionFilter: {
293
+ type: 'VTL',
294
+ value: 'true',
295
+ },
296
+ },
297
+ ];
298
+
299
+ const mockVariables = LunaticVariablesStore.makeFromObject({
300
+ TESTINPUT: 'Filled input',
301
+ });
302
+
303
+ const mockState = {
304
+ ...defaultMockState,
305
+ variables: mockVariables,
306
+ disableFiltersDescription: true,
307
+ };
308
+
309
+ const filledComponents = fillComponents(
310
+ components as LunaticComponentDefinition[],
311
+ mockState as unknown as FillComponentArgs
312
+ );
313
+
314
+ expect(filledComponents).toHaveLength(1);
315
+
316
+ const input = filledComponents[0];
317
+ expect(input.componentType).toBe('Input');
318
+ });
319
+
320
+ it('should keep FilterDescription components if disableFiltersDescription is false', () => {
321
+ const components = [
322
+ {
323
+ id: 'filter-desc',
324
+ componentType: 'FilterDescription',
325
+ page: '1',
326
+ label: {
327
+ type: 'VTL|MD',
328
+ value: '"Some filter description"',
329
+ },
330
+ conditionFilter: {
331
+ type: 'VTL',
332
+ value: 'true',
333
+ },
334
+ },
335
+ {
336
+ id: 'input1',
337
+ componentType: 'Input',
338
+ page: '1',
339
+ maxLength: 100,
340
+ response: {
341
+ name: 'TESTINPUT',
342
+ },
343
+ label: {
344
+ type: 'VTL|MD',
345
+ value: '"Input label"',
346
+ },
347
+ conditionFilter: {
348
+ type: 'VTL',
349
+ value: 'true',
350
+ },
351
+ },
352
+ ];
353
+
354
+ const mockVariables = LunaticVariablesStore.makeFromObject({
355
+ TESTINPUT: 'Filled input',
356
+ });
357
+
358
+ const mockState = {
359
+ ...defaultMockState,
360
+ variables: mockVariables,
361
+ disableFiltersDescription: false,
362
+ };
363
+
364
+ const filledComponents = fillComponents(
365
+ components as LunaticComponentDefinition[],
366
+ mockState as unknown as FillComponentArgs
367
+ );
368
+
369
+ expect(filledComponents).toHaveLength(2);
370
+ expect(filledComponents[0].componentType).toBe('FilterDescription');
371
+ expect(filledComponents[1].componentType).toBe('Input');
372
+ });
373
+
374
+ it('should filter out components with conditionFilter=false when disableFilters is false or undefined', () => {
375
+ const components = [
376
+ {
377
+ id: 'input1',
378
+ componentType: 'Input',
379
+ page: '1',
380
+ response: {
381
+ name: 'TESTINPUT',
382
+ },
383
+ label: {
384
+ type: 'VTL|MD',
385
+ value: '"Should be kept even with conditionFilter false"',
386
+ },
387
+ conditionFilter: {
388
+ type: 'VTL',
389
+ // value should be string, but did not find how to execute correctly with mocks
390
+ // for having a false conditionFilter at the end
391
+ value: false,
392
+ },
393
+ },
394
+ ];
395
+
396
+ const mockVariables = LunaticVariablesStore.makeFromObject({
397
+ TESTINPUT: 'Some value',
398
+ });
399
+
400
+ const mockState = {
401
+ ...defaultMockState,
402
+ variables: mockVariables,
403
+ disableFilters: false,
404
+ };
405
+
406
+ const filledComponents = fillComponents(
407
+ components as LunaticComponentDefinition[],
408
+ mockState as unknown as FillComponentArgs
409
+ );
410
+
411
+ expect(filledComponents).toHaveLength(0);
412
+ });
413
+
414
+ it('should not filter out components with conditionFilter=false when disableFilters is true', () => {
415
+ const components = [
416
+ {
417
+ id: 'input1',
418
+ componentType: 'Input',
419
+ page: '1',
420
+ response: {
421
+ name: 'TESTINPUT',
422
+ },
423
+ label: {
424
+ type: 'VTL|MD',
425
+ value: '"Should be kept even with conditionFilter false"',
426
+ },
427
+ conditionFilter: {
428
+ type: 'VTL',
429
+ // value should be string, but did not find how to execute correctly with mocks
430
+ // for having a false conditionFilter at the end
431
+ value: false,
432
+ },
433
+ },
434
+ ];
435
+
436
+ const mockVariables = LunaticVariablesStore.makeFromObject({
437
+ TESTINPUT: 'Some value',
438
+ });
439
+
440
+ const mockState = {
441
+ ...defaultMockState,
442
+ variables: mockVariables,
443
+ disableFilters: true,
444
+ };
445
+
446
+ const filledComponents = fillComponents(
447
+ components as LunaticComponentDefinition[],
448
+ mockState as unknown as FillComponentArgs
449
+ ) as any;
450
+
451
+ expect(filledComponents).toHaveLength(1);
452
+
453
+ const input = filledComponents[0];
454
+ expect(input.id).toBe('input1');
455
+ expect(input.conditionFilter).toBe(false);
456
+ });
457
+
458
+ it('should transform components into Text with empty label when conditionFilter is false and parentType is RosterForLoop', () => {
459
+ const components = [
460
+ {
461
+ id: 'input1',
462
+ componentType: 'Input',
463
+ page: '1',
464
+ label: { value: '"Input label"', type: 'VTL|MD' },
465
+ conditionFilter: {
466
+ type: 'VTL',
467
+ // value should be string, but did not find how to execute correctly with mocks
468
+ // for having a false conditionFilter at the end
469
+ value: false,
470
+ },
471
+ response: { name: 'TESTINPUT' },
472
+ },
473
+ {
474
+ id: 'radio1',
475
+ componentType: 'Radio',
476
+ page: '1',
477
+ label: { value: '"Radio label"', type: 'VTL|MD' },
478
+ options: [
479
+ { value: 'yes', label: { value: '"Yes"', type: 'VTL|MD' } },
480
+ { value: 'no', label: { value: '"No"', type: 'VTL|MD' } },
481
+ ],
482
+ response: { name: 'TESTRADIO' },
483
+ },
484
+ ];
485
+
486
+ const mockVariables = LunaticVariablesStore.makeFromObject({
487
+ TESTINPUT: 'Filled input',
488
+ TESTRADIO: 'yes',
489
+ });
490
+
491
+ const mockState = {
492
+ ...defaultMockState,
493
+ variables: mockVariables,
494
+ };
495
+
496
+ const filledComponents = fillComponents(
497
+ components as LunaticComponentDefinition[],
498
+ mockState as unknown as FillComponentArgs,
499
+ 'RosterForLoop'
500
+ ) as any;
501
+
502
+ expect(filledComponents).toHaveLength(2);
503
+
504
+ // Check the first component that has conditionFilter: false
505
+ const input = filledComponents[0];
506
+ // The component should be transformed into a Text without label
507
+ expect(input.componentType).toBe('Text');
508
+ expect(input.label).toBe('');
509
+ expect(input.id).toBe('input1');
510
+
511
+ // Check the second component that has conditionFilter: true
512
+ const radio = filledComponents[1];
513
+ // The component should remain unchanged
514
+ expect(radio.componentType).toBe('Radio');
515
+ expect(radio.label).toBe('"Radio label"');
516
+ expect(radio.options[0].label).toBe('"Yes"');
517
+ expect(radio.options[1].label).toBe('"No"');
518
+ });
519
+
520
+ it('should never transform components into Text when disableFilters is true', () => {
521
+ const components = [
522
+ {
523
+ id: 'input1',
524
+ componentType: 'Input',
525
+ page: '1',
526
+ label: { value: '"Input label"', type: 'VTL|MD' },
527
+ conditionFilter: {
528
+ type: 'VTL',
529
+ // value should be string, but did not find how to execute correctly with mocks
530
+ // for having a false conditionFilter at the end
531
+ value: false,
532
+ },
533
+ response: { name: 'TESTINPUT' },
534
+ },
535
+ {
536
+ id: 'radio1',
537
+ componentType: 'Radio',
538
+ page: '1',
539
+ label: { value: '"Radio label"', type: 'VTL|MD' },
540
+ options: [
541
+ { value: 'yes', label: { value: '"Yes"', type: 'VTL|MD' } },
542
+ { value: 'no', label: { value: '"No"', type: 'VTL|MD' } },
543
+ ],
544
+ response: { name: 'TESTRADIO' },
545
+ },
546
+ ];
547
+
548
+ const mockVariables = LunaticVariablesStore.makeFromObject({
549
+ TESTINPUT: 'Filled input',
550
+ TESTRADIO: 'yes',
551
+ });
552
+
553
+ const mockState = {
554
+ ...defaultMockState,
555
+ disableFilters: true,
556
+ variables: mockVariables,
557
+ };
558
+
559
+ const filledComponents = fillComponents(
560
+ components as LunaticComponentDefinition[],
561
+ mockState as unknown as FillComponentArgs,
562
+ 'RosterForLoop'
563
+ ) as any;
564
+
565
+ expect(filledComponents).toHaveLength(2);
566
+
567
+ // Check the first component that has conditionFilter: false
568
+ const input = filledComponents[0];
569
+ // The component should remain unchanged
570
+ expect(input.componentType).toBe('Input');
571
+ expect(input.label).toBe('"Input label"');
572
+
573
+ // Check the second component that has conditionFilter: true
574
+ const radio = filledComponents[1];
575
+ // The component should remain unchanged
576
+ expect(radio.componentType).toBe('Radio');
577
+ expect(radio.label).toBe('"Radio label"');
578
+ expect(radio.options[0].label).toBe('"Yes"');
579
+ expect(radio.options[1].label).toBe('"No"');
580
+ });
581
+ });
@@ -14,8 +14,9 @@ import { getIterationsProp } from '../../props/propIterations';
14
14
  import { getOptionsProp } from '../../props/propOptions';
15
15
  import { LunaticLogger } from '../../logger/type';
16
16
 
17
- type FillComponentArgs = {
17
+ export type FillComponentArgs = {
18
18
  disableFilters?: boolean;
19
+ disableFiltersDescription?: true;
19
20
  handleChanges: LunaticChangesHandler;
20
21
  executeExpression: LunaticReducerState['executeExpression'];
21
22
  goToPage: LunaticState['goToPage'];
@@ -59,7 +60,8 @@ export const fillComponent = (
59
60
  state.handleChanges,
60
61
  state.pager.iteration,
61
62
  value,
62
- state.logger
63
+ state.logger,
64
+ state.disableFilters
63
65
  ),
64
66
  ...getComponentTypeProps(interpretedProps, state),
65
67
  // This is too dynamic to be typed correctly, so we allow any here
@@ -71,11 +73,41 @@ export const fillComponent = (
71
73
  */
72
74
  export function fillComponents(
73
75
  components: LunaticComponentDefinition[],
74
- state: FillComponentArgs
76
+ state: FillComponentArgs,
77
+ parentType?: LunaticComponentDefinition['componentType']
75
78
  ): LunaticComponentProps[] {
76
- return components
77
- .map((component) => fillComponent(component, state))
78
- .filter(
79
- ({ conditionFilter }) => state.disableFilters || (conditionFilter ?? true)
79
+ // Flatmap to directly remove FilterDescription components if disableFiltersDescription is true
80
+ const filledComponents = components.flatMap((component) => {
81
+ if (
82
+ component.componentType === 'FilterDescription' &&
83
+ state.disableFiltersDescription
84
+ ) {
85
+ return [];
86
+ }
87
+
88
+ return [fillComponent(component, state)];
89
+ });
90
+
91
+ if (state.disableFilters) {
92
+ return filledComponents;
93
+ }
94
+
95
+ // For rosterForLoop we want empty cell when the component is filtered
96
+ if (parentType === 'RosterForLoop') {
97
+ return filledComponents.map((filledComponent) =>
98
+ (filledComponent.conditionFilter ?? true)
99
+ ? filledComponent
100
+ : // Replace the component by an empty text component
101
+ ({
102
+ ...filledComponent,
103
+ label: '',
104
+ componentType: 'Text',
105
+ } as LunaticComponentProps)
80
106
  );
107
+ }
108
+
109
+ // Remove filtered component (conditionFilter must be true to keep a component)
110
+ return filledComponents.filter(
111
+ ({ conditionFilter }) => conditionFilter ?? true
112
+ );
81
113
  }
@@ -62,18 +62,22 @@ function getChildComponentsWithIteration(
62
62
  ) {
63
63
  return {
64
64
  getComponents: (iteration: number) =>
65
- fillComponents(component.components, {
66
- ...state,
67
- handleChanges: createChangeHandlerForIteration(
68
- state.handleChanges,
69
- iteration
70
- ),
71
- pager: {
72
- ...state.pager,
73
- iteration: iteration,
74
- subPage: 0, // Fake a subpage to simulate an iteration
65
+ fillComponents(
66
+ component.components,
67
+ {
68
+ ...state,
69
+ handleChanges: createChangeHandlerForIteration(
70
+ state.handleChanges,
71
+ iteration
72
+ ),
73
+ pager: {
74
+ ...state.pager,
75
+ iteration: iteration,
76
+ subPage: 0, // Fake a subpage to simulate an iteration
77
+ },
75
78
  },
76
- }),
79
+ component.componentType
80
+ ),
77
81
  };
78
82
  }
79
83