@flowerforce/flower-core 4.0.1-beta.0 → 4.0.1-beta.10
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/CHANGELOG.md +35 -0
- package/dist/index.cjs.js +171 -102
- package/dist/index.esm.js +162 -101
- package/dist/src/ABAC/abacEngine.d.ts +32 -0
- package/dist/src/ABAC/abacSingleton.d.ts +8 -0
- package/dist/src/ABAC/index.d.ts +2 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/interfaces/CoreInterface.d.ts +16 -23
- package/dist/src/interfaces/ReducerInterface.d.ts +26 -28
- package/dist/src/interfaces/RulesMatcherInterface.d.ts +11 -0
- package/dist/src/interfaces/SelectorsInterface.d.ts +17 -17
- package/dist/src/interfaces/Store.d.ts +1 -1
- package/dist/src/interfaces/UtilsInterface.d.ts +1 -1
- package/dist/src/rules-matcher/RulesMatcher.d.ts +1 -1
- package/dist/src/state-manager/state-functions/FlowerCoreMergedReducers.d.ts +2 -2
- package/dist/src/state-manager/state-functions/FlowerDataStateFunctions.d.ts +2 -13
- package/dist/src/state-manager/state-functions/index.d.ts +1 -1
- package/dist/src/state-manager/state-selectors/FlowerDataStateSelectors.d.ts +2 -0
- package/dist/src/state-manager/state-selectors/FlowerSelectorsMerged.d.ts +2 -2
- package/dist/src/state-manager/state-selectors/index.d.ts +2 -2
- package/dist/src/utils/FlowerCoreStateUtils.d.ts +1 -1
- package/dist/src/utils/FlowerDataCoreUtils.d.ts +2 -0
- package/dist/src/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/src/state-manager/state-selectors/FlowerFormStateSelectors.d.ts +0 -2
- package/dist/src/utils/FlowerFormCoreUtils.d.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
## 3.5.2 (2025-04-23)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### 🩹 Fixes
|
|
5
|
+
|
|
6
|
+
- fix init nodes ([996d8af](https://github.com/flowerforce/flower/commit/996d8af))
|
|
7
|
+
|
|
8
|
+
- package lock ([a3bb210](https://github.com/flowerforce/flower/commit/a3bb210))
|
|
9
|
+
|
|
10
|
+
## 3.5.1 (2025-04-19)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### 🩹 Fixes
|
|
14
|
+
|
|
15
|
+
- remove empty object from init state ([8604346](https://github.com/flowerforce/flower/commit/8604346))
|
|
16
|
+
|
|
17
|
+
## 3.5.0 (2025-04-19)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### 🚀 Features
|
|
21
|
+
|
|
22
|
+
- remove data blank from init nodes ([#80](https://github.com/flowerforce/flower/pull/80))
|
|
23
|
+
|
|
24
|
+
## 3.4.0 (2025-04-19)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### 🚀 Features
|
|
28
|
+
|
|
29
|
+
- added remove value on hide element ([#68](https://github.com/flowerforce/flower/pull/68))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### 🩹 Fixes
|
|
33
|
+
|
|
34
|
+
- avoid validate hidden field ([#67](https://github.com/flowerforce/flower/pull/67))
|
|
35
|
+
|
|
1
36
|
## 3.3.0 (2024-10-08)
|
|
2
37
|
|
|
3
38
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -32,7 +32,7 @@ const devtoolState = {};
|
|
|
32
32
|
const FlowerStateUtils = {
|
|
33
33
|
getAllData: (state) => state &&
|
|
34
34
|
Object.entries(state ?? {}).reduce((acc, [k, v]) => ({ ...acc, [k]: v?.data ?? v }), {}),
|
|
35
|
-
|
|
35
|
+
selectFlowerDataNode: (name) => (state) => _get(state, name),
|
|
36
36
|
makeSelectCurrentNextRules: (name) => (state) => {
|
|
37
37
|
const nextRules = _get(state, [name, 'nextRules']);
|
|
38
38
|
const currentNodeId = FlowerStateUtils.makeSelectCurrentNodeId(name)(state);
|
|
@@ -44,24 +44,107 @@ const FlowerStateUtils = {
|
|
|
44
44
|
return _get(subState, ['current']) || startId;
|
|
45
45
|
},
|
|
46
46
|
makeSelectNodeErrors: (name) => (state) => {
|
|
47
|
-
const
|
|
48
|
-
return
|
|
47
|
+
const data = FlowerStateUtils.selectFlowerDataNode(name)(state);
|
|
48
|
+
return generateData(data);
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
-
const
|
|
52
|
-
const validationErrors =
|
|
51
|
+
const generateData = (data) => {
|
|
52
|
+
const validationErrors = data && data.errors;
|
|
53
53
|
const allErrors = Object.values(validationErrors || {});
|
|
54
54
|
return {
|
|
55
|
-
isSubmitted:
|
|
56
|
-
isDirty: Object.values(
|
|
57
|
-
hasFocus:
|
|
58
|
-
errors:
|
|
59
|
-
customErrors:
|
|
60
|
-
isValidating:
|
|
55
|
+
isSubmitted: data?.isSubmitted || false,
|
|
56
|
+
isDirty: Object.values(data?.dirty || {}).some(Boolean) || false,
|
|
57
|
+
hasFocus: data?.hasFocus,
|
|
58
|
+
errors: data?.errors,
|
|
59
|
+
customErrors: data?.customErrors,
|
|
60
|
+
isValidating: data?.isValidating,
|
|
61
61
|
isValid: allErrors.flat().length === 0
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
class AbacEngine {
|
|
66
|
+
constructor(rules = []) {
|
|
67
|
+
// compile string conditions once
|
|
68
|
+
this.rules = (rules || [])
|
|
69
|
+
.map((r) => {
|
|
70
|
+
let conditionFn = undefined;
|
|
71
|
+
if (r.condition) {
|
|
72
|
+
try {
|
|
73
|
+
// NOTE: uses new Function -> ensure rules.json is trusted by the app owner
|
|
74
|
+
conditionFn = new Function('subject', 'resource', 'action', 'environment', `return (${r.condition});`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error('ABAC: failed to compile rule condition', r.id, err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { ...r, conditionFn };
|
|
81
|
+
})
|
|
82
|
+
.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
83
|
+
}
|
|
84
|
+
decide(ctx) {
|
|
85
|
+
let anyPermit = false;
|
|
86
|
+
for (const r of this.rules) {
|
|
87
|
+
const matchesAction = Array.isArray(r.action)
|
|
88
|
+
? r.action.includes(ctx.action)
|
|
89
|
+
: r.action === ctx.action || r.action === '*';
|
|
90
|
+
if (!matchesAction)
|
|
91
|
+
continue;
|
|
92
|
+
let matches = true;
|
|
93
|
+
if (r.conditionFn) {
|
|
94
|
+
try {
|
|
95
|
+
matches = !!r.conditionFn(ctx.subject, ctx.resource, ctx.action, ctx.environment);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
matches = false;
|
|
99
|
+
console.error(`ABAC: rule ${r.id} threw while evaluating`, err);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!matches)
|
|
103
|
+
continue;
|
|
104
|
+
if (r.effect === 'Deny') {
|
|
105
|
+
// deny-overrides
|
|
106
|
+
return 'Deny';
|
|
107
|
+
}
|
|
108
|
+
if (r.effect === 'Permit') {
|
|
109
|
+
anyPermit = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return anyPermit ? 'Permit' : 'Deny';
|
|
113
|
+
}
|
|
114
|
+
// utility: checks multiple actions and returns those allowed
|
|
115
|
+
allowedActions(ctxBase, actions) {
|
|
116
|
+
return actions.filter((a) => this.decide({ ...ctxBase, action: a }) === 'Permit');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let engine = null;
|
|
121
|
+
let rawRules = null;
|
|
122
|
+
let currentSubject = null;
|
|
123
|
+
function initAbac(rules) {
|
|
124
|
+
engine = new AbacEngine(rules);
|
|
125
|
+
rawRules = rules;
|
|
126
|
+
}
|
|
127
|
+
function getAbacEngine() {
|
|
128
|
+
if (!engine)
|
|
129
|
+
console.warn('ABAC engine non inizializzato');
|
|
130
|
+
return engine;
|
|
131
|
+
}
|
|
132
|
+
function getRawRules() {
|
|
133
|
+
return rawRules;
|
|
134
|
+
}
|
|
135
|
+
function isAbacInitialized() {
|
|
136
|
+
return engine !== null;
|
|
137
|
+
}
|
|
138
|
+
function setSubject(subject) {
|
|
139
|
+
currentSubject = subject;
|
|
140
|
+
}
|
|
141
|
+
function getSubject() {
|
|
142
|
+
return currentSubject;
|
|
143
|
+
}
|
|
144
|
+
function clearSubject() {
|
|
145
|
+
currentSubject = null;
|
|
146
|
+
}
|
|
147
|
+
|
|
65
148
|
const EMPTY_STRING_REGEXP = /^\s*$/;
|
|
66
149
|
/**
|
|
67
150
|
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
|
@@ -85,6 +168,11 @@ const rulesMatcherUtils = {
|
|
|
85
168
|
if (!operators[op]) {
|
|
86
169
|
throw new Error(`Error missing operator:${op}`);
|
|
87
170
|
}
|
|
171
|
+
if (op === '$can') {
|
|
172
|
+
const subject = getSubject();
|
|
173
|
+
const valid = operators['$can'](subject ?? {}, _get(value, 'action'), _get(value, 'resource'));
|
|
174
|
+
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
175
|
+
}
|
|
88
176
|
const valid = operators[op] && operators[op](valueForKey, valueRef, opt, data);
|
|
89
177
|
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
90
178
|
},
|
|
@@ -242,6 +330,11 @@ const rulesMatcherUtils = {
|
|
|
242
330
|
* Defines a set of comparison operators used for matching rules against user input.
|
|
243
331
|
*/
|
|
244
332
|
const operators = {
|
|
333
|
+
$can: (subject, action, resource) => getAbacEngine()?.decide({
|
|
334
|
+
subject: subject ?? {},
|
|
335
|
+
action,
|
|
336
|
+
resource
|
|
337
|
+
}) === 'Permit',
|
|
245
338
|
$exists: (a, b) => !rulesMatcherUtils.isEmpty(a) === b,
|
|
246
339
|
$eq: (a, b) => a === b,
|
|
247
340
|
$ne: (a, b) => a !== b,
|
|
@@ -267,19 +360,19 @@ const operators = {
|
|
|
267
360
|
.some((c) => c instanceof RegExp ? c.test(a) : new RegExp(c, opt).test(a))
|
|
268
361
|
};
|
|
269
362
|
|
|
270
|
-
const rulesMatcher = (rules,
|
|
363
|
+
const rulesMatcher = (rules, dataValue = {}, apply = true, options) => {
|
|
271
364
|
if (!rules)
|
|
272
365
|
return [apply];
|
|
273
366
|
// if (typeof rules !== 'object' && !Array.isArray(rules)) {
|
|
274
367
|
// throw new Error('Rules accept only array or object');
|
|
275
368
|
// }
|
|
276
369
|
if (typeof rules === 'function') {
|
|
277
|
-
return [rules(
|
|
370
|
+
return [rules(dataValue) === apply];
|
|
278
371
|
}
|
|
279
372
|
const conditions = Array.isArray(rules)
|
|
280
373
|
? { $and: rules }
|
|
281
374
|
: rules;
|
|
282
|
-
const valid = rulesMatcherUtils.checkRule(conditions,
|
|
375
|
+
const valid = rulesMatcherUtils.checkRule(conditions, dataValue, options ?? {});
|
|
283
376
|
return [valid === apply];
|
|
284
377
|
};
|
|
285
378
|
|
|
@@ -304,9 +397,6 @@ const flattenRules = (ob) => {
|
|
|
304
397
|
}
|
|
305
398
|
return result;
|
|
306
399
|
};
|
|
307
|
-
const getRulesExists = (rules) => {
|
|
308
|
-
return Object.keys(rules).length ? FlowUtils.mapEdge(rules) : undefined;
|
|
309
|
-
};
|
|
310
400
|
const FlowUtils = {
|
|
311
401
|
generateRulesName: (nextRules) => {
|
|
312
402
|
return nextRules.reduce((acc, inc) => {
|
|
@@ -363,23 +453,6 @@ const FlowUtils = {
|
|
|
363
453
|
return res;
|
|
364
454
|
},
|
|
365
455
|
makeRules: (rules) => Object.entries(rules).reduce((acc2, [k, v]) => [...acc2, { nodeId: k, rules: v }], []),
|
|
366
|
-
// TODO: This function is strictly related to React nodes, could make sense to move it in the flower-react folder
|
|
367
|
-
generateNodesForFlowerJson: (nodes) => nodes
|
|
368
|
-
.filter((e) => !!_get(e, 'props.id'))
|
|
369
|
-
.map((e) => {
|
|
370
|
-
const rules = FlowUtils.makeRules(e.props.to ?? {});
|
|
371
|
-
const nextRules = getRulesExists(rules);
|
|
372
|
-
const children = e.props.data?.children;
|
|
373
|
-
return {
|
|
374
|
-
nodeId: e.props.id,
|
|
375
|
-
nodeType: e.type.displayName || e.props.as || 'FlowerNode',
|
|
376
|
-
nodeTitle: _get(e.props, 'data.title'),
|
|
377
|
-
children,
|
|
378
|
-
nextRules,
|
|
379
|
-
retain: e.props.retain,
|
|
380
|
-
disabled: e.props.disabled
|
|
381
|
-
};
|
|
382
|
-
}),
|
|
383
456
|
allEqual: (arr, arr2) => arr.length === arr2.length && arr.every((v) => arr2.includes(v)),
|
|
384
457
|
findValidRule: (nextRules, value, prefix) => find(nextRules, (rule) => {
|
|
385
458
|
// fix per evitare di entrare in un nodo senza regole, ma con un name,
|
|
@@ -406,7 +479,7 @@ const FlowUtils = {
|
|
|
406
479
|
})
|
|
407
480
|
};
|
|
408
481
|
|
|
409
|
-
const
|
|
482
|
+
const DataUtils = {
|
|
410
483
|
cleanPath: (name, char = '^') => _trimStart(name, char),
|
|
411
484
|
getPath: (idValue) => {
|
|
412
485
|
if (!idValue) {
|
|
@@ -420,9 +493,9 @@ const FormUtils = {
|
|
|
420
493
|
};
|
|
421
494
|
}
|
|
422
495
|
if (idValue.indexOf('^') === 0) {
|
|
423
|
-
const [
|
|
496
|
+
const [rootName, ...rest] = DataUtils.cleanPath(idValue).split('.');
|
|
424
497
|
return {
|
|
425
|
-
|
|
498
|
+
rootName,
|
|
426
499
|
path: rest
|
|
427
500
|
};
|
|
428
501
|
}
|
|
@@ -437,7 +510,7 @@ const FormUtils = {
|
|
|
437
510
|
*/
|
|
438
511
|
const CoreUtils = {
|
|
439
512
|
...FlowUtils,
|
|
440
|
-
...
|
|
513
|
+
...DataUtils
|
|
441
514
|
};
|
|
442
515
|
|
|
443
516
|
const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule } = CoreUtils;
|
|
@@ -650,7 +723,7 @@ const FlowerCoreBaseReducers = {
|
|
|
650
723
|
payload: { name: flowName, node: nextNumberNode }
|
|
651
724
|
});
|
|
652
725
|
},
|
|
653
|
-
|
|
726
|
+
back: (state, { payload }) => {
|
|
654
727
|
const { name, flowName } = payload;
|
|
655
728
|
FlowerCoreBaseReducers.historyPop(state, {
|
|
656
729
|
type: 'historyPop',
|
|
@@ -674,75 +747,65 @@ const FlowerCoreBaseReducers = {
|
|
|
674
747
|
};
|
|
675
748
|
|
|
676
749
|
const { getPath } = CoreUtils;
|
|
677
|
-
/**
|
|
678
|
-
* formName => FlowerForm
|
|
679
|
-
* initialData => FlowerForm
|
|
680
|
-
* fieldName => FlowerField
|
|
681
|
-
* fieldValue => FlowerField
|
|
682
|
-
* errors => FlowerField
|
|
683
|
-
* customErrors => FlowerField
|
|
684
|
-
* fieldTouched => FlowerField
|
|
685
|
-
* fieldDirty => FlowerField
|
|
686
|
-
* fieldHasFocus => FlowerField
|
|
687
|
-
*/
|
|
688
750
|
const FlowerCoreDataReducers = {
|
|
689
|
-
|
|
690
|
-
|
|
751
|
+
setFormSubmitted: (state, { payload }) => {
|
|
752
|
+
const rootPath = typeof payload === 'string' ? payload : payload.rootName;
|
|
753
|
+
if (!_get(state, [rootPath])) {
|
|
691
754
|
return state;
|
|
692
755
|
}
|
|
693
|
-
_set(state,
|
|
756
|
+
_set(state, [rootPath, 'isSubmitted'], true);
|
|
694
757
|
return state;
|
|
695
758
|
},
|
|
696
|
-
|
|
697
|
-
_set(state, [payload.
|
|
759
|
+
addCustomDataErrors: (state, { payload }) => {
|
|
760
|
+
_set(state, [payload.rootName, 'customErrors', payload.id], payload.errors);
|
|
698
761
|
},
|
|
699
|
-
|
|
700
|
-
_set(state, [payload.
|
|
762
|
+
addDataErrors: (state, { payload }) => {
|
|
763
|
+
_set(state, [payload.rootName, 'errors', payload.id], payload.errors);
|
|
701
764
|
},
|
|
702
|
-
|
|
703
|
-
_unset(state, [payload.
|
|
704
|
-
_unset(state, [payload.
|
|
705
|
-
_unset(state, [payload.
|
|
765
|
+
removeDataErrors: (state, { payload }) => {
|
|
766
|
+
_unset(state, [payload.rootName, 'errors', payload.id]);
|
|
767
|
+
_unset(state, [payload.rootName, 'customErrors', payload.id]);
|
|
768
|
+
_unset(state, [payload.rootName, 'isValidating']);
|
|
706
769
|
},
|
|
707
|
-
|
|
708
|
-
_set(state, [payload.
|
|
770
|
+
fieldTouch: (state, { payload }) => {
|
|
771
|
+
_set(state, [payload.rootName, 'touches', payload.id], payload.touched);
|
|
709
772
|
},
|
|
710
|
-
|
|
711
|
-
_set(state, [payload.
|
|
773
|
+
fieldDirty: (state, { payload }) => {
|
|
774
|
+
_set(state, [payload.rootName, 'dirty', payload.id], payload.dirty);
|
|
712
775
|
},
|
|
713
|
-
|
|
776
|
+
fieldFocus: (state, { payload }) => {
|
|
714
777
|
if (!payload.focused) {
|
|
715
|
-
_unset(state, [payload.
|
|
778
|
+
_unset(state, [payload.rootName, 'hasFocus']);
|
|
716
779
|
return;
|
|
717
780
|
}
|
|
718
|
-
_set(state, [payload.
|
|
781
|
+
_set(state, [payload.rootName, 'hasFocus'], payload.id);
|
|
719
782
|
},
|
|
720
783
|
addData: (state, { payload }) => {
|
|
721
|
-
const prevData = _get(state, [payload.
|
|
722
|
-
_set(state, [payload.
|
|
784
|
+
const prevData = _get(state, [payload.rootName, 'data'], {});
|
|
785
|
+
_set(state, [payload.rootName, 'data'], { ...prevData, ...payload.value });
|
|
723
786
|
},
|
|
724
787
|
addDataByPath: (state, { payload }) => {
|
|
725
788
|
const { path: newpath } = getPath(payload.id);
|
|
726
789
|
if (payload.id && payload.id.length) {
|
|
727
|
-
_set(state, [payload.
|
|
790
|
+
_set(state, [payload.rootName, 'data', ...newpath], payload.value);
|
|
728
791
|
if (payload && payload.dirty) {
|
|
729
|
-
_set(state, [payload.
|
|
792
|
+
_set(state, [payload.rootName, 'dirty', payload.id], payload.dirty);
|
|
730
793
|
}
|
|
731
794
|
}
|
|
732
795
|
},
|
|
733
796
|
// TODO usato al momento solo il devtool
|
|
734
797
|
replaceData: /* istanbul ignore next */ (state, { payload }) => {
|
|
735
798
|
/* istanbul ignore next */
|
|
736
|
-
_set(state, [payload.
|
|
799
|
+
_set(state, [payload.rootName, 'data'], payload.value);
|
|
737
800
|
},
|
|
738
801
|
unsetData: (state, { payload }) => {
|
|
739
|
-
_unset(state, [payload.
|
|
802
|
+
_unset(state, [payload.rootName, 'data', ...payload.id]);
|
|
740
803
|
},
|
|
741
|
-
|
|
742
|
-
_set(state, [payload.
|
|
804
|
+
setIsDataValidating: (state, { payload }) => {
|
|
805
|
+
_set(state, [payload.rootName, 'isValidating'], payload.isValidating);
|
|
743
806
|
},
|
|
744
|
-
|
|
745
|
-
const touchedFields = _get(state, [
|
|
807
|
+
resetData: (state, { payload: { rootName, initialData } }) => {
|
|
808
|
+
const touchedFields = _get(state, [rootName, 'errors'], {});
|
|
746
809
|
const newStateData = initialData
|
|
747
810
|
? Object.keys(touchedFields).reduce((acc, key) => {
|
|
748
811
|
const { path } = getPath(key);
|
|
@@ -751,13 +814,13 @@ const FlowerCoreDataReducers = {
|
|
|
751
814
|
return acc;
|
|
752
815
|
}, {})
|
|
753
816
|
: {};
|
|
754
|
-
_set(state, [
|
|
755
|
-
_unset(state, [
|
|
756
|
-
_unset(state, [
|
|
757
|
-
_unset(state, [
|
|
817
|
+
_set(state, [rootName, 'data'], newStateData);
|
|
818
|
+
_unset(state, [rootName, 'touches']);
|
|
819
|
+
_unset(state, [rootName, 'dirty']);
|
|
820
|
+
_unset(state, [rootName, 'isSubmitted']);
|
|
758
821
|
},
|
|
759
|
-
|
|
760
|
-
_set(state, [
|
|
822
|
+
initData: (state, { payload: { rootName, initialData } }) => {
|
|
823
|
+
_set(state, [rootName, 'data'], initialData);
|
|
761
824
|
}
|
|
762
825
|
};
|
|
763
826
|
|
|
@@ -766,8 +829,6 @@ const FlowerCoreReducers = { ...FlowerCoreBaseReducers, ...FlowerCoreDataReducer
|
|
|
766
829
|
const FlowerCoreStateBaseSelectors = {
|
|
767
830
|
selectGlobal: (state) => state && state[exports.REDUCER_NAME.FLOWER_FLOW],
|
|
768
831
|
selectFlower: (name) => (state) => _get(state, [name]),
|
|
769
|
-
// selectFlowerFormNode: (id) => (state) =>
|
|
770
|
-
// _get(state, [REDUCER_NAME.FLOWER_DATA, id]),
|
|
771
832
|
selectFlowerHistory: (flower) => _get(flower, ['history'], []),
|
|
772
833
|
makeSelectNodesIds: (flower) => _get(flower, ['nodes']),
|
|
773
834
|
makeSelectStartNodeId: (flower) => _get(flower, ['startId']),
|
|
@@ -796,24 +857,24 @@ const FlowerCoreStateBaseSelectors = {
|
|
|
796
857
|
|
|
797
858
|
const FlowerCoreStateDataSelectors = {
|
|
798
859
|
selectGlobalReducerByName: (name) => (state) => state[name] ?? state[exports.REDUCER_NAME.FLOWER_DATA][name],
|
|
799
|
-
|
|
860
|
+
selectGlobalData: (state) => {
|
|
800
861
|
return state && state[exports.REDUCER_NAME.FLOWER_DATA];
|
|
801
862
|
},
|
|
802
863
|
// getDataByFlow: (flower) => _get(flower, 'data') ?? {},
|
|
803
864
|
getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
return
|
|
808
|
-
},
|
|
809
|
-
|
|
810
|
-
makeSelectNodeErrors:
|
|
811
|
-
makeSelectFieldError: (name, id, validate) => (
|
|
812
|
-
const customErrors = Object.entries((
|
|
865
|
+
makeSelectNodeDataSubmitted: (data) => data && data.isSubmitted,
|
|
866
|
+
makeSelectNodeDataFieldTouched: (id) => (data) => data && data.touches && data.touches[id],
|
|
867
|
+
makeSelectNodeDataFieldFocused: (id) => (data) => {
|
|
868
|
+
return data && data.hasFocus === id ? id : undefined;
|
|
869
|
+
},
|
|
870
|
+
makeSelectNodeDataFieldDirty: (id) => (data) => data && data.dirty && data.dirty[id],
|
|
871
|
+
makeSelectNodeErrors: generateData,
|
|
872
|
+
makeSelectFieldError: (name, id, validate) => (globalData, data) => {
|
|
873
|
+
const customErrors = Object.entries((data && data.customErrors) || {})
|
|
813
874
|
.filter(([k]) => k === id)
|
|
814
875
|
.map(([, v]) => v)
|
|
815
876
|
.flat();
|
|
816
|
-
if (!validate || !
|
|
877
|
+
if (!validate || !globalData)
|
|
817
878
|
return [];
|
|
818
879
|
const errors = validate.filter((rule) => {
|
|
819
880
|
if (!rule)
|
|
@@ -821,7 +882,7 @@ const FlowerCoreStateDataSelectors = {
|
|
|
821
882
|
if (!rule.rules)
|
|
822
883
|
return true;
|
|
823
884
|
const transformSelf = CoreUtils.mapKeysDeepLodash(rule.rules, (v, key) => key === '$self' ? id : key);
|
|
824
|
-
const [hasError] = rulesMatcher(transformSelf,
|
|
885
|
+
const [hasError] = rulesMatcher(transformSelf, globalData, false, {
|
|
825
886
|
prefix: name
|
|
826
887
|
});
|
|
827
888
|
return hasError;
|
|
@@ -829,8 +890,8 @@ const FlowerCoreStateDataSelectors = {
|
|
|
829
890
|
const result = errors.map((r) => (r && r.message) || 'error');
|
|
830
891
|
return [...customErrors, ...(result.length === 0 ? [] : result)];
|
|
831
892
|
},
|
|
832
|
-
selectorRulesDisabled: (id, rules, keys, flowName, value) => (
|
|
833
|
-
const newState = { ...
|
|
893
|
+
selectorRulesDisabled: (id, rules, keys, flowName, value) => (globalData, data) => {
|
|
894
|
+
const newState = { ...globalData, ...value, $data: data, $form: data };
|
|
834
895
|
const state = Object.assign(newState, id ? { $self: _get(newState, [flowName, ...id.split('.')]) } : {});
|
|
835
896
|
if (!rules)
|
|
836
897
|
return false;
|
|
@@ -855,7 +916,9 @@ const FlowerCoreStateSelectors = {
|
|
|
855
916
|
...FlowerCoreStateDataSelectors
|
|
856
917
|
};
|
|
857
918
|
|
|
919
|
+
exports.AbacEngine = AbacEngine;
|
|
858
920
|
exports.CoreUtils = CoreUtils;
|
|
921
|
+
exports.DataUtils = DataUtils;
|
|
859
922
|
exports.Emitter = Emitter;
|
|
860
923
|
exports.FlowUtils = FlowUtils;
|
|
861
924
|
exports.FlowerCoreBaseReducers = FlowerCoreBaseReducers;
|
|
@@ -865,9 +928,15 @@ exports.FlowerCoreStateBaseSelectors = FlowerCoreStateBaseSelectors;
|
|
|
865
928
|
exports.FlowerCoreStateDataSelectors = FlowerCoreStateDataSelectors;
|
|
866
929
|
exports.FlowerCoreStateSelectors = FlowerCoreStateSelectors;
|
|
867
930
|
exports.FlowerStateUtils = FlowerStateUtils;
|
|
868
|
-
exports.
|
|
869
|
-
exports.createFormData = createFormData;
|
|
931
|
+
exports.clearSubject = clearSubject;
|
|
870
932
|
exports.devtoolState = devtoolState;
|
|
871
933
|
exports.flattenRules = flattenRules;
|
|
934
|
+
exports.generateData = generateData;
|
|
935
|
+
exports.getAbacEngine = getAbacEngine;
|
|
936
|
+
exports.getRawRules = getRawRules;
|
|
937
|
+
exports.getSubject = getSubject;
|
|
938
|
+
exports.initAbac = initAbac;
|
|
939
|
+
exports.isAbacInitialized = isAbacInitialized;
|
|
872
940
|
exports.rulesMatcher = rulesMatcher;
|
|
873
941
|
exports.rulesMatcherUtils = rulesMatcherUtils;
|
|
942
|
+
exports.setSubject = setSubject;
|