@flowerforce/flower-core 3.3.1-beta.2 → 4.0.1-beta.1
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/index.cjs.js +238 -266
- package/dist/index.esm.js +228 -265
- package/dist/src/constants/index.d.ts +5 -0
- package/dist/src/event-emitter/index.d.ts +1 -0
- package/dist/src/index.d.ts +6 -8
- package/dist/src/interfaces/CoreInterface.d.ts +23 -17
- package/dist/src/interfaces/ReducerInterface.d.ts +109 -109
- package/dist/src/{rules-matcher/interface.d.ts → interfaces/RulesMatcherInterface.d.ts} +1 -1
- package/dist/src/interfaces/SelectorsInterface.d.ts +34 -25
- package/dist/src/interfaces/Store.d.ts +2 -10
- package/dist/src/interfaces/UtilsInterface.d.ts +1 -1
- package/dist/src/interfaces/index.d.ts +3 -0
- package/dist/src/rules-matcher/RulesMatcher.d.ts +2 -0
- package/dist/src/rules-matcher/index.d.ts +2 -0
- package/dist/src/rules-matcher/utils.d.ts +2 -3
- package/dist/src/state-manager/index.d.ts +2 -0
- package/dist/src/state-manager/state-functions/FlowerCoreMergedReducers.d.ts +2 -0
- package/dist/src/state-manager/state-functions/FlowerCoreStateFunctions.d.ts +5 -0
- package/dist/src/state-manager/state-functions/FlowerDataStateFunctions.d.ts +2 -0
- package/dist/src/state-manager/state-functions/index.d.ts +4 -0
- package/dist/src/state-manager/state-selectors/FlowerCoreStateSelectors.d.ts +2 -0
- package/dist/src/state-manager/state-selectors/FlowerDataStateSelectors.d.ts +2 -0
- package/dist/src/state-manager/state-selectors/FlowerSelectorsMerged.d.ts +2 -0
- package/dist/src/state-manager/state-selectors/index.d.ts +4 -0
- package/dist/src/{FlowerCoreStateUtils.d.ts → utils/FlowerCoreStateUtils.d.ts} +2 -2
- package/dist/src/{CoreUtils.d.ts → utils/FlowerCoreUtils.d.ts} +1 -2
- package/dist/src/utils/FlowerDataCoreUtils.d.ts +2 -0
- package/dist/src/utils/FlowerFlowUtils.d.ts +3 -0
- package/dist/src/utils/index.d.ts +4 -0
- package/package.json +1 -1
- package/dist/src/FlowerCoreStateFunctions.d.ts +0 -5
- package/dist/src/FlowerCoreStateSelectors.d.ts +0 -2
- package/dist/src/RulesMatcher.d.ts +0 -5
- package/dist/src/devtoolState.d.ts +0 -2
- /package/dist/src/{Emitter.d.ts → event-emitter/Emitter.d.ts} +0 -0
package/dist/index.esm.js
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
import { TinyEmitter } from 'tiny-emitter';
|
2
|
-
import _set from 'lodash/set';
|
3
|
-
import _unset from 'lodash/unset';
|
4
2
|
import _get from 'lodash/get';
|
5
|
-
import _last from 'lodash/last';
|
6
|
-
import _slice from 'lodash/slice';
|
7
|
-
import _cloneDeep from 'lodash/cloneDeep';
|
8
|
-
import lastIndexOf from 'lodash/lastIndexOf';
|
9
3
|
import find from 'lodash/find';
|
10
4
|
import keyBy from 'lodash/keyBy';
|
11
5
|
import has from 'lodash/has';
|
@@ -16,10 +10,56 @@ import mapKeys from 'lodash/mapKeys';
|
|
16
10
|
import mapValues from 'lodash/mapValues';
|
17
11
|
import _trimStart from 'lodash/trimStart';
|
18
12
|
import _intersection from 'lodash/intersection';
|
13
|
+
import _set from 'lodash/set';
|
14
|
+
import _last from 'lodash/last';
|
15
|
+
import _slice from 'lodash/slice';
|
16
|
+
import _cloneDeep from 'lodash/cloneDeep';
|
17
|
+
import lastIndexOf from 'lodash/lastIndexOf';
|
18
|
+
import _unset from 'lodash/unset';
|
19
19
|
import { unflatten } from 'flat';
|
20
20
|
|
21
21
|
const Emitter = new TinyEmitter();
|
22
22
|
|
23
|
+
var REDUCER_NAME;
|
24
|
+
(function (REDUCER_NAME) {
|
25
|
+
REDUCER_NAME["FLOWER_FLOW"] = "FlowerFlow";
|
26
|
+
REDUCER_NAME["FLOWER_DATA"] = "FlowerData";
|
27
|
+
})(REDUCER_NAME || (REDUCER_NAME = {}));
|
28
|
+
const devtoolState = {};
|
29
|
+
|
30
|
+
const FlowerStateUtils = {
|
31
|
+
getAllData: (state) => state &&
|
32
|
+
Object.entries(state ?? {}).reduce((acc, [k, v]) => ({ ...acc, [k]: v?.data ?? v }), {}),
|
33
|
+
selectFlowerDataNode: (name) => (state) => _get(state, name),
|
34
|
+
makeSelectCurrentNextRules: (name) => (state) => {
|
35
|
+
const nextRules = _get(state, [name, 'nextRules']);
|
36
|
+
const currentNodeId = FlowerStateUtils.makeSelectCurrentNodeId(name)(state);
|
37
|
+
return _get(nextRules, [currentNodeId]);
|
38
|
+
},
|
39
|
+
makeSelectCurrentNodeId: (name) => (state) => {
|
40
|
+
const subState = _get(state, [name]);
|
41
|
+
const startId = _get(state, ['startId']);
|
42
|
+
return _get(subState, ['current']) || startId;
|
43
|
+
},
|
44
|
+
makeSelectNodeErrors: (name) => (state) => {
|
45
|
+
const data = FlowerStateUtils.selectFlowerDataNode(name)(state);
|
46
|
+
return generateData(data);
|
47
|
+
}
|
48
|
+
};
|
49
|
+
const generateData = (data) => {
|
50
|
+
const validationErrors = data && data.errors;
|
51
|
+
const allErrors = Object.values(validationErrors || {});
|
52
|
+
return {
|
53
|
+
isSubmitted: data?.isSubmitted || false,
|
54
|
+
isDirty: Object.values(data?.dirty || {}).some(Boolean) || false,
|
55
|
+
hasFocus: data?.hasFocus,
|
56
|
+
errors: data?.errors,
|
57
|
+
customErrors: data?.customErrors,
|
58
|
+
isValidating: data?.isValidating,
|
59
|
+
isValid: allErrors.flat().length === 0
|
60
|
+
};
|
61
|
+
};
|
62
|
+
|
23
63
|
const EMPTY_STRING_REGEXP = /^\s*$/;
|
24
64
|
/**
|
25
65
|
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
@@ -225,25 +265,21 @@ const operators = {
|
|
225
265
|
.some((c) => c instanceof RegExp ? c.test(a) : new RegExp(c, opt).test(a))
|
226
266
|
};
|
227
267
|
|
228
|
-
const rulesMatcher = (rules,
|
268
|
+
const rulesMatcher = (rules, dataValue = {}, apply = true, options) => {
|
229
269
|
if (!rules)
|
230
270
|
return [apply];
|
231
271
|
// if (typeof rules !== 'object' && !Array.isArray(rules)) {
|
232
272
|
// throw new Error('Rules accept only array or object');
|
233
273
|
// }
|
234
274
|
if (typeof rules === 'function') {
|
235
|
-
return [rules(
|
275
|
+
return [rules(dataValue) === apply];
|
236
276
|
}
|
237
277
|
const conditions = Array.isArray(rules)
|
238
278
|
? { $and: rules }
|
239
279
|
: rules;
|
240
|
-
const valid = rulesMatcherUtils.checkRule(conditions,
|
280
|
+
const valid = rulesMatcherUtils.checkRule(conditions, dataValue, options ?? {});
|
241
281
|
return [valid === apply];
|
242
282
|
};
|
243
|
-
const MatchRules = {
|
244
|
-
rulesMatcher,
|
245
|
-
utils: rulesMatcherUtils
|
246
|
-
};
|
247
283
|
|
248
284
|
/* eslint-disable no-useless-escape */
|
249
285
|
// TODO align this set of functions to selectors and reducers functions
|
@@ -266,36 +302,12 @@ const flattenRules = (ob) => {
|
|
266
302
|
}
|
267
303
|
return result;
|
268
304
|
};
|
269
|
-
// export const searchEmptyKeyRecursively = <T extends object>(
|
270
|
-
// _key: "$and" | "$or",
|
271
|
-
// obj: T
|
272
|
-
// ) => {
|
273
|
-
// if (
|
274
|
-
// isEmpty(obj) ||
|
275
|
-
// typeof obj !== "object" ||
|
276
|
-
// Object.keys(obj).length === 0
|
277
|
-
// ) {
|
278
|
-
// return true;
|
279
|
-
// }
|
280
|
-
// if (Object.keys(obj).includes(_key)) {
|
281
|
-
// if (obj[_key] && obj[_key].length === 0) return true;
|
282
|
-
// return Object.keys(obj).map((key) =>
|
283
|
-
// searchEmptyKeyRecursively(_key, obj[key])
|
284
|
-
// );
|
285
|
-
// }
|
286
|
-
// return Object.keys(obj)
|
287
|
-
// .map((key) => searchEmptyKeyRecursively(_key, obj[key]))
|
288
|
-
// .every((v) => v === true);
|
289
|
-
// };
|
290
305
|
const getRulesExists = (rules) => {
|
291
|
-
return Object.keys(rules).length ?
|
306
|
+
return Object.keys(rules).length ? FlowUtils.mapEdge(rules) : undefined;
|
292
307
|
};
|
293
|
-
|
294
|
-
* Defines a collection of utility functions for processing rules, nodes and graph-like structures
|
295
|
-
*/
|
296
|
-
const CoreUtils = {
|
308
|
+
const FlowUtils = {
|
297
309
|
generateRulesName: (nextRules) => {
|
298
|
-
|
310
|
+
return nextRules.reduce((acc, inc) => {
|
299
311
|
const n = typeof inc.rules === 'string'
|
300
312
|
? inc.rules || '__ERROR_NAME__'
|
301
313
|
: inc.rules?.name || '__ERROR_NAME__';
|
@@ -304,7 +316,6 @@ const CoreUtils = {
|
|
304
316
|
[n]: inc.nodeId
|
305
317
|
};
|
306
318
|
}, {});
|
307
|
-
return a;
|
308
319
|
},
|
309
320
|
mapKeysDeepLodash: (obj, cb, isRecursive) => {
|
310
321
|
/* istanbul ignore next */
|
@@ -320,13 +331,13 @@ const CoreUtils = {
|
|
320
331
|
}
|
321
332
|
}
|
322
333
|
if (Array.isArray(obj)) {
|
323
|
-
return obj.map((item) =>
|
334
|
+
return obj.map((item) => FlowUtils.mapKeysDeepLodash(item, cb, true));
|
324
335
|
}
|
325
336
|
if (!isPlainObject(obj)) {
|
326
337
|
return obj;
|
327
338
|
}
|
328
339
|
const result = mapKeys(obj, cb);
|
329
|
-
return mapValues(result, (value) =>
|
340
|
+
return mapValues(result, (value) => FlowUtils.mapKeysDeepLodash(value, cb, true));
|
330
341
|
},
|
331
342
|
generateNodes: (nodes) => keyBy(nodes.map((s) => omit(s, 'nextRules')), 'nodeId'),
|
332
343
|
makeObjectRules: (nodes) => nodes.reduce((acc, inc) => ({ ...acc, [inc.nodeId]: inc.nextRules }), {}),
|
@@ -343,17 +354,18 @@ const CoreUtils = {
|
|
343
354
|
},
|
344
355
|
mapEdge: (nextNode) => {
|
345
356
|
const res = nextNode.sort((a, b) => {
|
346
|
-
const x =
|
347
|
-
const y =
|
357
|
+
const x = FlowUtils.isEmptyRules(a.rules);
|
358
|
+
const y = FlowUtils.isEmptyRules(b.rules);
|
348
359
|
return Number(x) - Number(y);
|
349
360
|
});
|
350
361
|
return res;
|
351
362
|
},
|
352
363
|
makeRules: (rules) => Object.entries(rules).reduce((acc2, [k, v]) => [...acc2, { nodeId: k, rules: v }], []),
|
364
|
+
// TODO: This function is strictly related to React nodes, could make sense to move it in the flower-react folder
|
353
365
|
generateNodesForFlowerJson: (nodes) => nodes
|
354
366
|
.filter((e) => !!_get(e, 'props.id'))
|
355
367
|
.map((e) => {
|
356
|
-
const rules =
|
368
|
+
const rules = FlowUtils.makeRules(e.props.to ?? {});
|
357
369
|
const nextRules = getRulesExists(rules);
|
358
370
|
const children = e.props.data?.children;
|
359
371
|
return {
|
@@ -366,29 +378,6 @@ const CoreUtils = {
|
|
366
378
|
disabled: e.props.disabled
|
367
379
|
};
|
368
380
|
}),
|
369
|
-
cleanPath: (name, char = '^') => _trimStart(name, char),
|
370
|
-
getPath: (idValue) => {
|
371
|
-
if (!idValue) {
|
372
|
-
return {
|
373
|
-
path: []
|
374
|
-
};
|
375
|
-
}
|
376
|
-
if (idValue === '*') {
|
377
|
-
return {
|
378
|
-
path: '*'
|
379
|
-
};
|
380
|
-
}
|
381
|
-
if (idValue.indexOf('^') === 0) {
|
382
|
-
const [flowNameFromPath, ...rest] = CoreUtils.cleanPath(idValue).split('.');
|
383
|
-
return {
|
384
|
-
flowNameFromPath,
|
385
|
-
path: rest
|
386
|
-
};
|
387
|
-
}
|
388
|
-
return {
|
389
|
-
path: idValue.split('.')
|
390
|
-
};
|
391
|
-
},
|
392
381
|
allEqual: (arr, arr2) => arr.length === arr2.length && arr.every((v) => arr2.includes(v)),
|
393
382
|
findValidRule: (nextRules, value, prefix) => find(nextRules, (rule) => {
|
394
383
|
// fix per evitare di entrare in un nodo senza regole, ma con un name,
|
@@ -408,53 +397,52 @@ const CoreUtils = {
|
|
408
397
|
if (typeof rule.rules.rules === 'string') {
|
409
398
|
return false;
|
410
399
|
}
|
411
|
-
const [valid] =
|
400
|
+
const [valid] = rulesMatcher(rule.rules.rules, value, true, {
|
412
401
|
prefix
|
413
402
|
});
|
414
403
|
return valid;
|
415
404
|
})
|
416
405
|
};
|
417
406
|
|
418
|
-
const
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
407
|
+
const DataUtils = {
|
408
|
+
cleanPath: (name, char = '^') => _trimStart(name, char),
|
409
|
+
getPath: (idValue) => {
|
410
|
+
if (!idValue) {
|
411
|
+
return {
|
412
|
+
path: []
|
413
|
+
};
|
414
|
+
}
|
415
|
+
if (idValue === '*') {
|
416
|
+
return {
|
417
|
+
path: '*'
|
418
|
+
};
|
419
|
+
}
|
420
|
+
if (idValue.indexOf('^') === 0) {
|
421
|
+
const [rootName, ...rest] = DataUtils.cleanPath(idValue).split('.');
|
422
|
+
return {
|
423
|
+
rootName,
|
424
|
+
path: rest
|
425
|
+
};
|
426
|
+
}
|
427
|
+
return {
|
428
|
+
path: idValue.split('.')
|
429
|
+
};
|
435
430
|
}
|
436
431
|
};
|
437
|
-
const createFormData = (form) => {
|
438
|
-
const validationErrors = form && form.errors;
|
439
|
-
const allErrors = Object.values(validationErrors || {});
|
440
|
-
return {
|
441
|
-
isSubmitted: form?.isSubmitted || false,
|
442
|
-
isDirty: Object.values(form?.dirty || {}).some(Boolean) || false,
|
443
|
-
hasFocus: form?.hasFocus,
|
444
|
-
errors: form?.errors,
|
445
|
-
customErrors: form?.customErrors,
|
446
|
-
isValidating: form?.isValidating,
|
447
|
-
isValid: allErrors.flat().length === 0
|
448
|
-
};
|
449
|
-
};
|
450
432
|
|
451
|
-
|
433
|
+
/**
|
434
|
+
* Defines a collection of utility functions for processing rules, nodes and graph-like structures
|
435
|
+
*/
|
436
|
+
const CoreUtils = {
|
437
|
+
...FlowUtils,
|
438
|
+
...DataUtils
|
439
|
+
};
|
452
440
|
|
453
|
-
const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule
|
441
|
+
const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule } = CoreUtils;
|
454
442
|
/**
|
455
443
|
* These functions are Redux reducers used in a Flux architecture for managing state transitions and updates in a Flower application.
|
456
444
|
*/
|
457
|
-
const
|
445
|
+
const FlowerCoreBaseReducers = {
|
458
446
|
historyAdd: (state, { payload }) => {
|
459
447
|
if (hasNode(state, payload.name, payload.node)) {
|
460
448
|
state[payload.name].history.push(payload.node);
|
@@ -473,27 +461,11 @@ const FlowerCoreReducers = {
|
|
473
461
|
}
|
474
462
|
return state;
|
475
463
|
},
|
476
|
-
setFormTouched: (state, { payload }) => {
|
477
|
-
if (!_get(state, [
|
478
|
-
typeof payload === 'string' ? payload : payload.flowName,
|
479
|
-
'nodes',
|
480
|
-
typeof payload === 'string' ? payload : payload.currentNode
|
481
|
-
])) {
|
482
|
-
return state;
|
483
|
-
}
|
484
|
-
_set(state, [
|
485
|
-
typeof payload === 'string' ? payload : payload.flowName,
|
486
|
-
'form',
|
487
|
-
typeof payload === 'string' ? payload : payload.currentNode,
|
488
|
-
'isSubmitted'
|
489
|
-
], true);
|
490
|
-
return state;
|
491
|
-
},
|
492
464
|
// TODO check internal logic and use case
|
493
465
|
/* istanbul ignore next */
|
494
466
|
forceAddHistory: (state, { payload }) => {
|
495
467
|
const { name, flowName, history } = payload;
|
496
|
-
const key = name || flowName || ''
|
468
|
+
const key = name || flowName || '';
|
497
469
|
const resultHistory = history.slice(1, -1);
|
498
470
|
state[key].history.push(...resultHistory);
|
499
471
|
return state;
|
@@ -566,7 +538,8 @@ const FlowerCoreReducers = {
|
|
566
538
|
return state;
|
567
539
|
},
|
568
540
|
destroy: (state, { payload }) => {
|
569
|
-
|
541
|
+
delete state[payload.name];
|
542
|
+
return state;
|
570
543
|
},
|
571
544
|
initNodes: (state, { payload }) => {
|
572
545
|
if (payload.persist && _get(state, [payload.name, 'persist']))
|
@@ -589,8 +562,7 @@ const FlowerCoreReducers = {
|
|
589
562
|
current,
|
590
563
|
history,
|
591
564
|
nodes: generateNodes(payload.nodes),
|
592
|
-
nextRules: makeObjectRules(payload.nodes)
|
593
|
-
data: payload.initialData
|
565
|
+
nextRules: makeObjectRules(payload.nodes)
|
594
566
|
});
|
595
567
|
},
|
596
568
|
// TODO usato solo da flower su vscode
|
@@ -607,91 +579,14 @@ const FlowerCoreReducers = {
|
|
607
579
|
}
|
608
580
|
}
|
609
581
|
},
|
610
|
-
formAddCustomErrors: (state, { payload }) => {
|
611
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'customErrors', payload.id], payload.errors);
|
612
|
-
},
|
613
|
-
formAddErrors: (state, { payload }) => {
|
614
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'errors', payload.id], payload.errors);
|
615
|
-
},
|
616
|
-
formRemoveErrors: (state, { payload }) => {
|
617
|
-
_unset(state, [
|
618
|
-
payload.name,
|
619
|
-
'form',
|
620
|
-
payload.currentNode,
|
621
|
-
'errors',
|
622
|
-
payload.id
|
623
|
-
]);
|
624
|
-
_unset(state, [
|
625
|
-
payload.name,
|
626
|
-
'form',
|
627
|
-
payload.currentNode,
|
628
|
-
'customErrors',
|
629
|
-
payload.id
|
630
|
-
]);
|
631
|
-
_unset(state, [payload.name, 'form', payload.currentNode, 'isValidating']);
|
632
|
-
},
|
633
|
-
formFieldTouch: (state, { payload }) => {
|
634
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'touches', payload.id], payload.touched);
|
635
|
-
},
|
636
|
-
formFieldDirty: (state, { payload }) => {
|
637
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'dirty', payload.id], payload.dirty);
|
638
|
-
},
|
639
|
-
formFieldFocus: (state, { payload }) => {
|
640
|
-
if (!payload.focused) {
|
641
|
-
_unset(state, [payload.name, 'form', payload.currentNode, 'hasFocus']);
|
642
|
-
return;
|
643
|
-
}
|
644
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'hasFocus'], payload.id);
|
645
|
-
},
|
646
|
-
addData: (state, { payload }) => {
|
647
|
-
const prevData = _get(state, [payload.flowName, 'data']);
|
648
|
-
_set(state, [payload.flowName, 'data'], { ...prevData, ...payload.value });
|
649
|
-
},
|
650
|
-
addDataByPath: (state, { payload }) => {
|
651
|
-
const { path: newpath } = getPath(payload.id);
|
652
|
-
const currentNode = FlowerStateUtils.makeSelectCurrentNodeId(payload.flowName)(state);
|
653
|
-
if (payload.id && payload.id.length) {
|
654
|
-
_set(state, [payload.flowName, 'data', ...newpath], payload.value);
|
655
|
-
if (payload && payload.dirty) {
|
656
|
-
_set(state, [payload.flowName, 'form', currentNode, 'dirty', payload.id], payload.dirty);
|
657
|
-
}
|
658
|
-
}
|
659
|
-
},
|
660
|
-
// TODO usato al momento solo il devtool
|
661
|
-
replaceData: /* istanbul ignore next */ (state, { payload }) => {
|
662
|
-
/* istanbul ignore next */
|
663
|
-
_set(state, [payload.flowName, 'data'], payload.value);
|
664
|
-
},
|
665
|
-
unsetData: (state, { payload }) => {
|
666
|
-
_unset(state, [payload.flowName, 'data', ...payload.id]);
|
667
|
-
},
|
668
|
-
setFormIsValidating: (state, { payload }) => {
|
669
|
-
_set(state, [payload.name, 'form', payload.currentNode, 'isValidating'], payload.isValidating);
|
670
|
-
},
|
671
|
-
resetForm: (state, { payload }) => {
|
672
|
-
const touchedFields = _get(state, [payload.flowName, 'form', payload.id, 'errors'], {});
|
673
|
-
Object.keys(touchedFields).forEach((key) => {
|
674
|
-
const { flowNameFromPath = payload.flowName, path } = getPath(key);
|
675
|
-
_unset(state, [flowNameFromPath, 'data', ...path]);
|
676
|
-
});
|
677
|
-
_unset(state, [payload.flowName, 'form', payload.id, 'touches']);
|
678
|
-
_unset(state, [payload.flowName, 'form', payload.id, 'dirty']);
|
679
|
-
_unset(state, [payload.flowName, 'form', payload.id, 'isSubmitted']);
|
680
|
-
},
|
681
582
|
node: (state, { payload }) => {
|
682
583
|
const { name, history } = payload;
|
683
584
|
const node = payload.nodeId || payload.node || '';
|
684
585
|
const flowName = name || payload.flowName || '';
|
685
|
-
const startNode = _get(state, [payload.name, 'startId']);
|
686
|
-
const currentNodeId = _get(state, [payload.name, 'current'], startNode);
|
687
|
-
FlowerCoreReducers.setFormTouched(state, {
|
688
|
-
type: 'setFormTouched',
|
689
|
-
payload: { flowName, currentNode: currentNodeId }
|
690
|
-
});
|
691
586
|
/* istanbul ignore next */
|
692
587
|
// eslint-disable-next-line no-underscore-dangle
|
693
588
|
if (devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS__') && history) {
|
694
|
-
|
589
|
+
FlowerCoreBaseReducers.forceAddHistory(state, {
|
695
590
|
type: 'forceAddHistory',
|
696
591
|
payload: {
|
697
592
|
name,
|
@@ -700,34 +595,35 @@ const FlowerCoreReducers = {
|
|
700
595
|
}
|
701
596
|
});
|
702
597
|
}
|
703
|
-
|
598
|
+
FlowerCoreBaseReducers.historyAdd(state, {
|
704
599
|
type: 'historyAdd',
|
705
600
|
payload: { name: name || flowName || '', node }
|
706
601
|
});
|
707
602
|
},
|
708
603
|
prevToNode: (state, { payload }) => {
|
709
604
|
const { node, name, flowName } = payload;
|
710
|
-
|
605
|
+
FlowerCoreBaseReducers.historyPrevToNode(state, {
|
711
606
|
type: 'historyPrevToNode',
|
712
607
|
payload: { name: name || flowName || '', node }
|
713
608
|
});
|
714
609
|
},
|
715
610
|
next: (state, { payload }) => {
|
716
|
-
const { name, data = {},
|
717
|
-
const flowName = name ||
|
611
|
+
const { name, route, flowName: flow, data = {}, dataIn = {} } = payload;
|
612
|
+
const flowName = name || flow || '';
|
613
|
+
const { FlowerData, FlowerFlow, ...external } = data;
|
718
614
|
const currentNodeId = FlowerStateUtils.makeSelectCurrentNodeId(flowName)(state);
|
719
615
|
const currentNextRules = FlowerStateUtils.makeSelectCurrentNextRules(flowName)(state);
|
720
|
-
const
|
721
|
-
const
|
616
|
+
const $data = FlowerStateUtils.makeSelectNodeErrors(flowName, currentNodeId)(FlowerData);
|
617
|
+
const internalClonedData = _cloneDeep(FlowerStateUtils.getAllData(FlowerData));
|
618
|
+
const externalClonedData = _cloneDeep(FlowerStateUtils.getAllData(external));
|
722
619
|
const stateWithNodeData = {
|
723
|
-
$in:
|
724
|
-
$
|
725
|
-
|
620
|
+
$in: dataIn,
|
621
|
+
/** @deprecated use $data instead */
|
622
|
+
$form: $data,
|
623
|
+
$data,
|
624
|
+
...externalClonedData,
|
625
|
+
...internalClonedData
|
726
626
|
};
|
727
|
-
FlowerCoreReducers.setFormTouched(state, {
|
728
|
-
type: 'setFormTouched',
|
729
|
-
payload: { flowName, currentNode: currentNodeId }
|
730
|
-
});
|
731
627
|
if (!currentNextRules) {
|
732
628
|
return;
|
733
629
|
}
|
@@ -736,7 +632,7 @@ const FlowerCoreReducers = {
|
|
736
632
|
if (!rulesByName[route]) {
|
737
633
|
return;
|
738
634
|
}
|
739
|
-
|
635
|
+
FlowerCoreBaseReducers.historyAdd(state, {
|
740
636
|
type: 'historyAdd',
|
741
637
|
payload: { name: flowName, node: rulesByName[route] }
|
742
638
|
});
|
@@ -747,51 +643,120 @@ const FlowerCoreReducers = {
|
|
747
643
|
if (!nextNumberNode) {
|
748
644
|
return;
|
749
645
|
}
|
750
|
-
|
646
|
+
FlowerCoreBaseReducers.historyAdd(state, {
|
751
647
|
type: 'historyAdd',
|
752
648
|
payload: { name: flowName, node: nextNumberNode }
|
753
649
|
});
|
754
650
|
},
|
755
651
|
prev: (state, { payload }) => {
|
756
652
|
const { name, flowName } = payload;
|
757
|
-
|
653
|
+
FlowerCoreBaseReducers.historyPop(state, {
|
758
654
|
type: 'historyPop',
|
759
655
|
payload: { name: name || flowName || '' }
|
760
656
|
});
|
761
657
|
},
|
762
658
|
restart: (state, { payload }) => {
|
763
659
|
const { name, flowName } = payload;
|
764
|
-
|
660
|
+
FlowerCoreBaseReducers.restoreHistory(state, {
|
765
661
|
type: 'restoreHistory',
|
766
662
|
payload: { name: name || flowName || '' }
|
767
663
|
});
|
768
664
|
},
|
769
665
|
reset: (state, { payload }) => {
|
770
|
-
const { name, flowName
|
771
|
-
|
666
|
+
const { name, flowName } = payload;
|
667
|
+
FlowerCoreBaseReducers.restoreHistory(state, {
|
772
668
|
type: 'restoreHistory',
|
773
669
|
payload: { name: name || flowName || '' }
|
774
670
|
});
|
775
|
-
_set(state, [name || flowName || '', 'form'], {});
|
776
|
-
_set(state, [name || flowName || '', 'data'], initialData);
|
777
671
|
}
|
778
672
|
};
|
779
673
|
|
780
|
-
const
|
781
|
-
|
674
|
+
const { getPath } = CoreUtils;
|
675
|
+
const FlowerCoreDataReducers = {
|
676
|
+
setFormSubmitted: (state, { payload }) => {
|
677
|
+
const rootPath = typeof payload === 'string' ? payload : payload.rootName;
|
678
|
+
if (!_get(state, [rootPath])) {
|
679
|
+
return state;
|
680
|
+
}
|
681
|
+
_set(state, [rootPath, 'isSubmitted'], true);
|
682
|
+
return state;
|
683
|
+
},
|
684
|
+
addCustomDataErrors: (state, { payload }) => {
|
685
|
+
_set(state, [payload.rootName, 'customErrors', payload.id], payload.errors);
|
686
|
+
},
|
687
|
+
addDataErrors: (state, { payload }) => {
|
688
|
+
_set(state, [payload.rootName, 'errors', payload.id], payload.errors);
|
689
|
+
},
|
690
|
+
removeDataErrors: (state, { payload }) => {
|
691
|
+
_unset(state, [payload.rootName, 'errors', payload.id]);
|
692
|
+
_unset(state, [payload.rootName, 'customErrors', payload.id]);
|
693
|
+
_unset(state, [payload.rootName, 'isValidating']);
|
694
|
+
},
|
695
|
+
fieldTouch: (state, { payload }) => {
|
696
|
+
_set(state, [payload.rootName, 'touches', payload.id], payload.touched);
|
697
|
+
},
|
698
|
+
fieldDirty: (state, { payload }) => {
|
699
|
+
_set(state, [payload.rootName, 'dirty', payload.id], payload.dirty);
|
700
|
+
},
|
701
|
+
fieldFocus: (state, { payload }) => {
|
702
|
+
if (!payload.focused) {
|
703
|
+
_unset(state, [payload.rootName, 'hasFocus']);
|
704
|
+
return;
|
705
|
+
}
|
706
|
+
_set(state, [payload.rootName, 'hasFocus'], payload.id);
|
707
|
+
},
|
708
|
+
addData: (state, { payload }) => {
|
709
|
+
const prevData = _get(state, [payload.rootName, 'data'], {});
|
710
|
+
_set(state, [payload.rootName, 'data'], { ...prevData, ...payload.value });
|
711
|
+
},
|
712
|
+
addDataByPath: (state, { payload }) => {
|
713
|
+
const { path: newpath } = getPath(payload.id);
|
714
|
+
if (payload.id && payload.id.length) {
|
715
|
+
_set(state, [payload.rootName, 'data', ...newpath], payload.value);
|
716
|
+
if (payload && payload.dirty) {
|
717
|
+
_set(state, [payload.rootName, 'dirty', payload.id], payload.dirty);
|
718
|
+
}
|
719
|
+
}
|
720
|
+
},
|
721
|
+
// TODO usato al momento solo il devtool
|
722
|
+
replaceData: /* istanbul ignore next */ (state, { payload }) => {
|
723
|
+
/* istanbul ignore next */
|
724
|
+
_set(state, [payload.rootName, 'data'], payload.value);
|
725
|
+
},
|
726
|
+
unsetData: (state, { payload }) => {
|
727
|
+
_unset(state, [payload.rootName, 'data', ...payload.id]);
|
728
|
+
},
|
729
|
+
setIsDataValidating: (state, { payload }) => {
|
730
|
+
_set(state, [payload.rootName, 'isValidating'], payload.isValidating);
|
731
|
+
},
|
732
|
+
resetData: (state, { payload: { rootName, initialData } }) => {
|
733
|
+
const touchedFields = _get(state, [rootName, 'errors'], {});
|
734
|
+
const newStateData = initialData
|
735
|
+
? Object.keys(touchedFields).reduce((acc, key) => {
|
736
|
+
const { path } = getPath(key);
|
737
|
+
const initialDataByPath = _get(initialData, [...path], undefined);
|
738
|
+
_set(acc, [...path], initialDataByPath);
|
739
|
+
return acc;
|
740
|
+
}, {})
|
741
|
+
: {};
|
742
|
+
_set(state, [rootName, 'data'], newStateData);
|
743
|
+
_unset(state, [rootName, 'touches']);
|
744
|
+
_unset(state, [rootName, 'dirty']);
|
745
|
+
_unset(state, [rootName, 'isSubmitted']);
|
746
|
+
},
|
747
|
+
initData: (state, { payload: { rootName, initialData } }) => {
|
748
|
+
_set(state, [rootName, 'data'], initialData);
|
749
|
+
}
|
750
|
+
};
|
751
|
+
|
752
|
+
const FlowerCoreReducers = { ...FlowerCoreBaseReducers, ...FlowerCoreDataReducers };
|
753
|
+
|
754
|
+
const FlowerCoreStateBaseSelectors = {
|
755
|
+
selectGlobal: (state) => state && state[REDUCER_NAME.FLOWER_FLOW],
|
782
756
|
selectFlower: (name) => (state) => _get(state, [name]),
|
783
|
-
selectFlowerFormNode: (id) => (state) => _get(state, ['form', id]),
|
784
757
|
selectFlowerHistory: (flower) => _get(flower, ['history'], []),
|
785
758
|
makeSelectNodesIds: (flower) => _get(flower, ['nodes']),
|
786
759
|
makeSelectStartNodeId: (flower) => _get(flower, ['startId']),
|
787
|
-
getDataByFlow: (flower) => _get(flower, ['data']) ?? {},
|
788
|
-
getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
|
789
|
-
makeSelectNodeFormSubmitted: (form) => form && form.isSubmitted,
|
790
|
-
makeSelectNodeFormFieldTouched: (id) => (form) => form && form.touches && form.touches[id],
|
791
|
-
makeSelectNodeFormFieldFocused: (id) => (form) => {
|
792
|
-
return form && form.hasFocus === id ? id : undefined;
|
793
|
-
},
|
794
|
-
makeSelectNodeFormFieldDirty: (id) => (form) => form && form.dirty && form.dirty[id],
|
795
760
|
makeSelectCurrentNodeId: (flower, startNodeId) => _get(flower, ['current']) || startNodeId,
|
796
761
|
makeSelectCurrentNodeDisabled: (nodes, current) => !!_get(nodes, [current, 'disabled']),
|
797
762
|
makeSelectPrevNodeRetain: (nodes, history, current) => {
|
@@ -812,14 +777,29 @@ const FlowerCoreStateSelectors = {
|
|
812
777
|
return nodes[prevFlowerNode] && nodes[prevFlowerNode].retain
|
813
778
|
? prevFlowerNode
|
814
779
|
: undefined;
|
780
|
+
}
|
781
|
+
};
|
782
|
+
|
783
|
+
const FlowerCoreStateDataSelectors = {
|
784
|
+
selectGlobalReducerByName: (name) => (state) => state[name] ?? state[REDUCER_NAME.FLOWER_DATA][name],
|
785
|
+
selectGlobalData: (state) => {
|
786
|
+
return state && state[REDUCER_NAME.FLOWER_DATA];
|
815
787
|
},
|
816
|
-
|
817
|
-
|
818
|
-
|
788
|
+
// getDataByFlow: (flower) => _get(flower, 'data') ?? {},
|
789
|
+
getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
|
790
|
+
makeSelectNodeDataSubmitted: (data) => data && data.isSubmitted,
|
791
|
+
makeSelectNodeDataFieldTouched: (id) => (data) => data && data.touches && data.touches[id],
|
792
|
+
makeSelectNodeDataFieldFocused: (id) => (data) => {
|
793
|
+
return data && data.hasFocus === id ? id : undefined;
|
794
|
+
},
|
795
|
+
makeSelectNodeDataFieldDirty: (id) => (data) => data && data.dirty && data.dirty[id],
|
796
|
+
makeSelectNodeErrors: generateData,
|
797
|
+
makeSelectFieldError: (name, id, validate) => (globalData, data) => {
|
798
|
+
const customErrors = Object.entries((data && data.customErrors) || {})
|
819
799
|
.filter(([k]) => k === id)
|
820
800
|
.map(([, v]) => v)
|
821
801
|
.flat();
|
822
|
-
if (!validate || !
|
802
|
+
if (!validate || !globalData)
|
823
803
|
return [];
|
824
804
|
const errors = validate.filter((rule) => {
|
825
805
|
if (!rule)
|
@@ -827,7 +807,7 @@ const FlowerCoreStateSelectors = {
|
|
827
807
|
if (!rule.rules)
|
828
808
|
return true;
|
829
809
|
const transformSelf = CoreUtils.mapKeysDeepLodash(rule.rules, (v, key) => key === '$self' ? id : key);
|
830
|
-
const [hasError] =
|
810
|
+
const [hasError] = rulesMatcher(transformSelf, globalData, false, {
|
831
811
|
prefix: name
|
832
812
|
});
|
833
813
|
return hasError;
|
@@ -835,8 +815,8 @@ const FlowerCoreStateSelectors = {
|
|
835
815
|
const result = errors.map((r) => (r && r.message) || 'error');
|
836
816
|
return [...customErrors, ...(result.length === 0 ? [] : result)];
|
837
817
|
},
|
838
|
-
selectorRulesDisabled: (id, rules, keys, flowName, value) => (
|
839
|
-
const newState = { ...
|
818
|
+
selectorRulesDisabled: (id, rules, keys, flowName, value) => (globalData, data) => {
|
819
|
+
const newState = { ...globalData, ...value, $data: data, $form: data };
|
840
820
|
const state = Object.assign(newState, id ? { $self: _get(newState, [flowName, ...id.split('.')]) } : {});
|
841
821
|
if (!rules)
|
842
822
|
return false;
|
@@ -849,33 +829,16 @@ const FlowerCoreStateSelectors = {
|
|
849
829
|
const k = inc;
|
850
830
|
return Object.assign(acc, { [k]: _get(state, k) });
|
851
831
|
}, {});
|
852
|
-
const [disabled] =
|
832
|
+
const [disabled] = rulesMatcher(rules, { ...unflatten(res) }, false, {
|
833
|
+
prefix: flowName
|
834
|
+
});
|
853
835
|
return disabled;
|
854
836
|
}
|
855
837
|
};
|
856
838
|
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
RulesOperators["$ne"] = "$ne";
|
862
|
-
RulesOperators["$gt"] = "$gt";
|
863
|
-
RulesOperators["$gte"] = "$gte";
|
864
|
-
RulesOperators["$lt"] = "$lt";
|
865
|
-
RulesOperators["$lte"] = "$lte";
|
866
|
-
RulesOperators["$strGt"] = "$strGt";
|
867
|
-
RulesOperators["$strGte"] = "$strGte";
|
868
|
-
RulesOperators["$strLt"] = "$strLt";
|
869
|
-
RulesOperators["$strLte"] = "$strLte";
|
870
|
-
RulesOperators["$in"] = "$in";
|
871
|
-
RulesOperators["$nin"] = "$nin";
|
872
|
-
RulesOperators["$all"] = "$all";
|
873
|
-
RulesOperators["$regex"] = "$regex";
|
874
|
-
})(RulesOperators || (RulesOperators = {}));
|
875
|
-
var RulesModes;
|
876
|
-
(function (RulesModes) {
|
877
|
-
RulesModes["$and"] = "$and";
|
878
|
-
RulesModes["$or"] = "$or";
|
879
|
-
})(RulesModes || (RulesModes = {}));
|
839
|
+
const FlowerCoreStateSelectors = {
|
840
|
+
...FlowerCoreStateBaseSelectors,
|
841
|
+
...FlowerCoreStateDataSelectors
|
842
|
+
};
|
880
843
|
|
881
|
-
export { CoreUtils, Emitter,
|
844
|
+
export { CoreUtils, DataUtils, Emitter, FlowUtils, FlowerCoreBaseReducers, FlowerCoreDataReducers, FlowerCoreReducers, FlowerCoreStateBaseSelectors, FlowerCoreStateDataSelectors, FlowerCoreStateSelectors, FlowerStateUtils, REDUCER_NAME, devtoolState, flattenRules, generateData, rulesMatcher, rulesMatcherUtils };
|