@icure/form 3.1.0 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/cache/{markdown-it-npm-14.1.0-e337d75bfe-07296b45eb.zip → markdown-it-npm-14.1.1-45c173274d-d6d55865c6.zip} +0 -0
- package/.yarn/install-state.gz +0 -0
- package/components/icure-button-group/index.js +1 -1
- package/components/icure-button-group/index.js.map +1 -1
- package/components/icure-form/index.js +14 -9
- package/components/icure-form/index.js.map +1 -1
- package/components/icure-form/renderer/form/form.js +5 -3
- package/components/icure-form/renderer/form/form.js.map +1 -1
- package/components/model/index.d.ts +1 -1
- package/components/model/index.js.map +1 -1
- package/icure/form-values-container.d.ts +5 -4
- package/icure/form-values-container.js +117 -33
- package/icure/form-values-container.js.map +1 -1
- package/package.json +1 -1
- package/utils/code-utils.js +2 -2
- package/utils/code-utils.js.map +1 -1
|
@@ -12,8 +12,8 @@ import { sortedBy } from '../utils/no-lodash';
|
|
|
12
12
|
import { areCodesEqual, codeStubToCode, contentToPrimitiveType, isContentEqual, primitiveTypeToContent } from './icure-utils';
|
|
13
13
|
import { parsePrimitive } from '../utils/primitive';
|
|
14
14
|
import { anyDateToDate, dateToFuzzyDate } from '../utils/dates';
|
|
15
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
16
15
|
import { normalizeCodes } from '../utils/code-utils';
|
|
16
|
+
let _ordinal = 0;
|
|
17
17
|
function notify(l, fvc, changedKeys, force = false) {
|
|
18
18
|
l(fvc, changedKeys, force);
|
|
19
19
|
}
|
|
@@ -84,11 +84,12 @@ export class BridgedFormValuesContainer {
|
|
|
84
84
|
this.changeListeners = changeListeners;
|
|
85
85
|
this.interpreterContext = interpreterContext;
|
|
86
86
|
this.dependenciesCache = dependenciesCache;
|
|
87
|
-
this._id =
|
|
87
|
+
this._id = '';
|
|
88
88
|
this.dependentValuesComputationIteration = undefined;
|
|
89
|
-
console.log(`Creating bridge FVC (${contactFormValuesContainer.rootForm.formTemplateId}) with ${contactFormValuesContainer.children.length} children [${this._id}]`);
|
|
90
89
|
//Before start to broadcast changes, we need to fill in the contactFormValuesContainer with the dependent values
|
|
91
90
|
this.contactFormValuesContainer = contactFormValuesContainer;
|
|
91
|
+
this._id = `[${contactFormValuesContainer._id}]`;
|
|
92
|
+
console.log(`+ BFVC ${this._id} created`);
|
|
92
93
|
this.mutateAndNotify = (newContactFormValuesContainer, changedKeys, force = false) => {
|
|
93
94
|
if (this.changeListeners.length === 0) {
|
|
94
95
|
return;
|
|
@@ -277,7 +278,7 @@ export class BridgedFormValuesContainer {
|
|
|
277
278
|
return __awaiter(this, void 0, void 0, function* () {
|
|
278
279
|
const iterate = (changedKeys, iterationCount) => __awaiter(this, void 0, void 0, function* () {
|
|
279
280
|
if (this.contactFormValuesContainer.rootForm.formTemplateId) {
|
|
280
|
-
console.log(
|
|
281
|
+
console.log(`% ${iterationCount}, keys: ${changedKeys ? changedKeys.join(', ') : 'all'}`);
|
|
281
282
|
return yield Promise.all(this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
|
|
282
283
|
var _b, _c;
|
|
283
284
|
try {
|
|
@@ -339,7 +340,12 @@ export class BridgedFormValuesContainer {
|
|
|
339
340
|
allChangedKeys.push(...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []));
|
|
340
341
|
};
|
|
341
342
|
changes.forEach(([id, metadata, language, newValue]) => {
|
|
342
|
-
|
|
343
|
+
try {
|
|
344
|
+
setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, language, newValue !== null && newValue !== void 0 ? newValue : undefined, id, metadata, interceptor);
|
|
345
|
+
}
|
|
346
|
+
catch (e) {
|
|
347
|
+
console.log(`Error while applying dependent value change for ${metadata.label} (${id})`, e);
|
|
348
|
+
}
|
|
343
349
|
});
|
|
344
350
|
return allChangedKeys;
|
|
345
351
|
}
|
|
@@ -385,6 +391,7 @@ export class BridgedFormValuesContainer {
|
|
|
385
391
|
.join(', ');
|
|
386
392
|
};
|
|
387
393
|
const log = console.log;
|
|
394
|
+
// noinspection JSUnusedGlobalSymbols
|
|
388
395
|
const native = {
|
|
389
396
|
parseInt: parseInt,
|
|
390
397
|
parseFloat: parseFloat,
|
|
@@ -446,9 +453,7 @@ export class BridgedFormValuesContainer {
|
|
|
446
453
|
}
|
|
447
454
|
getChildren() {
|
|
448
455
|
return __awaiter(this, void 0, void 0, function* () {
|
|
449
|
-
|
|
450
|
-
console.log(`${children.length} children found in ${this.contactFormValuesContainer.rootForm.formTemplateId} initialised with `, this.initialValuesProvider);
|
|
451
|
-
return children;
|
|
456
|
+
return yield Promise.all((yield this.contactFormValuesContainer.getChildren()).map((fvc) => new BridgedFormValuesContainer(this.responsible, fvc, this.interpreter, this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, [], this.interpreterContext).init()));
|
|
452
457
|
});
|
|
453
458
|
}
|
|
454
459
|
getValidationErrors() {
|
|
@@ -518,17 +523,20 @@ export class ContactFormValuesContainer {
|
|
|
518
523
|
allForms() {
|
|
519
524
|
return [this.rootForm].concat(this.children.flatMap((c) => c.allForms()));
|
|
520
525
|
}
|
|
521
|
-
constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], initialised = true) {
|
|
522
|
-
|
|
526
|
+
constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], anchorId, initialised = true) {
|
|
527
|
+
var _a;
|
|
528
|
+
this._id = '';
|
|
523
529
|
this._initialised = false;
|
|
524
|
-
|
|
530
|
+
this.rootForm = rootForm;
|
|
531
|
+
this._id = `${((_a = rootForm.formTemplateId) !== null && _a !== void 0 ? _a : '').substring(0, 4)}.${++_ordinal}`;
|
|
532
|
+
console.log(`+ CFVC: ${this._id} with children { ${children.map((c) => c._id).join(', ')} }`);
|
|
525
533
|
if (contactsHistory.includes(currentContact)) {
|
|
526
534
|
throw new Error('Illegal argument, the history must not contain the currentContact');
|
|
527
535
|
}
|
|
528
|
-
this.rootForm = rootForm;
|
|
529
536
|
this.currentContact = currentContact;
|
|
530
537
|
this.contactsHistory = sortedBy(contactsHistory, 'created', 'desc');
|
|
531
538
|
this.children = children;
|
|
539
|
+
this.anchorId = anchorId;
|
|
532
540
|
this.serviceFactory = serviceFactory;
|
|
533
541
|
this.formFactory = formFactory;
|
|
534
542
|
this.formRecycler = formRecycler;
|
|
@@ -536,7 +544,7 @@ export class ContactFormValuesContainer {
|
|
|
536
544
|
this._initialised = initialised;
|
|
537
545
|
this.indexedServices = [this.currentContact].concat(this.contactsHistory).reduce((acc, ctc) => {
|
|
538
546
|
var _a, _b, _c;
|
|
539
|
-
|
|
547
|
+
return ((_c = (_b = (_a = ctc.services) === null || _a === void 0 ? void 0 : _a.filter((s) => { var _a; return (_a = ctc.subContacts) === null || _a === void 0 ? void 0 : _a.some((sc) => { var _a; return sc.formId === this.rootForm.id && ((_a = sc.services) === null || _a === void 0 ? void 0 : _a.some((sss) => sss.serviceId === s.id)); }); })) === null || _b === void 0 ? void 0 : _b.reduce((acc, s) => {
|
|
540
548
|
var _a, _b;
|
|
541
549
|
return s.id
|
|
542
550
|
? Object.assign(Object.assign({}, acc), { [s.id]: ((_a = acc[s.id]) !== null && _a !== void 0 ? _a : (acc[s.id] = [])).concat({
|
|
@@ -544,26 +552,29 @@ export class ContactFormValuesContainer {
|
|
|
544
552
|
modified: ctc.created,
|
|
545
553
|
value: s,
|
|
546
554
|
}) }) : acc;
|
|
547
|
-
}, acc)) !== null && _c !== void 0 ? _c : acc;
|
|
548
|
-
return services;
|
|
555
|
+
}, acc)) !== null && _c !== void 0 ? _c : acc);
|
|
549
556
|
}, {});
|
|
550
557
|
this.synchronise();
|
|
551
558
|
}
|
|
552
559
|
synchronise() {
|
|
553
560
|
this.children.forEach((childFVC) => {
|
|
554
|
-
|
|
561
|
+
var _a;
|
|
562
|
+
this.registerChildFormValuesContainer(childFVC.synchronise(), (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : '');
|
|
555
563
|
});
|
|
556
564
|
return this;
|
|
557
565
|
}
|
|
558
566
|
//Make sure that when a child is changed, a new version of this is created with the updated child
|
|
559
|
-
registerChildFormValuesContainer(childFormValueContainer) {
|
|
567
|
+
registerChildFormValuesContainer(childFormValueContainer, anchorId) {
|
|
560
568
|
childFormValueContainer.changeListeners = [
|
|
561
|
-
(newValue) => {
|
|
569
|
+
(newValue, changedKeys, force) => {
|
|
570
|
+
if ((changedKeys === null || changedKeys === void 0 ? void 0 : changedKeys.length) === 0 && !force) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
562
573
|
console.log(`Child ${newValue._id} ${childFormValueContainer.rootForm.formTemplateId} changed, updating parent ${this._id} ${this.rootForm.formTemplateId}`);
|
|
563
574
|
const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.map((c) => {
|
|
564
575
|
return c.rootForm.id === childFormValueContainer.rootForm.id ? newValue : c;
|
|
565
|
-
}), this.formFactory, this.formRecycler);
|
|
566
|
-
this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer,
|
|
576
|
+
}), this.formFactory, this.formRecycler, [], this.anchorId, true);
|
|
577
|
+
this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, null));
|
|
567
578
|
},
|
|
568
579
|
];
|
|
569
580
|
}
|
|
@@ -573,8 +584,8 @@ export class ContactFormValuesContainer {
|
|
|
573
584
|
? yield Promise.all((yield formChildrenProvider(rootForm.id)).map((f) => __awaiter(this, void 0, void 0, function* () {
|
|
574
585
|
// eslint-disable-next-line max-len
|
|
575
586
|
return yield ContactFormValuesContainer.fromFormsHierarchy(f, currentContact, contactsHistory, serviceFactory, formChildrenProvider, formFactory, formRecycler); })))
|
|
576
|
-
: [], formFactory, formRecycler, changeListeners, false);
|
|
577
|
-
contactFormValuesContainer.children.forEach((childFVC) => contactFormValuesContainer.registerChildFormValuesContainer(childFVC));
|
|
587
|
+
: [], formFactory, formRecycler, changeListeners, rootForm.descr, false);
|
|
588
|
+
contactFormValuesContainer.children.forEach((childFVC) => { var _a; return contactFormValuesContainer.registerChildFormValuesContainer(childFVC, (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : 'all'); });
|
|
578
589
|
return contactFormValuesContainer;
|
|
579
590
|
});
|
|
580
591
|
}
|
|
@@ -646,8 +657,8 @@ export class ContactFormValuesContainer {
|
|
|
646
657
|
meta.valueDate && (newService.valueDate = meta.valueDate);
|
|
647
658
|
meta.codes && (newService.codes = normalizeCodes(meta.codes));
|
|
648
659
|
meta.tags && (newService.tags = normalizeCodes(meta.tags));
|
|
649
|
-
const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => (s.id === service.id ? newService : s)) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
|
|
650
|
-
this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label]
|
|
660
|
+
const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => (s.id === service.id ? newService : s)) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
|
|
661
|
+
this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label]));
|
|
651
662
|
}
|
|
652
663
|
}
|
|
653
664
|
setValue(label, language, value, id, metadata, changeListenersOverrider) {
|
|
@@ -711,7 +722,7 @@ export class ContactFormValuesContainer {
|
|
|
711
722
|
? ((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []).map((s) => (s.id === service.id ? newService : s))
|
|
712
723
|
: [...((_w = this.currentContact.services) !== null && _w !== void 0 ? _w : []), newService] }));
|
|
713
724
|
}
|
|
714
|
-
const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, newCurrentContact, this.contactsHistory.map((c) => (c === this.currentContact ? newCurrentContact : c)), this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
|
|
725
|
+
const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, newCurrentContact, this.contactsHistory.map((c) => (c === this.currentContact ? newCurrentContact : c)), this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
|
|
715
726
|
changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer, [label]) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [label]));
|
|
716
727
|
}
|
|
717
728
|
}
|
|
@@ -721,8 +732,8 @@ export class ContactFormValuesContainer {
|
|
|
721
732
|
if (service) {
|
|
722
733
|
const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => s.id === serviceId
|
|
723
734
|
? new DecryptedService(Object.assign(Object.assign({}, service), { endOfLife: Date.now() }))
|
|
724
|
-
: s) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
|
|
725
|
-
this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, []));
|
|
735
|
+
: s) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
|
|
736
|
+
this.changeListeners.forEach((l) => { var _a; return notify(l, newFormValuesContainer, [(_a = service.label) !== null && _a !== void 0 ? _a : service.id] /* only the label is going to propagate the changes for the formulas */); });
|
|
726
737
|
}
|
|
727
738
|
}
|
|
728
739
|
toMarkdownTable() {
|
|
@@ -788,10 +799,12 @@ export class ContactFormValuesContainer {
|
|
|
788
799
|
if (!parentId)
|
|
789
800
|
return;
|
|
790
801
|
const newForm = yield this.formFactory(parentId, anchorId, templateId, label);
|
|
791
|
-
const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], false);
|
|
792
|
-
const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners);
|
|
793
|
-
newContactFormValuesContainer.registerChildFormValuesContainer(childFVC);
|
|
794
|
-
this.changeListeners.forEach((l) =>
|
|
802
|
+
const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], anchorId, false);
|
|
803
|
+
const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
|
|
804
|
+
newContactFormValuesContainer.registerChildFormValuesContainer(childFVC, anchorId);
|
|
805
|
+
this.changeListeners.forEach((l) => {
|
|
806
|
+
notify(l, newContactFormValuesContainer, null);
|
|
807
|
+
});
|
|
795
808
|
});
|
|
796
809
|
}
|
|
797
810
|
getServiceInCurrentContact(id) {
|
|
@@ -801,13 +814,84 @@ export class ContactFormValuesContainer {
|
|
|
801
814
|
}
|
|
802
815
|
removeChild(container) {
|
|
803
816
|
return __awaiter(this, void 0, void 0, function* () {
|
|
804
|
-
const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.filter((c) => c.rootForm.id !== container.rootForm.id), this.formFactory, this.formRecycler, this.changeListeners);
|
|
805
|
-
this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, []));
|
|
817
|
+
const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.filter((c) => c.rootForm.id !== container.rootForm.id), this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
|
|
818
|
+
this.changeListeners.forEach((l) => { var _a; return notify(l, newContactFormValuesContainer, [`subForms_${(_a = container.anchorId) !== null && _a !== void 0 ? _a : 'all'}`]); });
|
|
806
819
|
});
|
|
807
820
|
}
|
|
808
821
|
}
|
|
822
|
+
// Runtime validation for FieldValue — guards against mistyped data coming from
|
|
823
|
+
// external callers (formulas, SDK bridges, etc.) where the TypeScript types may
|
|
824
|
+
// not match the actual runtime values.
|
|
825
|
+
const validatePrimitiveType = (pt, path) => {
|
|
826
|
+
const v = pt.value;
|
|
827
|
+
switch (pt.type) {
|
|
828
|
+
case 'string':
|
|
829
|
+
if (typeof v !== 'string') {
|
|
830
|
+
throw new Error(`${path}: expected string value, got ${typeof v}`);
|
|
831
|
+
}
|
|
832
|
+
break;
|
|
833
|
+
case 'number':
|
|
834
|
+
if (typeof v !== 'number') {
|
|
835
|
+
throw new Error(`${path}: expected number value, got ${typeof v}`);
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
case 'boolean':
|
|
839
|
+
if (typeof v !== 'boolean') {
|
|
840
|
+
throw new Error(`${path}: expected boolean value, got ${typeof v}`);
|
|
841
|
+
}
|
|
842
|
+
break;
|
|
843
|
+
case 'timestamp':
|
|
844
|
+
if (typeof v !== 'number') {
|
|
845
|
+
throw new Error(`${path}: expected number value for timestamp, got ${typeof v}`);
|
|
846
|
+
}
|
|
847
|
+
break;
|
|
848
|
+
case 'datetime':
|
|
849
|
+
if (typeof v !== 'number') {
|
|
850
|
+
throw new Error(`${path}: expected number value for datetime, got ${typeof v}`);
|
|
851
|
+
}
|
|
852
|
+
break;
|
|
853
|
+
case 'measure': {
|
|
854
|
+
const m = pt;
|
|
855
|
+
if (m.value !== undefined && typeof m.value !== 'number') {
|
|
856
|
+
throw new Error(`${path}: expected number or undefined value for measure, got ${typeof m.value}`);
|
|
857
|
+
}
|
|
858
|
+
if (m.unit !== undefined && typeof m.unit !== 'string') {
|
|
859
|
+
throw new Error(`${path}: expected string or undefined unit for measure, got ${typeof m.unit}`);
|
|
860
|
+
}
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
case 'compound':
|
|
864
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v)) {
|
|
865
|
+
throw new Error(`${path}: expected object value for compound, got ${Array.isArray(v) ? 'array' : typeof v}`);
|
|
866
|
+
}
|
|
867
|
+
for (const [key, subValue] of Object.entries(v)) {
|
|
868
|
+
validatePrimitiveType(subValue, `${path}.compound[${key}]`);
|
|
869
|
+
}
|
|
870
|
+
break;
|
|
871
|
+
default:
|
|
872
|
+
throw new Error(`${path}: unknown PrimitiveType type: ${pt.type}`);
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
const validateCode = (code, path) => {
|
|
876
|
+
const id = code.id;
|
|
877
|
+
if (!id || typeof id !== 'string') {
|
|
878
|
+
throw new Error(`${path}: code must have a non-empty string id, got ${JSON.stringify(id)}`);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
const validateFieldValue = (fv, language, label) => {
|
|
882
|
+
const pt = fv.content[language];
|
|
883
|
+
if (pt) {
|
|
884
|
+
validatePrimitiveType(pt, `FieldValue[${label}].content[${language}]`);
|
|
885
|
+
}
|
|
886
|
+
if (fv.codes) {
|
|
887
|
+
fv.codes.forEach((code, i) => validateCode(code, `FieldValue[${label}].codes[${i}]`));
|
|
888
|
+
}
|
|
889
|
+
};
|
|
809
890
|
const setValueOnContactFormValuesContainer = (cfvc, label, language, fv, id, metadata, changeListenersOverrider) => {
|
|
810
891
|
var _a, _b, _c, _d;
|
|
892
|
+
if (fv) {
|
|
893
|
+
validateFieldValue(fv, language, label);
|
|
894
|
+
}
|
|
811
895
|
const value = fv === null || fv === void 0 ? void 0 : fv.content[language];
|
|
812
896
|
cfvc.setValue(label, language, new DecryptedService({
|
|
813
897
|
id: id,
|