@rsuci/shared-form-components 1.0.51 → 1.0.53
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/dist/components/roster/RosterPanel.d.ts.map +1 -1
- package/dist/components/roster/RosterPanel.js +18 -4
- package/dist/hooks/useFormTree.d.ts +2 -0
- package/dist/hooks/useFormTree.d.ts.map +1 -1
- package/dist/hooks/useFormTree.js +32 -1
- package/dist/lib/condition-engine.d.ts +15 -0
- package/dist/lib/condition-engine.d.ts.map +1 -1
- package/dist/lib/condition-engine.js +60 -2
- package/dist/lib/form-tree.d.ts +35 -0
- package/dist/lib/form-tree.d.ts.map +1 -1
- package/dist/lib/form-tree.js +168 -2
- package/dist/lib/roster-condition-engine.d.ts +8 -0
- package/dist/lib/roster-condition-engine.d.ts.map +1 -1
- package/dist/lib/roster-condition-engine.js +35 -9
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RosterPanel.d.ts","sourceRoot":"","sources":["../../../src/components/roster/RosterPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAsB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAM5D,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAE3C,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACvH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"RosterPanel.d.ts","sourceRoot":"","sources":["../../../src/components/roster/RosterPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAsB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAM5D,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAE3C,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACvH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA2M3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -12,12 +12,26 @@ import VariableRenderer from '../VariableRenderer';
|
|
|
12
12
|
import { cn } from '../../lib/utils/cn';
|
|
13
13
|
import { RosterConditionEngine } from '../../lib/roster-condition-engine';
|
|
14
14
|
const RosterPanel = ({ option, rosterVariables, value, onChange, disabled, showCheckbox = false, isChecked = true, onCheckChange, services, isConsultationMode = false, interpolateVariableLabel, allResponses, numeroMembre }) => {
|
|
15
|
-
// Trier les variables par ordre
|
|
16
|
-
const sortedVariables =
|
|
15
|
+
// Trier les variables par ordre (seulement si elles ne sont pas déjà triées)
|
|
16
|
+
const sortedVariables = useMemo(() => {
|
|
17
|
+
// Vérifier si déjà trié pour éviter un tri inutile
|
|
18
|
+
let isSorted = true;
|
|
19
|
+
for (let i = 1; i < rosterVariables.length; i++) {
|
|
20
|
+
if (rosterVariables[i].ordre < rosterVariables[i - 1].ordre) {
|
|
21
|
+
isSorted = false;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return isSorted ? rosterVariables : [...rosterVariables].sort((a, b) => a.ordre - b.ordre);
|
|
26
|
+
}, [rosterVariables]);
|
|
27
|
+
// Créer une clé stable pour les valeurs (pour comparaison dans useMemo)
|
|
28
|
+
const lineValuesKey = useMemo(() => {
|
|
29
|
+
return JSON.stringify(value);
|
|
30
|
+
}, [value]);
|
|
17
31
|
// Calculer les variables masquées par les jumps
|
|
18
32
|
const jumpedVariables = useMemo(() => {
|
|
19
33
|
return RosterConditionEngine.computeJumpedVariables(sortedVariables.map(v => ({ code: v.code, ordre: v.ordre, conditionsAffichage: v.conditionsAffichage })), value);
|
|
20
|
-
}, [sortedVariables,
|
|
34
|
+
}, [sortedVariables, lineValuesKey]);
|
|
21
35
|
// Filtrer les variables visibles (conditions + jumps)
|
|
22
36
|
const visibleVariables = useMemo(() => {
|
|
23
37
|
return sortedVariables.filter(rosterVar => {
|
|
@@ -32,7 +46,7 @@ const RosterPanel = ({ option, rosterVariables, value, onChange, disabled, showC
|
|
|
32
46
|
// Évaluer la condition avec les valeurs de cette ligne
|
|
33
47
|
return RosterConditionEngine.evaluate(rosterVar.conditionsAffichage, value);
|
|
34
48
|
});
|
|
35
|
-
}, [sortedVariables, jumpedVariables,
|
|
49
|
+
}, [sortedVariables, jumpedVariables, lineValuesKey]);
|
|
36
50
|
return (_jsxs("div", { className: cn('border border-gray-200 rounded-lg p-4 bg-white', 'shadow-sm hover:shadow-md transition-shadow', disabled && 'opacity-60'), children: [_jsx("div", { className: "border-b border-gray-100 pb-3 mb-4", children: _jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "flex items-center flex-1", children: [showCheckbox && (_jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onCheckChange?.(e.target.checked), disabled: disabled, className: cn('w-5 h-5 mr-3 text-green-600 border-gray-300 rounded focus:ring-green-500', disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer') })), _jsxs("div", { children: [_jsxs("h3", { className: "font-semibold text-lg text-gray-800 flex items-center", children: [_jsx("span", { className: "mr-2", children: "\uD83D\uDCCC" }), option.designation] }), _jsxs("p", { className: "text-xs text-blue-600 font-mono mt-1", children: ["(", option.code, ")"] })] })] }) }) }), !showCheckbox || isChecked ? (_jsx("div", { className: "space-y-4", children: visibleVariables.map(rosterVar => {
|
|
37
51
|
// Créer un objet VariableFormulaire compatible avec VariableRenderer
|
|
38
52
|
// Rendre le code unique par panel pour éviter les conflits de radios/checkboxes
|
|
@@ -10,6 +10,8 @@ export interface UseFormTreeOptions {
|
|
|
10
10
|
onJumpError?: (error: JumpError) => void;
|
|
11
11
|
/** Activer le logging de debug */
|
|
12
12
|
debug?: boolean;
|
|
13
|
+
/** Code du groupe actif (pour optimisation de la réévaluation) */
|
|
14
|
+
activeGroupCode?: string;
|
|
13
15
|
}
|
|
14
16
|
export interface UseFormTreeReturn {
|
|
15
17
|
/** Instance du FormTree */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormTree.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormTree.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE7F,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACzC,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useFormTree.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormTree.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE7F,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACzC,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IAEnB,kDAAkD;IAClD,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,kBAAkB,EAAE,CAAC;IAElE,mGAAmG;IACnG,8BAA8B,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,kBAAkB,EAAE,CAAC;IAErG,8DAA8D;IAC9D,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;IAE5D,gGAAgG;IAChG,iCAAiC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;IAE/F,+CAA+C;IAC/C,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAE9E,uEAAuE;IACvE,yBAAyB,EAAE,MAAM,MAAM,EAAE,CAAC;IAE1C,qCAAqC;IACrC,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;IAE1E,kCAAkC;IAClC,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAElE,0CAA0C;IAC1C,UAAU,EAAE,SAAS,EAAE,CAAC;IAExB,6BAA6B;IAC7B,WAAW,EAAE,SAAS,EAAE,CAAC;IAEzB,6DAA6D;IAC7D,yBAAyB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAEvF,sDAAsD;IACtD,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IAEpB,oEAAoE;IACpE,kBAAkB,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAErD,+EAA+E;IAC/E,8BAA8B,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC9G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EACzC,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAkKnB;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -37,6 +37,8 @@ export function useFormTree(groupes, responses, options = {}) {
|
|
|
37
37
|
// Référence stable pour les options
|
|
38
38
|
const optionsRef = useRef(options);
|
|
39
39
|
optionsRef.current = options;
|
|
40
|
+
// Référence pour tracker les réponses précédentes
|
|
41
|
+
const previousResponsesRef = useRef(responses);
|
|
40
42
|
// Créer l'instance FormTree (stable tant que groupes ne changent pas)
|
|
41
43
|
const formTree = useMemo(() => {
|
|
42
44
|
const tree = new FormTree(responses, {
|
|
@@ -52,7 +54,36 @@ export function useFormTree(groupes, responses, options = {}) {
|
|
|
52
54
|
}, [formTree, options.onJumpError]);
|
|
53
55
|
// Mettre à jour quand les réponses changent
|
|
54
56
|
useEffect(() => {
|
|
55
|
-
|
|
57
|
+
const activeGroupCode = optionsRef.current.activeGroupCode;
|
|
58
|
+
// Si un groupe actif est spécifié, utiliser l'optimisation
|
|
59
|
+
if (activeGroupCode) {
|
|
60
|
+
// Identifier les variables qui ont changé
|
|
61
|
+
const changedVariableCodes = [];
|
|
62
|
+
const currentKeys = Object.keys(responses);
|
|
63
|
+
const previousKeys = Object.keys(previousResponsesRef.current);
|
|
64
|
+
// Vérifier les nouvelles variables et les valeurs modifiées
|
|
65
|
+
for (const key of currentKeys) {
|
|
66
|
+
const current = responses[key];
|
|
67
|
+
const previous = previousResponsesRef.current[key];
|
|
68
|
+
if (!previous || JSON.stringify(current.valeur) !== JSON.stringify(previous.valeur)) {
|
|
69
|
+
changedVariableCodes.push(current.variableCode);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Vérifier les variables supprimées
|
|
73
|
+
for (const key of previousKeys) {
|
|
74
|
+
if (!responses[key]) {
|
|
75
|
+
changedVariableCodes.push(previousResponsesRef.current[key].variableCode);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Utiliser la mise à jour optimisée par groupe
|
|
79
|
+
formTree.updateResponsesForGroup(responses, activeGroupCode, changedVariableCodes);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Sinon, utiliser la mise à jour complète
|
|
83
|
+
formTree.updateResponses(responses);
|
|
84
|
+
}
|
|
85
|
+
// Mettre à jour la référence
|
|
86
|
+
previousResponsesRef.current = responses;
|
|
56
87
|
setUpdateCount(c => c + 1);
|
|
57
88
|
}, [formTree, responses]);
|
|
58
89
|
// Fonctions de requête memoizées
|
|
@@ -19,6 +19,8 @@ export declare class ConditionEngine {
|
|
|
19
19
|
private responses;
|
|
20
20
|
private context;
|
|
21
21
|
private autoActions;
|
|
22
|
+
private conditionCache;
|
|
23
|
+
private maxCacheSize;
|
|
22
24
|
constructor(responses: Record<string, EnqueteReponse>);
|
|
23
25
|
/**
|
|
24
26
|
* Évalue une condition complexe
|
|
@@ -39,6 +41,10 @@ export declare class ConditionEngine {
|
|
|
39
41
|
* - "setValeur('MAJEUR', ${STATUT_AGE}, ${AGE} >= 18)"
|
|
40
42
|
*/
|
|
41
43
|
evaluate(condition: string, currentIteration?: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Met en cache un résultat d'évaluation
|
|
46
|
+
*/
|
|
47
|
+
private cacheResult;
|
|
42
48
|
/**
|
|
43
49
|
* Met à jour le contexte avec de nouvelles réponses
|
|
44
50
|
*/
|
|
@@ -47,6 +53,15 @@ export declare class ConditionEngine {
|
|
|
47
53
|
* Obtient toutes les variables référencées dans une condition
|
|
48
54
|
*/
|
|
49
55
|
getReferencedVariables(condition: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Génère un hash du contexte pour les variables référencées dans une condition
|
|
58
|
+
* Utilisé pour le cache des résultats d'évaluation
|
|
59
|
+
*/
|
|
60
|
+
private getContextHashForCondition;
|
|
61
|
+
/**
|
|
62
|
+
* Invalide le cache pour les conditions qui référencent les variables spécifiées
|
|
63
|
+
*/
|
|
64
|
+
invalidateCacheForVariables(variableCodes: string[]): void;
|
|
50
65
|
/**
|
|
51
66
|
* Vérifie si une condition contient une fonction utilitaire
|
|
52
67
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/condition-engine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIjE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAGD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,OAAO,GAAG,UAAU,EAAE,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,eAAe;
|
|
1
|
+
{"version":3,"file":"condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/condition-engine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIjE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAGD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,OAAO,GAAG,UAAU,EAAE,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,eAAe;IAMd,OAAO,CAAC,SAAS;IAL7B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,cAAc,CAAoE;IAC1F,OAAO,CAAC,YAAY,CAAO;gBAEP,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;IAI7D;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO;IA+C/D;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI;IAOjE;;OAEG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAKnD;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAQlC;;OAEG;IACH,2BAA2B,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI;IAa1D;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAkB/B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAoCtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA+CzB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAwB5B;;OAEG;IACH,OAAO,CAAC,UAAU;IA0ClB;;;OAGG;IACH,OAAO,CAAC,UAAU;IA8FlB;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAI9B;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;;OAGG;IACH,OAAO,CAAC,uCAAuC;IAmC/C;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAahC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAuDnC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IA8BtB;;OAEG;IACH,OAAO,CAAC,eAAe;IA6BvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA2CzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAyBhC;;OAEG;IACH,OAAO,CAAC,YAAY;IA6CpB;;OAEG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAwGhF;;OAEG;IACH,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,EAAE;CAwE5D;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,oBAS3E,CAAC"}
|
|
@@ -9,6 +9,8 @@ export class ConditionEngine {
|
|
|
9
9
|
this.responses = responses;
|
|
10
10
|
this.context = {};
|
|
11
11
|
this.autoActions = [];
|
|
12
|
+
this.conditionCache = new Map();
|
|
13
|
+
this.maxCacheSize = 500;
|
|
12
14
|
this.buildContext();
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
@@ -33,20 +35,51 @@ export class ConditionEngine {
|
|
|
33
35
|
if (!condition || condition.trim() === '')
|
|
34
36
|
return true;
|
|
35
37
|
try {
|
|
38
|
+
// Générer une clé de cache incluant l'itération si présente
|
|
39
|
+
const cacheKey = currentIteration !== undefined
|
|
40
|
+
? `${condition}::iter${currentIteration}`
|
|
41
|
+
: condition;
|
|
42
|
+
// Vérifier le cache
|
|
43
|
+
const cached = this.conditionCache.get(cacheKey);
|
|
44
|
+
if (cached) {
|
|
45
|
+
const currentHash = this.getContextHashForCondition(condition);
|
|
46
|
+
if (cached.contextHash === currentHash) {
|
|
47
|
+
return cached.result;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
36
50
|
// Vérifier si c'est une fonction utilitaire
|
|
37
51
|
if (this.isUtilityFunction(condition)) {
|
|
38
|
-
|
|
52
|
+
const result = this.evaluateUtilityFunction(condition, currentIteration);
|
|
53
|
+
// Mettre en cache le résultat
|
|
54
|
+
this.cacheResult(cacheKey, condition, result);
|
|
55
|
+
return result;
|
|
39
56
|
}
|
|
40
57
|
// Remplacer les références aux variables avec support des itérations
|
|
41
58
|
const processedCondition = this.replaceVariableReferencesWithIterations(condition, currentIteration);
|
|
42
59
|
// Évaluer l'expression
|
|
43
|
-
|
|
60
|
+
const result = this.safeEvaluate(processedCondition);
|
|
61
|
+
// Mettre en cache le résultat
|
|
62
|
+
this.cacheResult(cacheKey, condition, result);
|
|
63
|
+
return result;
|
|
44
64
|
}
|
|
45
65
|
catch (error) {
|
|
46
66
|
console.warn('Erreur lors de l\'évaluation de la condition:', condition, error);
|
|
47
67
|
return true; // En cas d'erreur, on affiche la variable
|
|
48
68
|
}
|
|
49
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Met en cache un résultat d'évaluation
|
|
72
|
+
*/
|
|
73
|
+
cacheResult(cacheKey, condition, result) {
|
|
74
|
+
// Limiter la taille du cache
|
|
75
|
+
if (this.conditionCache.size >= this.maxCacheSize) {
|
|
76
|
+
// Supprimer la première entrée (stratégie FIFO simple)
|
|
77
|
+
const firstKey = this.conditionCache.keys().next().value;
|
|
78
|
+
this.conditionCache.delete(firstKey);
|
|
79
|
+
}
|
|
80
|
+
const contextHash = this.getContextHashForCondition(condition);
|
|
81
|
+
this.conditionCache.set(cacheKey, { result, contextHash });
|
|
82
|
+
}
|
|
50
83
|
/**
|
|
51
84
|
* Met à jour le contexte avec de nouvelles réponses
|
|
52
85
|
*/
|
|
@@ -54,6 +87,7 @@ export class ConditionEngine {
|
|
|
54
87
|
this.responses = { ...this.responses, ...newResponses };
|
|
55
88
|
this.buildContext();
|
|
56
89
|
this.autoActions = []; // Réinitialiser les actions automatiques
|
|
90
|
+
this.conditionCache.clear(); // Invalider le cache
|
|
57
91
|
}
|
|
58
92
|
/**
|
|
59
93
|
* Obtient toutes les variables référencées dans une condition
|
|
@@ -62,6 +96,30 @@ export class ConditionEngine {
|
|
|
62
96
|
const matches = condition.match(/\$\{([A-Z_][A-Z0-9_]*(?:_\d+)?)\}/g);
|
|
63
97
|
return matches ? matches.map(match => match.slice(2, -1)) : [];
|
|
64
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Génère un hash du contexte pour les variables référencées dans une condition
|
|
101
|
+
* Utilisé pour le cache des résultats d'évaluation
|
|
102
|
+
*/
|
|
103
|
+
getContextHashForCondition(condition) {
|
|
104
|
+
const referencedVars = this.getReferencedVariables(condition);
|
|
105
|
+
const relevantContext = referencedVars
|
|
106
|
+
.map(varCode => `${varCode}:${JSON.stringify(this.context[varCode])}`)
|
|
107
|
+
.join('|');
|
|
108
|
+
return relevantContext;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Invalide le cache pour les conditions qui référencent les variables spécifiées
|
|
112
|
+
*/
|
|
113
|
+
invalidateCacheForVariables(variableCodes) {
|
|
114
|
+
const varSet = new Set(variableCodes);
|
|
115
|
+
for (const [condition, cacheEntry] of this.conditionCache.entries()) {
|
|
116
|
+
const referencedVars = this.getReferencedVariables(condition);
|
|
117
|
+
const hasAffectedVar = referencedVars.some(varCode => varSet.has(varCode));
|
|
118
|
+
if (hasAffectedVar) {
|
|
119
|
+
this.conditionCache.delete(condition);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
65
123
|
/**
|
|
66
124
|
* Vérifie si une condition contient une fonction utilitaire
|
|
67
125
|
*/
|
package/dist/lib/form-tree.d.ts
CHANGED
|
@@ -22,11 +22,17 @@ export declare class FormTree implements IFormTree {
|
|
|
22
22
|
private debug;
|
|
23
23
|
private instanceStates;
|
|
24
24
|
private instanceJumpRanges;
|
|
25
|
+
private crossGroupDependencies;
|
|
25
26
|
onJumpError?: (error: JumpError) => void;
|
|
26
27
|
constructor(responses?: Record<string, EnqueteReponse>, options?: FormTreeOptions);
|
|
27
28
|
private log;
|
|
28
29
|
buildFromFormulaire(groupes: GroupeFormulaire[]): void;
|
|
29
30
|
updateResponses(responses: Record<string, EnqueteReponse>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Met à jour les réponses et réévalue uniquement le groupe actif et ses dépendances
|
|
33
|
+
* Optimisation pour éviter de réévaluer tout l'arbre
|
|
34
|
+
*/
|
|
35
|
+
updateResponsesForGroup(responses: Record<string, EnqueteReponse>, activeGroupCode: string, changedVariableCodes?: string[]): void;
|
|
30
36
|
evaluateAll(): void;
|
|
31
37
|
private evaluateGroupConditions;
|
|
32
38
|
private containsJump;
|
|
@@ -110,6 +116,35 @@ export declare class FormTree implements IFormTree {
|
|
|
110
116
|
* @returns Map<variableCode_suffixé, valeur> des variables à mettre à jour
|
|
111
117
|
*/
|
|
112
118
|
evaluateAutoActionsForInstance(groupeCode?: string, instanceNumber?: number): Map<string, VariableValue>;
|
|
119
|
+
/**
|
|
120
|
+
* Analyse les dépendances entre groupes
|
|
121
|
+
* Identifie quels groupes référencent des variables d'autres groupes
|
|
122
|
+
*/
|
|
123
|
+
private analyzeCrossGroupDependencies;
|
|
124
|
+
/**
|
|
125
|
+
* Enregistre les dépendances pour un groupe
|
|
126
|
+
*/
|
|
127
|
+
private recordDependencies;
|
|
128
|
+
/**
|
|
129
|
+
* Retourne les groupes qui dépendent du groupe spécifié
|
|
130
|
+
*/
|
|
131
|
+
private getGroupsDependingOn;
|
|
132
|
+
/**
|
|
133
|
+
* Évalue uniquement un groupe spécifique
|
|
134
|
+
*/
|
|
135
|
+
private evaluateGroup;
|
|
136
|
+
/**
|
|
137
|
+
* Applique les jump ranges uniquement pour un groupe spécifique
|
|
138
|
+
*/
|
|
139
|
+
private applyJumpRangesForGroup;
|
|
140
|
+
/**
|
|
141
|
+
* Calcule la visibilité finale uniquement pour un groupe spécifique
|
|
142
|
+
*/
|
|
143
|
+
private computeFinalVisibilityForGroup;
|
|
144
|
+
/**
|
|
145
|
+
* Invalide le cache des instances uniquement pour un groupe spécifique
|
|
146
|
+
*/
|
|
147
|
+
private invalidateInstanceCacheForGroup;
|
|
113
148
|
/**
|
|
114
149
|
* Retourne un snapshot de l'état complet pour debug
|
|
115
150
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-tree.d.ts","sourceRoot":"","sources":["../../src/lib/form-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,SAAS,EACT,eAAe,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAc,MAAM,oBAAoB,CAAC;AAEjE,qBAAa,QAAS,YAAW,SAAS;IACxC,OAAO,CAAC,UAAU,CAA0C;IAC5D,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,KAAK,CAAU;IAIvB,OAAO,CAAC,cAAc,CAA0D;IAGhF,OAAO,CAAC,kBAAkB,CAAuC;
|
|
1
|
+
{"version":3,"file":"form-tree.d.ts","sourceRoot":"","sources":["../../src/lib/form-tree.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/form-tree.js
CHANGED
|
@@ -22,6 +22,9 @@ export class FormTree {
|
|
|
22
22
|
// Cache pour les jumps par instance
|
|
23
23
|
// Clé: "groupeCode_instanceNumber", Valeur: JumpRange[]
|
|
24
24
|
this.instanceJumpRanges = new Map();
|
|
25
|
+
// Analyse des dépendances entre groupes
|
|
26
|
+
// Clé: groupeCode, Valeur: Set de groupes qui dépendent de ce groupe
|
|
27
|
+
this.crossGroupDependencies = new Map();
|
|
25
28
|
this.responses = responses;
|
|
26
29
|
this.conditionEngine = new ConditionEngine(responses);
|
|
27
30
|
this.onJumpError = options.onJumpError;
|
|
@@ -70,6 +73,8 @@ export class FormTree {
|
|
|
70
73
|
this.groupNodes.set(groupe.code, groupState);
|
|
71
74
|
this.log(`Group ${groupe.code} built with ${variableStates.length} variables`);
|
|
72
75
|
}
|
|
76
|
+
// Analyser les dépendances entre groupes
|
|
77
|
+
this.analyzeCrossGroupDependencies(groupes);
|
|
73
78
|
// Évaluer toutes les conditions initiales
|
|
74
79
|
this.evaluateAll();
|
|
75
80
|
}
|
|
@@ -88,6 +93,32 @@ export class FormTree {
|
|
|
88
93
|
// Réévaluer toutes les conditions
|
|
89
94
|
this.evaluateAll();
|
|
90
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Met à jour les réponses et réévalue uniquement le groupe actif et ses dépendances
|
|
98
|
+
* Optimisation pour éviter de réévaluer tout l'arbre
|
|
99
|
+
*/
|
|
100
|
+
updateResponsesForGroup(responses, activeGroupCode, changedVariableCodes) {
|
|
101
|
+
this.log('Updating responses for group', activeGroupCode);
|
|
102
|
+
this.responses = responses;
|
|
103
|
+
this.conditionEngine.updateContext(responses);
|
|
104
|
+
// Mettre à jour les valeurs dans les noeuds
|
|
105
|
+
for (const [code, state] of this.variableNodes) {
|
|
106
|
+
state.currentValue = responses[code]?.valeur ?? null;
|
|
107
|
+
}
|
|
108
|
+
// Invalider seulement le cache du groupe actif
|
|
109
|
+
this.invalidateInstanceCacheForGroup(activeGroupCode);
|
|
110
|
+
// Si des variables spécifiques ont changé, invalider le cache sélectivement
|
|
111
|
+
if (changedVariableCodes && changedVariableCodes.length > 0) {
|
|
112
|
+
this.conditionEngine.invalidateCacheForVariables(changedVariableCodes);
|
|
113
|
+
}
|
|
114
|
+
// Réévaluer le groupe actif et ses dépendances
|
|
115
|
+
this.evaluateGroup(activeGroupCode);
|
|
116
|
+
// Réévaluer les groupes qui dépendent de celui-ci
|
|
117
|
+
const dependentGroups = this.getGroupsDependingOn(activeGroupCode);
|
|
118
|
+
for (const groupCode of dependentGroups) {
|
|
119
|
+
this.evaluateGroup(groupCode);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
91
122
|
evaluateAll() {
|
|
92
123
|
this.log('Evaluating all conditions');
|
|
93
124
|
// Reset des états
|
|
@@ -627,13 +658,148 @@ export class FormTree {
|
|
|
627
658
|
this.log(`Got ${actions.length} autoactions after evaluation`);
|
|
628
659
|
for (const action of actions) {
|
|
629
660
|
if (action.shouldExecute && action.type === 'setValue') {
|
|
630
|
-
|
|
631
|
-
|
|
661
|
+
// Vérifier si la valeur cible est différente de la valeur actuelle
|
|
662
|
+
// pour éviter les boucles infinies
|
|
663
|
+
const targetKey = action.targetVariable;
|
|
664
|
+
const currentResponse = this.responses[targetKey];
|
|
665
|
+
const currentValue = currentResponse?.valeur;
|
|
666
|
+
// Comparer les valeurs (gérer les cas null/undefined)
|
|
667
|
+
const valuesAreDifferent = currentValue !== action.value &&
|
|
668
|
+
!(currentValue == null && action.value == null) &&
|
|
669
|
+
JSON.stringify(currentValue) !== JSON.stringify(action.value);
|
|
670
|
+
if (valuesAreDifferent) {
|
|
671
|
+
updates.set(targetKey, action.value);
|
|
672
|
+
this.log(`AutoAction for instance: ${targetKey} = ${JSON.stringify(action.value)} (was: ${JSON.stringify(currentValue)})`);
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
this.log(`AutoAction skipped (same value): ${targetKey} = ${JSON.stringify(action.value)}`);
|
|
676
|
+
}
|
|
632
677
|
}
|
|
633
678
|
}
|
|
634
679
|
this.conditionEngine.clearAutoActions();
|
|
635
680
|
return updates;
|
|
636
681
|
}
|
|
682
|
+
// ============ OPTIMISATION PAR GROUPE ============
|
|
683
|
+
/**
|
|
684
|
+
* Analyse les dépendances entre groupes
|
|
685
|
+
* Identifie quels groupes référencent des variables d'autres groupes
|
|
686
|
+
*/
|
|
687
|
+
analyzeCrossGroupDependencies(groupes) {
|
|
688
|
+
this.crossGroupDependencies.clear();
|
|
689
|
+
// Pour chaque groupe
|
|
690
|
+
for (const groupe of groupes) {
|
|
691
|
+
// Analyser les conditions du groupe lui-même
|
|
692
|
+
if (groupe.conditionsAffichage) {
|
|
693
|
+
const referencedVars = this.conditionEngine.getReferencedVariables(groupe.conditionsAffichage);
|
|
694
|
+
this.recordDependencies(groupe.code, referencedVars);
|
|
695
|
+
}
|
|
696
|
+
// Analyser les conditions de chaque variable du groupe
|
|
697
|
+
for (const variable of groupe.variables) {
|
|
698
|
+
if (variable.conditionsAffichage) {
|
|
699
|
+
const referencedVars = this.conditionEngine.getReferencedVariables(variable.conditionsAffichage);
|
|
700
|
+
this.recordDependencies(groupe.code, referencedVars);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
this.log('Cross-group dependencies analyzed:', this.crossGroupDependencies);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Enregistre les dépendances pour un groupe
|
|
708
|
+
*/
|
|
709
|
+
recordDependencies(dependentGroupCode, referencedVarCodes) {
|
|
710
|
+
for (const varCode of referencedVarCodes) {
|
|
711
|
+
// Trouver le groupe de la variable référencée
|
|
712
|
+
const varState = this.variableNodes.get(varCode);
|
|
713
|
+
if (varState && varState.variable.groupeCode !== dependentGroupCode) {
|
|
714
|
+
const sourceGroupCode = varState.variable.groupeCode;
|
|
715
|
+
if (!this.crossGroupDependencies.has(sourceGroupCode)) {
|
|
716
|
+
this.crossGroupDependencies.set(sourceGroupCode, new Set());
|
|
717
|
+
}
|
|
718
|
+
this.crossGroupDependencies.get(sourceGroupCode).add(dependentGroupCode);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Retourne les groupes qui dépendent du groupe spécifié
|
|
724
|
+
*/
|
|
725
|
+
getGroupsDependingOn(groupeCode) {
|
|
726
|
+
return Array.from(this.crossGroupDependencies.get(groupeCode) || []);
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Évalue uniquement un groupe spécifique
|
|
730
|
+
*/
|
|
731
|
+
evaluateGroup(groupeCode) {
|
|
732
|
+
const groupNode = this.groupNodes.get(groupeCode);
|
|
733
|
+
if (!groupNode) {
|
|
734
|
+
this.log(`Group ${groupeCode} not found`);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
this.log(`Evaluating group ${groupeCode}`);
|
|
738
|
+
// Reset des états pour ce groupe
|
|
739
|
+
for (const varState of groupNode.variables) {
|
|
740
|
+
varState.isJumpedOver = false;
|
|
741
|
+
varState.skipValidation = false;
|
|
742
|
+
varState.shouldClearOnSave = false;
|
|
743
|
+
}
|
|
744
|
+
// Évaluer les conditions du groupe
|
|
745
|
+
this.evaluateGroupConditions(groupNode);
|
|
746
|
+
// Appliquer les jumps pour ce groupe
|
|
747
|
+
this.applyJumpRangesForGroup(groupeCode);
|
|
748
|
+
// Calculer la visibilité finale pour ce groupe
|
|
749
|
+
this.computeFinalVisibilityForGroup(groupeCode);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Applique les jump ranges uniquement pour un groupe spécifique
|
|
753
|
+
*/
|
|
754
|
+
applyJumpRangesForGroup(groupeCode) {
|
|
755
|
+
const groupJumps = this.jumpRanges.filter(j => j.groupeCode === groupeCode);
|
|
756
|
+
for (const jump of groupJumps) {
|
|
757
|
+
if (!jump.isActive)
|
|
758
|
+
continue;
|
|
759
|
+
this.log(`Applying jump in group ${groupeCode}: ${jump.sourceCode} to ${jump.targetCode}`);
|
|
760
|
+
// Marquer les variables du groupe entre source et cible comme "jumped over"
|
|
761
|
+
for (const [code, state] of this.variableNodes) {
|
|
762
|
+
if (state.variable.groupeCode !== groupeCode)
|
|
763
|
+
continue;
|
|
764
|
+
const ordre = state.variable.ordre;
|
|
765
|
+
if (ordre > jump.sourceOrdre && ordre < jump.targetOrdre) {
|
|
766
|
+
state.isJumpedOver = true;
|
|
767
|
+
state.skipValidation = true;
|
|
768
|
+
state.shouldClearOnSave = true;
|
|
769
|
+
this.log(`Variable ${code} marked as jumped over in group ${groupeCode}`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Calcule la visibilité finale uniquement pour un groupe spécifique
|
|
776
|
+
*/
|
|
777
|
+
computeFinalVisibilityForGroup(groupeCode) {
|
|
778
|
+
for (const state of this.variableNodes.values()) {
|
|
779
|
+
if (state.variable.groupeCode !== groupeCode)
|
|
780
|
+
continue;
|
|
781
|
+
state.isVisible =
|
|
782
|
+
state.variable.estVisible &&
|
|
783
|
+
state.isConditionMet &&
|
|
784
|
+
!state.isJumpedOver;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Invalide le cache des instances uniquement pour un groupe spécifique
|
|
789
|
+
*/
|
|
790
|
+
invalidateInstanceCacheForGroup(groupeCode) {
|
|
791
|
+
const keysToDelete = [];
|
|
792
|
+
for (const key of this.instanceStates.keys()) {
|
|
793
|
+
if (key.startsWith(`${groupeCode}_`)) {
|
|
794
|
+
keysToDelete.push(key);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
for (const key of keysToDelete) {
|
|
798
|
+
this.instanceStates.delete(key);
|
|
799
|
+
this.instanceJumpRanges.delete(key);
|
|
800
|
+
}
|
|
801
|
+
this.log(`Invalidated instance cache for group ${groupeCode}`);
|
|
802
|
+
}
|
|
637
803
|
// ============ DEBUG ============
|
|
638
804
|
/**
|
|
639
805
|
* Retourne un snapshot de l'état complet pour debug
|
|
@@ -25,6 +25,7 @@ export interface RosterVariableRef {
|
|
|
25
25
|
* Toutes les méthodes sont statiques pour une utilisation sans état
|
|
26
26
|
*/
|
|
27
27
|
export declare class RosterConditionEngine {
|
|
28
|
+
private static sharedEngine;
|
|
28
29
|
/**
|
|
29
30
|
* Valide une condition au moment du design (admin)
|
|
30
31
|
* Vérifie que les références sont dans le scope et que les jumps sont valides
|
|
@@ -33,8 +34,13 @@ export declare class RosterConditionEngine {
|
|
|
33
34
|
/**
|
|
34
35
|
* Évalue une condition au runtime (rendu)
|
|
35
36
|
* Utilise les valeurs de la ligne courante du roster
|
|
37
|
+
* Réutilise un ConditionEngine partagé pour améliorer les performances
|
|
36
38
|
*/
|
|
37
39
|
static evaluate(condition: string, lineValues: Record<string, any>): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Réinitialise l'engine partagé (utile pour les tests ou pour forcer un nettoyage)
|
|
42
|
+
*/
|
|
43
|
+
static resetSharedEngine(): void;
|
|
38
44
|
/**
|
|
39
45
|
* Extrait toutes les références de variables d'une condition
|
|
40
46
|
* Format: ${VAR_CODE}
|
|
@@ -61,10 +67,12 @@ export declare class RosterConditionEngine {
|
|
|
61
67
|
* Supporte les jumps multiples avec court-circuit:
|
|
62
68
|
* - jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
|
|
63
69
|
* - Si cond1 est vraie, on saute à VAR1 et cond2 n'est pas évaluée
|
|
70
|
+
* Optimisé avec un index pré-construit pour O(n) au lieu de O(n²)
|
|
64
71
|
*/
|
|
65
72
|
static computeJumpedVariables(sortedVariables: RosterVariableRef[], lineValues: Record<string, any>): Set<string>;
|
|
66
73
|
/**
|
|
67
74
|
* Évalue une condition interne (sans le wrapper jump())
|
|
75
|
+
* Réutilise l'engine partagé pour améliorer les performances
|
|
68
76
|
*/
|
|
69
77
|
private static evaluateInnerCondition;
|
|
70
78
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roster-condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/roster-condition-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,wBAAwB,GAChC,uBAAuB,GACvB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,cAAc,CAAC;AAEnB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,qBAAqB;
|
|
1
|
+
{"version":3,"file":"roster-condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/roster-condition-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,wBAAwB,GAChC,uBAAuB,GACvB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,cAAc,CAAC;AAEnB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAgC;IAE3D;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CACtB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,iBAAiB,EAAE,EACvC,mBAAmB,EAAE,MAAM,EAC3B,oBAAoB,EAAE,MAAM,GAC3B,+BAA+B;IA6ElC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO;IA8B5E;;OAEG;IACH,MAAM,CAAC,iBAAiB,IAAI,IAAI;IAIhC;;;OAGG;IACH,MAAM,CAAC,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAO7D;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO1D;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;QAC/C,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAoBF;;;;;;OAMG;IACH,MAAM,CAAC,sBAAsB,CAC3B,eAAe,EAAE,iBAAiB,EAAE,EACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC9B,GAAG,CAAC,MAAM,CAAC;IAyCd;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAkCrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;CAsD9B"}
|
|
@@ -89,6 +89,7 @@ export class RosterConditionEngine {
|
|
|
89
89
|
/**
|
|
90
90
|
* Évalue une condition au runtime (rendu)
|
|
91
91
|
* Utilise les valeurs de la ligne courante du roster
|
|
92
|
+
* Réutilise un ConditionEngine partagé pour améliorer les performances
|
|
92
93
|
*/
|
|
93
94
|
static evaluate(condition, lineValues) {
|
|
94
95
|
if (!condition?.trim()) {
|
|
@@ -104,15 +105,26 @@ export class RosterConditionEngine {
|
|
|
104
105
|
dateModification: new Date()
|
|
105
106
|
};
|
|
106
107
|
}
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
// Réutiliser l'engine partagé au lieu d'en créer un nouveau
|
|
109
|
+
if (!this.sharedEngine) {
|
|
110
|
+
this.sharedEngine = new ConditionEngine(responses);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
this.sharedEngine.updateContext(responses);
|
|
114
|
+
}
|
|
115
|
+
return this.sharedEngine.evaluate(condition);
|
|
110
116
|
}
|
|
111
117
|
catch (error) {
|
|
112
118
|
console.warn('[RosterConditionEngine] Erreur évaluation:', condition, error);
|
|
113
119
|
return true; // En cas d'erreur, afficher par défaut
|
|
114
120
|
}
|
|
115
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Réinitialise l'engine partagé (utile pour les tests ou pour forcer un nettoyage)
|
|
124
|
+
*/
|
|
125
|
+
static resetSharedEngine() {
|
|
126
|
+
this.sharedEngine = null;
|
|
127
|
+
}
|
|
116
128
|
/**
|
|
117
129
|
* Extrait toutes les références de variables d'une condition
|
|
118
130
|
* Format: ${VAR_CODE}
|
|
@@ -160,9 +172,15 @@ export class RosterConditionEngine {
|
|
|
160
172
|
* Supporte les jumps multiples avec court-circuit:
|
|
161
173
|
* - jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
|
|
162
174
|
* - Si cond1 est vraie, on saute à VAR1 et cond2 n'est pas évaluée
|
|
175
|
+
* Optimisé avec un index pré-construit pour O(n) au lieu de O(n²)
|
|
163
176
|
*/
|
|
164
177
|
static computeJumpedVariables(sortedVariables, lineValues) {
|
|
165
178
|
const jumped = new Set();
|
|
179
|
+
// Pré-construire un index des ordres pour optimisation O(n)
|
|
180
|
+
const orderIndex = new Map();
|
|
181
|
+
for (const rosterVar of sortedVariables) {
|
|
182
|
+
orderIndex.set(rosterVar.code, rosterVar.ordre);
|
|
183
|
+
}
|
|
166
184
|
for (const rosterVar of sortedVariables) {
|
|
167
185
|
const condition = rosterVar.conditionsAffichage;
|
|
168
186
|
if (!condition)
|
|
@@ -177,10 +195,10 @@ export class RosterConditionEngine {
|
|
|
177
195
|
const innerConditionResult = this.evaluateInnerCondition(jump.innerCondition, lineValues);
|
|
178
196
|
if (innerConditionResult) {
|
|
179
197
|
// Ce jump s'active - masquer les variables entre source et cible
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
198
|
+
const targetOrdre = orderIndex.get(jump.target);
|
|
199
|
+
if (targetOrdre !== undefined) {
|
|
182
200
|
for (const v of sortedVariables) {
|
|
183
|
-
if (v.ordre > rosterVar.ordre && v.ordre <
|
|
201
|
+
if (v.ordre > rosterVar.ordre && v.ordre < targetOrdre) {
|
|
184
202
|
jumped.add(v.code);
|
|
185
203
|
}
|
|
186
204
|
}
|
|
@@ -194,6 +212,7 @@ export class RosterConditionEngine {
|
|
|
194
212
|
}
|
|
195
213
|
/**
|
|
196
214
|
* Évalue une condition interne (sans le wrapper jump())
|
|
215
|
+
* Réutilise l'engine partagé pour améliorer les performances
|
|
197
216
|
*/
|
|
198
217
|
static evaluateInnerCondition(innerCondition, lineValues) {
|
|
199
218
|
if (!innerCondition?.trim())
|
|
@@ -208,13 +227,19 @@ export class RosterConditionEngine {
|
|
|
208
227
|
dateModification: new Date()
|
|
209
228
|
};
|
|
210
229
|
}
|
|
211
|
-
|
|
230
|
+
// Réutiliser l'engine partagé au lieu d'en créer un nouveau
|
|
231
|
+
if (!this.sharedEngine) {
|
|
232
|
+
this.sharedEngine = new ConditionEngine(responses);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
this.sharedEngine.updateContext(responses);
|
|
236
|
+
}
|
|
212
237
|
// Si c'est déjà un showMe(), l'évaluer directement
|
|
213
238
|
if (innerCondition.trim().startsWith('showMe(')) {
|
|
214
|
-
return
|
|
239
|
+
return this.sharedEngine.evaluate(innerCondition);
|
|
215
240
|
}
|
|
216
241
|
// Sinon, wrapper dans showMe pour évaluation
|
|
217
|
-
return
|
|
242
|
+
return this.sharedEngine.evaluate(`showMe(${innerCondition})`);
|
|
218
243
|
}
|
|
219
244
|
catch (error) {
|
|
220
245
|
console.warn('[RosterConditionEngine] Erreur évaluation condition interne:', innerCondition, error);
|
|
@@ -277,3 +302,4 @@ export class RosterConditionEngine {
|
|
|
277
302
|
}
|
|
278
303
|
}
|
|
279
304
|
}
|
|
305
|
+
RosterConditionEngine.sharedEngine = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsuci/shared-form-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.53",
|
|
4
4
|
"description": "Composants partagés de rendu de formulaires RSU v2 - Package local pour frontend Admin et Public",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
],
|
|
24
24
|
"author": "RSU v2 Architecture Team",
|
|
25
25
|
"license": "MIT",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24.0.0",
|
|
28
|
+
"npm": ">=11.0.0"
|
|
29
|
+
},
|
|
26
30
|
"peerDependencies": {
|
|
27
31
|
"lucide-react": "^0.263.0 || ^0.525.0",
|
|
28
32
|
"next": "^14.0.0 || ^15.0.0",
|