@inseefr/lunatic 3.14.0-rc-delay-sequence-cleaning.0 → 4.0.0
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.
- package/esm/type.source.d.ts +10 -0
- package/esm/use-lunatic/commons/fill-components/fill-component.spec.js +7 -9
- package/esm/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
- package/esm/use-lunatic/commons/fill-components/fill-components.d.ts +2 -2
- package/esm/use-lunatic/commons/fill-components/fill-components.js +1 -2
- package/esm/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
- package/esm/use-lunatic/commons/index.d.ts +1 -0
- package/esm/use-lunatic/commons/index.js +1 -0
- package/esm/use-lunatic/commons/index.js.map +1 -1
- package/esm/use-lunatic/commons/pagination/page.js +1 -1
- package/esm/use-lunatic/commons/pagination/page.js.map +1 -1
- package/esm/use-lunatic/commons/remove-condition-filters.d.ts +12 -0
- package/esm/use-lunatic/commons/remove-condition-filters.js +78 -0
- package/esm/use-lunatic/commons/remove-condition-filters.js.map +1 -0
- package/esm/use-lunatic/commons/remove-condition-filters.spec.d.ts +1 -0
- package/esm/use-lunatic/commons/remove-condition-filters.spec.js +111 -0
- package/esm/use-lunatic/commons/remove-condition-filters.spec.js.map +1 -0
- package/esm/use-lunatic/hooks/useOverview.d.ts +1 -1
- package/esm/use-lunatic/hooks/useOverview.js +5 -7
- package/esm/use-lunatic/hooks/useOverview.js.map +1 -1
- package/esm/use-lunatic/hooks/useOverview.spec.js +13 -4
- package/esm/use-lunatic/hooks/useOverview.spec.js.map +1 -1
- package/esm/use-lunatic/props/propOptions.d.ts +1 -2
- package/esm/use-lunatic/props/propOptions.js +3 -5
- package/esm/use-lunatic/props/propOptions.js.map +1 -1
- package/esm/use-lunatic/props/propOptions.spec.js +66 -57
- package/esm/use-lunatic/props/propOptions.spec.js.map +1 -1
- package/esm/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
- package/esm/use-lunatic/reducer/reducerInitializer.js +19 -7
- package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
- package/esm/use-lunatic/type.d.ts +10 -6
- package/esm/use-lunatic/use-lunatic.js +3 -3
- package/esm/use-lunatic/use-lunatic.js.map +1 -1
- package/package.json +16 -1
- package/src/stories/behaviour/filter/filter.stories.tsx +24 -0
- package/src/stories/behaviour/filter/sourceActiveFilters.json +275 -0
- package/src/stories/utils/Orchestrator.tsx +6 -5
- package/src/type.source.ts +10 -0
- package/src/use-lunatic/commons/fill-components/fill-component.spec.ts +7 -9
- package/src/use-lunatic/commons/fill-components/fill-components.ts +8 -8
- package/src/use-lunatic/commons/index.ts +4 -0
- package/src/use-lunatic/commons/pagination/page.ts +1 -1
- package/src/use-lunatic/commons/remove-condition-filters.spec.ts +131 -0
- package/src/use-lunatic/commons/remove-condition-filters.ts +103 -0
- package/src/use-lunatic/hooks/useOverview.spec.ts +15 -4
- package/src/use-lunatic/hooks/useOverview.ts +5 -20
- package/src/use-lunatic/props/propOptions.spec.ts +83 -60
- package/src/use-lunatic/props/propOptions.ts +2 -8
- package/src/use-lunatic/reducer/reducerInitializer.tsx +23 -8
- package/src/use-lunatic/type.ts +27 -23
- package/src/use-lunatic/use-lunatic.test.ts +9 -9
- package/src/use-lunatic/use-lunatic.ts +6 -6
- package/tsconfig.build.tsbuildinfo +1 -1
- package/type.source.d.ts +10 -0
- package/use-lunatic/commons/fill-components/fill-component.spec.js +7 -9
- package/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
- package/use-lunatic/commons/fill-components/fill-components.d.ts +2 -2
- package/use-lunatic/commons/fill-components/fill-components.js +1 -2
- package/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
- package/use-lunatic/commons/index.d.ts +1 -0
- package/use-lunatic/commons/index.js +4 -1
- package/use-lunatic/commons/index.js.map +1 -1
- package/use-lunatic/commons/pagination/page.js +1 -1
- package/use-lunatic/commons/pagination/page.js.map +1 -1
- package/use-lunatic/commons/remove-condition-filters.d.ts +12 -0
- package/use-lunatic/commons/remove-condition-filters.js +81 -0
- package/use-lunatic/commons/remove-condition-filters.js.map +1 -0
- package/use-lunatic/commons/remove-condition-filters.spec.d.ts +1 -0
- package/use-lunatic/commons/remove-condition-filters.spec.js +113 -0
- package/use-lunatic/commons/remove-condition-filters.spec.js.map +1 -0
- package/use-lunatic/hooks/useOverview.d.ts +1 -1
- package/use-lunatic/hooks/useOverview.js +5 -7
- package/use-lunatic/hooks/useOverview.js.map +1 -1
- package/use-lunatic/hooks/useOverview.spec.js +13 -4
- package/use-lunatic/hooks/useOverview.spec.js.map +1 -1
- package/use-lunatic/props/propOptions.d.ts +1 -2
- package/use-lunatic/props/propOptions.js +3 -5
- package/use-lunatic/props/propOptions.js.map +1 -1
- package/use-lunatic/props/propOptions.spec.js +66 -57
- package/use-lunatic/props/propOptions.spec.js.map +1 -1
- package/use-lunatic/reducer/reducerInitializer.d.ts +2 -2
- package/use-lunatic/reducer/reducerInitializer.js +19 -7
- package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
- package/use-lunatic/type.d.ts +10 -6
- package/use-lunatic/use-lunatic.js +3 -3
- package/use-lunatic/use-lunatic.js.map +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ComponentDefinition } from '../../type.source';
|
|
2
|
+
import type { ActiveFilter, LunaticExpression, LunaticSource } from '../type';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Decide if a conditionFilter must be kept, depending on the active filters mode.
|
|
6
|
+
* - "ALL": Keep every filter
|
|
7
|
+
* - "EXTERNAL": Keep filters based only on external variables
|
|
8
|
+
* - "NONE": Ignore every filter
|
|
9
|
+
*/
|
|
10
|
+
export function shouldKeepFilter(
|
|
11
|
+
filter: LunaticExpression | undefined,
|
|
12
|
+
activeFilters: ActiveFilter
|
|
13
|
+
): boolean {
|
|
14
|
+
if (!filter) return true;
|
|
15
|
+
if (activeFilters === 'ALL') return true;
|
|
16
|
+
if (activeFilters === 'NONE') return false;
|
|
17
|
+
// For external active filter we have to check dependencies and remove any filter based on collected or calculated variables
|
|
18
|
+
const dependencies = filter.variablesDependencies;
|
|
19
|
+
return Boolean(
|
|
20
|
+
dependencies &&
|
|
21
|
+
(dependencies.COLLECTED?.length ?? 0) === 0 &&
|
|
22
|
+
(dependencies.CALCULATED?.length ?? 0) === 0
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Compare the existing element against the outcome of the filtering function
|
|
28
|
+
* and remove it from the source if needed
|
|
29
|
+
*/
|
|
30
|
+
const removeFilterIfChanged = <T>(
|
|
31
|
+
elements: T[],
|
|
32
|
+
cleanFilterFunction: (element: T) => T
|
|
33
|
+
): T[] => {
|
|
34
|
+
const cleaned = elements.map((element) => cleanFilterFunction(element));
|
|
35
|
+
return cleaned.some((element, index) => element !== elements[index])
|
|
36
|
+
? cleaned
|
|
37
|
+
: elements;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Remove filters from source based from activeFilters props
|
|
42
|
+
*/
|
|
43
|
+
export function removeConditionFilters(
|
|
44
|
+
source: LunaticSource,
|
|
45
|
+
activeFilters: ActiveFilter
|
|
46
|
+
): LunaticSource {
|
|
47
|
+
if (activeFilters === 'ALL') {
|
|
48
|
+
return source;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Element that can have a condition filter
|
|
52
|
+
// Component is too dynamic to be typed
|
|
53
|
+
const cleanSingleElement = <T extends object>(element: T): T => {
|
|
54
|
+
if (
|
|
55
|
+
'conditionFilter' in element &&
|
|
56
|
+
!shouldKeepFilter(
|
|
57
|
+
element.conditionFilter as LunaticExpression | undefined,
|
|
58
|
+
activeFilters
|
|
59
|
+
)
|
|
60
|
+
) {
|
|
61
|
+
const rest = { ...element };
|
|
62
|
+
delete rest.conditionFilter;
|
|
63
|
+
return rest as T;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return element;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const cleanComponents = <T extends ComponentDefinition>(component: T): T => {
|
|
70
|
+
let current = cleanSingleElement(component);
|
|
71
|
+
if ('components' in current && Array.isArray(current.components)) {
|
|
72
|
+
const components = removeFilterIfChanged(
|
|
73
|
+
current.components,
|
|
74
|
+
cleanComponents
|
|
75
|
+
);
|
|
76
|
+
if (components !== current.components) {
|
|
77
|
+
current = { ...current, components } as T;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if ('responses' in current && Array.isArray(current.responses)) {
|
|
81
|
+
const currentResponses = current.responses;
|
|
82
|
+
const responses = removeFilterIfChanged(
|
|
83
|
+
currentResponses,
|
|
84
|
+
cleanSingleElement
|
|
85
|
+
);
|
|
86
|
+
if (responses !== currentResponses) {
|
|
87
|
+
current = { ...current, responses } as T;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if ('options' in current && Array.isArray(current.options)) {
|
|
91
|
+
const currentOptions = current.options
|
|
92
|
+
const options = removeFilterIfChanged(currentOptions, cleanSingleElement);
|
|
93
|
+
if (options !== currentOptions) {
|
|
94
|
+
current = { ...current, options } as T;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return current;
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
...source,
|
|
101
|
+
components: source.components.map(cleanComponents),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -6,7 +6,7 @@ import { useLunatic } from '../use-lunatic';
|
|
|
6
6
|
import { dataFromObject } from '../../utils/object';
|
|
7
7
|
|
|
8
8
|
describe('use-overview test with useLunatic()', () => {
|
|
9
|
-
it('should initialize correctly with
|
|
9
|
+
it('should initialize correctly with all filters active (without data)', () => {
|
|
10
10
|
const params = [
|
|
11
11
|
source as any,
|
|
12
12
|
dataFromObject({}),
|
|
@@ -16,7 +16,7 @@ describe('use-overview test with useLunatic()', () => {
|
|
|
16
16
|
expect(result.current.overview.length).toBe(3);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('should initialize correctly with
|
|
19
|
+
it('should initialize correctly with all filters active (with data)', () => {
|
|
20
20
|
const params = [
|
|
21
21
|
source as any,
|
|
22
22
|
dataFromObject({
|
|
@@ -29,15 +29,26 @@ describe('use-overview test with useLunatic()', () => {
|
|
|
29
29
|
expect(result.current.overview.length).toBe(9);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('should
|
|
32
|
+
it('should show filtered items when activeFilters is NONE', () => {
|
|
33
33
|
const params = [
|
|
34
34
|
source as any,
|
|
35
35
|
dataFromObject({}),
|
|
36
|
-
{ withOverview: true,
|
|
36
|
+
{ withOverview: true, activeFilters: 'NONE' },
|
|
37
37
|
] as const;
|
|
38
38
|
|
|
39
39
|
const { result } = renderHook(() => useLunatic(...params));
|
|
40
40
|
// All elements have to be presents
|
|
41
41
|
expect(result.current.overview.length).toBe(9);
|
|
42
42
|
});
|
|
43
|
+
|
|
44
|
+
it('should show items without external-only filter dependencies when activeFilters is EXTERNAL', () => {
|
|
45
|
+
const params = [
|
|
46
|
+
source as any,
|
|
47
|
+
dataFromObject({}),
|
|
48
|
+
{ withOverview: true, activeFilters: 'EXTERNAL' },
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
const { result } = renderHook(() => useLunatic(...params));
|
|
52
|
+
expect(result.current.overview.length).toBe(9);
|
|
53
|
+
});
|
|
43
54
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
LunaticOptions,
|
|
3
2
|
LunaticOverviewItem,
|
|
4
3
|
LunaticReducerState,
|
|
5
4
|
PageTag,
|
|
@@ -30,23 +29,13 @@ export const useOverview = (
|
|
|
30
29
|
overview,
|
|
31
30
|
executeExpression,
|
|
32
31
|
pager,
|
|
33
|
-
|
|
34
|
-
}: Pick<
|
|
35
|
-
LunaticReducerState,
|
|
36
|
-
'executeExpression' | 'overview' | 'pager' | 'options'
|
|
37
|
-
>,
|
|
32
|
+
}: Pick<LunaticReducerState, 'executeExpression' | 'overview' | 'pager'>,
|
|
38
33
|
deps: DependencyList
|
|
39
34
|
) => {
|
|
40
35
|
return useMemo(
|
|
41
|
-
() =>
|
|
42
|
-
interpretOverview(
|
|
43
|
-
overview,
|
|
44
|
-
executeExpression,
|
|
45
|
-
pager,
|
|
46
|
-
options.disableFilters
|
|
47
|
-
),
|
|
36
|
+
() => interpretOverview(overview, executeExpression, pager),
|
|
48
37
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
49
|
-
[...deps, overview
|
|
38
|
+
[...deps, overview]
|
|
50
39
|
);
|
|
51
40
|
};
|
|
52
41
|
|
|
@@ -56,15 +45,13 @@ export const useOverview = (
|
|
|
56
45
|
const interpretOverview = (
|
|
57
46
|
overviewItems: LunaticOverviewItem[],
|
|
58
47
|
executeExpression: LunaticReducerState['executeExpression'],
|
|
59
|
-
pager?: LunaticReducerState['pager']
|
|
60
|
-
disableFilters?: LunaticOptions['disableFilters']
|
|
48
|
+
pager?: LunaticReducerState['pager']
|
|
61
49
|
) => {
|
|
62
50
|
// Flat structure of the overview
|
|
63
51
|
let items = overviewItems.reduce(
|
|
64
52
|
(acc, item) =>
|
|
65
53
|
interpretOverviewItem(acc, item, executeExpression, {
|
|
66
54
|
pager,
|
|
67
|
-
disableFilters,
|
|
68
55
|
}),
|
|
69
56
|
[] as InterpretedLunaticOverviewItem[]
|
|
70
57
|
);
|
|
@@ -99,7 +86,6 @@ const interpretOverviewItem = (
|
|
|
99
86
|
executeExpression: LunaticReducerState['executeExpression'],
|
|
100
87
|
state: {
|
|
101
88
|
pager?: LunaticReducerState['pager'];
|
|
102
|
-
disableFilters?: LunaticOptions['disableFilters'];
|
|
103
89
|
},
|
|
104
90
|
|
|
105
91
|
iteration?: number
|
|
@@ -115,9 +101,8 @@ const interpretOverviewItem = (
|
|
|
115
101
|
);
|
|
116
102
|
}
|
|
117
103
|
|
|
118
|
-
// if disableFilters is set to true, item are visible and reached by default
|
|
119
104
|
const isVisible = (() => {
|
|
120
|
-
if (
|
|
105
|
+
if (!item.conditionFilter) return true;
|
|
121
106
|
return Boolean(
|
|
122
107
|
executeExpression(item.conditionFilter, {
|
|
123
108
|
iteration: iteration,
|
|
@@ -5,7 +5,9 @@ import type { DeepTranslateExpression } from '../commons/fill-components/fill-co
|
|
|
5
5
|
import type {
|
|
6
6
|
LunaticChangesHandler,
|
|
7
7
|
LunaticComponentDefinition,
|
|
8
|
+
LunaticSource,
|
|
8
9
|
} from '../type';
|
|
10
|
+
import { removeConditionFilters } from '../commons/remove-condition-filters';
|
|
9
11
|
|
|
10
12
|
describe('computeOptionsFromComponent', () => {
|
|
11
13
|
let variables: LunaticVariablesStore;
|
|
@@ -318,7 +320,7 @@ describe('computeOptionsFromComponent', () => {
|
|
|
318
320
|
expect(options).toHaveLength(1);
|
|
319
321
|
expect(options[0].shouldBeFiltered).toBe(false);
|
|
320
322
|
});
|
|
321
|
-
it('should
|
|
323
|
+
it('should keep responses after NONE filters have been removed during initialization', () => {
|
|
322
324
|
const definition = {
|
|
323
325
|
...checkboxGroupDefinition,
|
|
324
326
|
responses: [
|
|
@@ -331,26 +333,27 @@ describe('computeOptionsFromComponent', () => {
|
|
|
331
333
|
],
|
|
332
334
|
} satisfies DeepTranslateExpression<LunaticComponentDefinition>;
|
|
333
335
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
336
|
+
const cleanedDefinition = removeConditionFilters(
|
|
337
|
+
{
|
|
338
|
+
variables: [],
|
|
339
|
+
components: [definition as any],
|
|
340
|
+
} as LunaticSource,
|
|
341
|
+
'NONE'
|
|
342
|
+
)
|
|
343
|
+
.components[0] as unknown as DeepTranslateExpression<LunaticComponentDefinition>;
|
|
344
|
+
|
|
345
|
+
const options = computeOptionsFromComponent(cleanedDefinition, {
|
|
340
346
|
variables,
|
|
341
347
|
handleChanges: mockChange,
|
|
342
348
|
pagerIteration: undefined,
|
|
343
349
|
value: undefined,
|
|
344
350
|
logger: mockLogger,
|
|
345
|
-
disableFilters: true,
|
|
346
351
|
});
|
|
347
352
|
|
|
348
|
-
// Ensure the option is not filtered
|
|
349
353
|
expect(options).toHaveLength(1);
|
|
350
|
-
|
|
351
|
-
expect(options[0].shouldBeFiltered).toBe(true);
|
|
354
|
+
expect(options[0].shouldBeFiltered).toBe(false);
|
|
352
355
|
});
|
|
353
|
-
it('should
|
|
356
|
+
it('should keep options after NONE filters have been removed during initialization', () => {
|
|
354
357
|
const definition = {
|
|
355
358
|
...radioDefinition,
|
|
356
359
|
options: [
|
|
@@ -362,79 +365,99 @@ describe('computeOptionsFromComponent', () => {
|
|
|
362
365
|
],
|
|
363
366
|
} as any as DeepTranslateExpression<LunaticComponentDefinition>;
|
|
364
367
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
const cleanedDefinition = removeConditionFilters(
|
|
369
|
+
{
|
|
370
|
+
variables: [],
|
|
371
|
+
components: [definition as any],
|
|
372
|
+
} as LunaticSource,
|
|
373
|
+
'NONE'
|
|
374
|
+
)
|
|
375
|
+
.components[0] as unknown as DeepTranslateExpression<LunaticComponentDefinition>;
|
|
376
|
+
|
|
377
|
+
const options = computeOptionsFromComponent(cleanedDefinition, {
|
|
371
378
|
variables,
|
|
372
379
|
handleChanges: mockChange,
|
|
373
380
|
pagerIteration: undefined,
|
|
374
381
|
value: undefined,
|
|
375
382
|
logger: mockLogger,
|
|
376
|
-
disableFilters: true,
|
|
377
383
|
});
|
|
378
384
|
|
|
379
|
-
// Ensure the option is not filtered
|
|
380
385
|
expect(options).toHaveLength(1);
|
|
381
|
-
|
|
382
|
-
expect(options[0].shouldBeFiltered).toBe(true);
|
|
386
|
+
expect(options[0].shouldBeFiltered).toBe(false);
|
|
383
387
|
});
|
|
384
|
-
it('should set the response (CheckboxGroup) shouldBeFiltered=true when the parent component should be filtered', () => {
|
|
385
|
-
const definition = {
|
|
386
|
-
...checkboxGroupDefinition,
|
|
387
|
-
responses: [
|
|
388
|
-
{
|
|
389
|
-
label: 'Option 1',
|
|
390
|
-
response: { name: 'O1' },
|
|
391
|
-
id: 'id1',
|
|
392
|
-
conditionFilter: { type: 'VTL', value: 'expression' },
|
|
393
|
-
},
|
|
394
|
-
],
|
|
395
|
-
} satisfies DeepTranslateExpression<LunaticComponentDefinition>;
|
|
396
|
-
|
|
397
|
-
const options = computeOptionsFromComponent(definition, {
|
|
398
|
-
variables,
|
|
399
|
-
handleChanges: mockChange,
|
|
400
|
-
pagerIteration: undefined,
|
|
401
|
-
value: undefined,
|
|
402
|
-
logger: mockLogger,
|
|
403
|
-
disableFilters: true,
|
|
404
|
-
shouldParentBeFiltered: true,
|
|
405
|
-
});
|
|
406
388
|
|
|
407
|
-
|
|
408
|
-
expect(options).toHaveLength(1);
|
|
409
|
-
// the option would have been filtered if we did not disable filters because its parent would
|
|
410
|
-
expect(options[0].shouldBeFiltered).toBe(true);
|
|
411
|
-
});
|
|
412
|
-
it('should set the option (Radio) shouldBeFiltered=true when the parent component should be filtered', () => {
|
|
389
|
+
it('should evaluate the external-only filters retained during initialization', () => {
|
|
413
390
|
const definition = {
|
|
414
391
|
...radioDefinition,
|
|
415
392
|
options: [
|
|
416
393
|
{
|
|
417
|
-
label: '
|
|
418
|
-
value: '
|
|
419
|
-
conditionFilter: {
|
|
394
|
+
label: 'External option',
|
|
395
|
+
value: 'external',
|
|
396
|
+
conditionFilter: {
|
|
397
|
+
type: 'VTL',
|
|
398
|
+
value: 'externalFilter',
|
|
399
|
+
variablesDependencies: {
|
|
400
|
+
EXTERNAL: ['CADRE'],
|
|
401
|
+
COLLECTED: [],
|
|
402
|
+
CALCULATED: [],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
label: 'Collected option',
|
|
408
|
+
value: 'collected',
|
|
409
|
+
conditionFilter: {
|
|
410
|
+
type: 'VTL',
|
|
411
|
+
value: 'collectedFilter',
|
|
412
|
+
variablesDependencies: {
|
|
413
|
+
EXTERNAL: [],
|
|
414
|
+
COLLECTED: ['NAME'],
|
|
415
|
+
CALCULATED: [],
|
|
416
|
+
},
|
|
417
|
+
},
|
|
420
418
|
},
|
|
421
419
|
],
|
|
422
420
|
} as any as DeepTranslateExpression<LunaticComponentDefinition>;
|
|
423
421
|
|
|
424
|
-
const
|
|
422
|
+
const cleanedDefinition = removeConditionFilters(
|
|
423
|
+
{
|
|
424
|
+
variables: [],
|
|
425
|
+
components: [definition as any],
|
|
426
|
+
} as LunaticSource,
|
|
427
|
+
'EXTERNAL'
|
|
428
|
+
)
|
|
429
|
+
.components[0] as unknown as DeepTranslateExpression<LunaticComponentDefinition>;
|
|
430
|
+
expect((cleanedDefinition as any).options).toEqual([
|
|
431
|
+
{
|
|
432
|
+
label: 'External option',
|
|
433
|
+
value: 'external',
|
|
434
|
+
conditionFilter: {
|
|
435
|
+
type: 'VTL',
|
|
436
|
+
value: 'externalFilter',
|
|
437
|
+
variablesDependencies: {
|
|
438
|
+
EXTERNAL: ['CADRE'],
|
|
439
|
+
COLLECTED: [],
|
|
440
|
+
CALCULATED: [],
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
{ label: 'Collected option', value: 'collected' },
|
|
445
|
+
]);
|
|
446
|
+
vi.spyOn(variables, 'run').mockImplementation(
|
|
447
|
+
(expression) => expression !== 'externalFilter'
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
const options = computeOptionsFromComponent(cleanedDefinition, {
|
|
425
451
|
variables,
|
|
426
452
|
handleChanges: mockChange,
|
|
427
453
|
pagerIteration: undefined,
|
|
428
454
|
value: undefined,
|
|
429
455
|
logger: mockLogger,
|
|
430
|
-
disableFilters: true,
|
|
431
|
-
shouldParentBeFiltered: true,
|
|
432
456
|
});
|
|
433
457
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
expect(options[0].shouldBeFiltered).toBe(true);
|
|
458
|
+
expect(
|
|
459
|
+
(options as InterpretedOption[]).map((option) => option.value)
|
|
460
|
+
).toEqual(['collected']);
|
|
438
461
|
});
|
|
439
462
|
});
|
|
440
463
|
|
|
@@ -36,7 +36,6 @@ export function computeOptionsFromComponent(
|
|
|
36
36
|
pagerIteration,
|
|
37
37
|
value,
|
|
38
38
|
logger,
|
|
39
|
-
disableFilters,
|
|
40
39
|
shouldParentBeFiltered,
|
|
41
40
|
}: {
|
|
42
41
|
variables: LunaticVariablesStore;
|
|
@@ -44,7 +43,6 @@ export function computeOptionsFromComponent(
|
|
|
44
43
|
pagerIteration: LunaticState['pager']['iteration'];
|
|
45
44
|
value: unknown;
|
|
46
45
|
logger: LunaticLogger;
|
|
47
|
-
disableFilters?: boolean;
|
|
48
46
|
shouldParentBeFiltered?: boolean;
|
|
49
47
|
}
|
|
50
48
|
) {
|
|
@@ -53,7 +51,7 @@ export function computeOptionsFromComponent(
|
|
|
53
51
|
if (definition.componentType === 'CheckboxGroup') {
|
|
54
52
|
return definition.responses
|
|
55
53
|
.filter((response) => {
|
|
56
|
-
if (
|
|
54
|
+
if (!response.conditionFilter) {
|
|
57
55
|
return true;
|
|
58
56
|
}
|
|
59
57
|
return !isFilteredOutOption(
|
|
@@ -118,11 +116,7 @@ export function computeOptionsFromComponent(
|
|
|
118
116
|
|
|
119
117
|
return definition.options
|
|
120
118
|
.filter((option) => {
|
|
121
|
-
if (
|
|
122
|
-
disableFilters ||
|
|
123
|
-
!('conditionFilter' in option) ||
|
|
124
|
-
!option.conditionFilter
|
|
125
|
-
) {
|
|
119
|
+
if (!('conditionFilter' in option) || !option.conditionFilter) {
|
|
126
120
|
return true;
|
|
127
121
|
}
|
|
128
122
|
return !isFilteredOutOption(
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from '../type';
|
|
7
7
|
import { LunaticVariablesStore } from '../commons/variables/lunatic-variables-store';
|
|
8
8
|
import { checkLoops, createMapPages } from '../commons';
|
|
9
|
+
import { removeConditionFilters } from '../commons/remove-condition-filters';
|
|
9
10
|
import { getExpressionAsString, getExpressionType } from '../../utils/vtl';
|
|
10
11
|
import { MD, VTL } from '../../utils/constants';
|
|
11
12
|
import { MDLabel } from '../../components/shared/MDLabel/MDLabel';
|
|
@@ -35,7 +36,10 @@ const baseState = {
|
|
|
35
36
|
overview: [],
|
|
36
37
|
updateBindings: () => {},
|
|
37
38
|
executeExpression: <T,>() => null as T,
|
|
38
|
-
options: {
|
|
39
|
+
options: {
|
|
40
|
+
activeFilters: 'ALL',
|
|
41
|
+
disableFiltersDescription: true,
|
|
42
|
+
},
|
|
39
43
|
} satisfies LunaticReducerState;
|
|
40
44
|
|
|
41
45
|
const onChange = { current: () => {} };
|
|
@@ -47,8 +51,8 @@ export function reducerInitializer({
|
|
|
47
51
|
initialPage = '1',
|
|
48
52
|
lastReachedPage = undefined,
|
|
49
53
|
withOverview = false,
|
|
50
|
-
disableFilters = false,
|
|
51
54
|
disableFiltersDescription = true,
|
|
55
|
+
activeFilters,
|
|
52
56
|
getReferentiel,
|
|
53
57
|
onVariableChange = onChange,
|
|
54
58
|
logger = console.error,
|
|
@@ -59,18 +63,26 @@ export function reducerInitializer({
|
|
|
59
63
|
initialPage?: LunaticOptions['initialPage'];
|
|
60
64
|
lastReachedPage?: LunaticOptions['lastReachedPage'];
|
|
61
65
|
withOverview?: LunaticOptions['withOverview'];
|
|
62
|
-
disableFilters?: LunaticOptions['disableFilters'];
|
|
63
66
|
disableFiltersDescription?: LunaticOptions['disableFiltersDescription'];
|
|
67
|
+
activeFilters?: LunaticOptions['activeFilters'];
|
|
64
68
|
getReferentiel?: LunaticOptions['getReferentiel'];
|
|
65
69
|
onVariableChange?: RefObject<LunaticOptions['onVariableChange']>;
|
|
66
70
|
logger?: LunaticLogger;
|
|
67
71
|
}): LunaticReducerState {
|
|
68
|
-
const
|
|
72
|
+
const filteredSource =
|
|
73
|
+
activeFilters && activeFilters !== 'ALL'
|
|
74
|
+
? removeConditionFilters(source, activeFilters)
|
|
75
|
+
: source;
|
|
76
|
+
|
|
77
|
+
// Cleaning is disabled if not all filters are active.
|
|
78
|
+
const disableCleaning =
|
|
79
|
+
activeFilters !== undefined && activeFilters !== 'ALL';
|
|
80
|
+
const variables = LunaticVariablesStore.makeFromSource(filteredSource, data, {
|
|
69
81
|
autoCommit: false,
|
|
70
82
|
changeHandler: onVariableChange,
|
|
71
|
-
disableCleaning:
|
|
83
|
+
disableCleaning: disableCleaning,
|
|
72
84
|
});
|
|
73
|
-
const pages = checkLoops(createMapPages(
|
|
85
|
+
const pages = checkLoops(createMapPages(filteredSource));
|
|
74
86
|
|
|
75
87
|
if (!source || !data) {
|
|
76
88
|
return baseState;
|
|
@@ -151,10 +163,13 @@ export function reducerInitializer({
|
|
|
151
163
|
pages,
|
|
152
164
|
isInLoop: pager.subPage !== undefined,
|
|
153
165
|
updatedAt: Date.now(),
|
|
154
|
-
overview: withOverview ? buildOverview(
|
|
166
|
+
overview: withOverview ? buildOverview(filteredSource) : [],
|
|
155
167
|
updateBindings,
|
|
156
168
|
executeExpression,
|
|
157
|
-
options: {
|
|
169
|
+
options: {
|
|
170
|
+
activeFilters: activeFilters ?? 'ALL',
|
|
171
|
+
disableFiltersDescription,
|
|
172
|
+
},
|
|
158
173
|
});
|
|
159
174
|
}
|
|
160
175
|
|
package/src/use-lunatic/type.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type LunaticError = Pick<
|
|
|
59
59
|
|
|
60
60
|
export type VariableType = 'COLLECTED' | 'EXTERNAL' | 'CALCULATED';
|
|
61
61
|
export type LunaticExpression = VTLExpression | VTLScalarExpression;
|
|
62
|
+
export type ActiveFilter = 'ALL' | 'EXTERNAL' | 'NONE';
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
65
|
* Page numerotation.
|
|
@@ -142,22 +143,22 @@ export type LunaticReducerState = {
|
|
|
142
143
|
pager: LunaticPager;
|
|
143
144
|
pages: {
|
|
144
145
|
[key: number | string]:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
146
|
+
| {
|
|
147
|
+
components: LunaticSource['components'];
|
|
148
|
+
isLoop: false;
|
|
149
|
+
iterations?: undefined;
|
|
150
|
+
loopDependencies?: undefined;
|
|
151
|
+
subPages?: undefined;
|
|
152
|
+
}
|
|
153
|
+
| {
|
|
154
|
+
components: LunaticSource['components'];
|
|
155
|
+
isLoop: true;
|
|
156
|
+
iterations: VTLScalarExpression;
|
|
157
|
+
/** Variables affecting this loop. */
|
|
158
|
+
loopDependencies: string[];
|
|
159
|
+
/** List of child pages (ex: ['20.1', '20.2'] */
|
|
160
|
+
subPages: string[];
|
|
161
|
+
};
|
|
161
162
|
};
|
|
162
163
|
/** Run an expression using the value from the state. */
|
|
163
164
|
executeExpression: <T = unknown>(
|
|
@@ -178,25 +179,28 @@ export type LunaticReducerState = {
|
|
|
178
179
|
options: { iteration?: number[] }
|
|
179
180
|
) => unknown;
|
|
180
181
|
options: {
|
|
181
|
-
disableFilters?: boolean;
|
|
182
182
|
disableFiltersDescription?: boolean;
|
|
183
|
+
activeFilters?: ActiveFilter;
|
|
183
184
|
};
|
|
184
185
|
};
|
|
185
186
|
|
|
186
187
|
/** Specific behaviour options defined in the {@link useLunatic} hook. */
|
|
187
188
|
export type LunaticOptions = {
|
|
188
|
-
/**
|
|
189
|
-
* Ignore filters.
|
|
190
|
-
* @default false
|
|
191
|
-
*/
|
|
192
|
-
disableFilters?: boolean;
|
|
193
|
-
|
|
194
189
|
/**
|
|
195
190
|
* Disable filters description.
|
|
196
191
|
* @default true
|
|
197
192
|
*/
|
|
198
193
|
disableFiltersDescription?: boolean;
|
|
199
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Decides whether or not filters are active.
|
|
197
|
+
* - "ALL": Keep every filters
|
|
198
|
+
* - "EXTERNAL": Keep filter only if it is based on external variables only
|
|
199
|
+
* - "NONE": Ignore every filters
|
|
200
|
+
* @default 'ALL'
|
|
201
|
+
*/
|
|
202
|
+
activeFilters?: ActiveFilter;
|
|
203
|
+
|
|
200
204
|
/** Enable VTL and Markdown support. */
|
|
201
205
|
features?: ('MD' | 'VTL')[];
|
|
202
206
|
preferences?: ['COLLECTED'];
|
|
@@ -240,8 +240,8 @@ describe('use-lunatic()', () => {
|
|
|
240
240
|
});
|
|
241
241
|
});
|
|
242
242
|
|
|
243
|
-
describe('
|
|
244
|
-
const
|
|
243
|
+
describe('active filters', () => {
|
|
244
|
+
const lunaticConfiguration = {
|
|
245
245
|
management: false,
|
|
246
246
|
activeControls: false,
|
|
247
247
|
initialPage: '1' as PageTag,
|
|
@@ -258,29 +258,29 @@ describe('use-lunatic()', () => {
|
|
|
258
258
|
useLunatic(
|
|
259
259
|
sourceLogement,
|
|
260
260
|
undefined,
|
|
261
|
-
|
|
261
|
+
lunaticConfiguration
|
|
262
262
|
)
|
|
263
263
|
);
|
|
264
264
|
act(() => result.current.goToPage({ page: '3' }));
|
|
265
265
|
const currentPage = result.current.pageTag;
|
|
266
266
|
expect(currentPage).not.toBe('3');
|
|
267
267
|
});
|
|
268
|
-
it('should filter out some components when
|
|
268
|
+
it('should filter out some components when activeFilters is ALL', function () {
|
|
269
269
|
const { result } = renderHook(() =>
|
|
270
270
|
useLunatic(sourceLogement, undefined, {
|
|
271
|
-
...
|
|
272
|
-
|
|
271
|
+
...lunaticConfiguration,
|
|
272
|
+
activeFilters: 'ALL',
|
|
273
273
|
})
|
|
274
274
|
);
|
|
275
275
|
act(() => result.current.goToPage({ page: '3' }));
|
|
276
276
|
const currentPage = result.current.pageTag;
|
|
277
277
|
expect(currentPage).not.toBe('3');
|
|
278
278
|
});
|
|
279
|
-
it('should not filter any component when
|
|
279
|
+
it('should not filter any component when activeFilters is NONE', function () {
|
|
280
280
|
const { result } = renderHook(() =>
|
|
281
281
|
useLunatic(sourceLogement, undefined, {
|
|
282
|
-
...
|
|
283
|
-
|
|
282
|
+
...lunaticConfiguration,
|
|
283
|
+
activeFilters: 'NONE',
|
|
284
284
|
})
|
|
285
285
|
);
|
|
286
286
|
act(() => result.current.goToPage({ page: '3' }));
|