@icure/form 3.0.45 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/.yarn/cache/{@babel-runtime-npm-7.28.4-31bc1b0001-934b0a0460.zip → @babel-runtime-npm-7.28.6-f40c99aeef-42d8a868c2.zip} +0 -0
  2. package/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.5.1-3b3c832bd1-22c404c481.zip +0 -0
  3. package/.yarn/cache/@lit-reactive-element-npm-2.1.2-2c713bebce-e0ed931b9c.zip +0 -0
  4. package/.yarn/cache/{lit-element-npm-4.2.1-b5bc114ced-5925326176.zip → lit-element-npm-4.2.2-70d4af2233-554254b87c.zip} +0 -0
  5. package/.yarn/cache/lit-html-npm-3.3.2-4a3e00215f-7fe23502ca.zip +0 -0
  6. package/.yarn/cache/{lit-npm-3.3.1-8f683c51f1-fb88f1ff80.zip → lit-npm-3.3.2-7dea58471e-2136d4beac.zip} +0 -0
  7. package/.yarn/cache/prosemirror-markdown-npm-1.13.4-1a47b172bd-3306b4eca0.zip +0 -0
  8. package/.yarn/cache/prosemirror-transform-npm-1.11.0-fa260ad6f3-71989931b8.zip +0 -0
  9. package/.yarn/cache/prosemirror-view-npm-1.41.6-a9d2feed27-68f6a8bd66.zip +0 -0
  10. package/.yarn/install-state.gz +0 -0
  11. package/components/common/field.d.ts +14 -2
  12. package/components/common/field.js +95 -2
  13. package/components/common/field.js.map +1 -1
  14. package/components/common/utils.js +11 -1
  15. package/components/common/utils.js.map +1 -1
  16. package/components/icure-form/fields/button-group/checkbox.js +3 -4
  17. package/components/icure-form/fields/button-group/checkbox.js.map +1 -1
  18. package/components/icure-form/fields/button-group/radio-button.js +3 -4
  19. package/components/icure-form/fields/button-group/radio-button.js.map +1 -1
  20. package/components/icure-form/fields/date-picker/date-picker.js +3 -4
  21. package/components/icure-form/fields/date-picker/date-picker.js.map +1 -1
  22. package/components/icure-form/fields/date-picker/date-time-picker.js +3 -4
  23. package/components/icure-form/fields/date-picker/date-time-picker.js.map +1 -1
  24. package/components/icure-form/fields/date-picker/time-picker.js +3 -4
  25. package/components/icure-form/fields/date-picker/time-picker.js.map +1 -1
  26. package/components/icure-form/fields/dropdown/dropdown-field.js +3 -4
  27. package/components/icure-form/fields/dropdown/dropdown-field.js.map +1 -1
  28. package/components/icure-form/fields/measure-field/measure-field.js +3 -4
  29. package/components/icure-form/fields/measure-field/measure-field.js.map +1 -1
  30. package/components/icure-form/fields/number-field/number-field.js +3 -4
  31. package/components/icure-form/fields/number-field/number-field.js.map +1 -1
  32. package/components/icure-form/fields/text-field/text-field.js +3 -4
  33. package/components/icure-form/fields/text-field/text-field.js.map +1 -1
  34. package/components/icure-form/fields/utils/index.d.ts +0 -5
  35. package/components/icure-form/fields/utils/index.js +0 -8
  36. package/components/icure-form/fields/utils/index.js.map +1 -1
  37. package/components/icure-form/index.js +0 -1
  38. package/components/icure-form/index.js.map +1 -1
  39. package/components/icure-form/renderer/form/form.js +4 -4
  40. package/components/icure-form/renderer/form/form.js.map +1 -1
  41. package/components/icure-text-field/index.d.ts +3 -0
  42. package/components/icure-text-field/index.js +65 -13
  43. package/components/icure-text-field/index.js.map +1 -1
  44. package/components/icure-text-field/schema/measure-schema.js +0 -1
  45. package/components/icure-text-field/schema/measure-schema.js.map +1 -1
  46. package/components/model/index.d.ts +16 -16
  47. package/components/model/index.js +34 -30
  48. package/components/model/index.js.map +1 -1
  49. package/conversion/icure-convert.d.ts +3 -0
  50. package/conversion/icure-convert.js +161 -0
  51. package/conversion/icure-convert.js.map +1 -0
  52. package/generic/model.d.ts +11 -6
  53. package/generic/model.js.map +1 -1
  54. package/icure/form-values-container.d.ts +23 -18
  55. package/icure/form-values-container.js +208 -99
  56. package/icure/form-values-container.js.map +1 -1
  57. package/icure/icure-utils.js +47 -17
  58. package/icure/icure-utils.js.map +1 -1
  59. package/package.json +1 -1
  60. package/utils/fields-values-provider.d.ts +1 -1
  61. package/utils/fields-values-provider.js +6 -4
  62. package/utils/fields-values-provider.js.map +1 -1
  63. package/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.4.0-e5ef5fbeba-e267c25576.zip +0 -0
  64. package/.yarn/cache/@lit-reactive-element-npm-2.1.1-3875228c32-b9bbc9c089.zip +0 -0
  65. package/.yarn/cache/lit-html-npm-3.3.1-e3722d4f4a-de07c66945.zip +0 -0
  66. package/.yarn/cache/prosemirror-markdown-npm-1.13.2-6e2f179fd8-ce9fcb3b13.zip +0 -0
  67. package/.yarn/cache/prosemirror-transform-npm-1.10.5-5b3b4f5f61-6f5921e53a.zip +0 -0
  68. package/.yarn/cache/prosemirror-view-npm-1.41.4-cf361fd330-b663b8c6ce.zip +0 -0
@@ -14,8 +14,28 @@ import { parsePrimitive } from '../utils/primitive';
14
14
  import { anyDateToDate, dateToFuzzyDate } from '../utils/dates';
15
15
  import { v4 as uuidv4 } from 'uuid';
16
16
  import { normalizeCodes } from '../utils/code-utils';
17
- function notify(l, fvc) {
18
- l(fvc);
17
+ function notify(l, fvc, changedKeys, force = false) {
18
+ l(fvc, changedKeys, force);
19
+ }
20
+ function primitiveTypeToString(pt) {
21
+ switch (pt.type) {
22
+ case 'string':
23
+ return pt.value;
24
+ case 'number':
25
+ return pt.value.toString();
26
+ case 'boolean':
27
+ return pt.value.toString();
28
+ case 'measure':
29
+ return pt.value !== undefined ? `${pt.value}${pt.unit ? ' ' + pt.unit : ''}` : '';
30
+ case 'timestamp':
31
+ return new Date(pt.value).toISOString();
32
+ case 'datetime':
33
+ return pt.value.toString();
34
+ case 'compound':
35
+ return Object.entries(pt.value)
36
+ .map(([k, v]) => `${k}: ${primitiveTypeToString(v)}`)
37
+ .join(', ');
38
+ }
19
39
  }
20
40
  /** This class is a bridge between the ICure API and the generic FormValuesContainer interface.
21
41
  * It wraps around a ContactFormValuesContainer and provides a series of services:
@@ -52,8 +72,9 @@ export class BridgedFormValuesContainer {
52
72
  * @param language The language in which the values are displayed
53
73
  * @param changeListeners The listeners that will be notified when the values change
54
74
  * @param interpreterContext A map with keys that are the names of the variables and values that are the functions that return the values of the variables
75
+ * @param dependenciesCache
55
76
  */
56
- constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}) {
77
+ constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}, dependenciesCache = {}) {
57
78
  this.responsible = responsible;
58
79
  this.interpreter = interpreter;
59
80
  this.initialValuesProvider = initialValuesProvider;
@@ -62,25 +83,53 @@ export class BridgedFormValuesContainer {
62
83
  this.language = language;
63
84
  this.changeListeners = changeListeners;
64
85
  this.interpreterContext = interpreterContext;
86
+ this.dependenciesCache = dependenciesCache;
65
87
  this._id = uuidv4();
88
+ this.dependentValuesComputationIteration = undefined;
66
89
  console.log(`Creating bridge FVC (${contactFormValuesContainer.rootForm.formTemplateId}) with ${contactFormValuesContainer.children.length} children [${this._id}]`);
67
90
  //Before start to broadcast changes, we need to fill in the contactFormValuesContainer with the dependent values
68
91
  this.contactFormValuesContainer = contactFormValuesContainer;
69
- this.mutateAndNotify = (newContactFormValuesContainer) => __awaiter(this, void 0, void 0, function* () {
92
+ this.mutateAndNotify = (newContactFormValuesContainer, changedKeys, force = false) => {
93
+ if (this.changeListeners.length === 0) {
94
+ return;
95
+ }
96
+ if (!force && this.contactFormValuesContainer === newContactFormValuesContainer) {
97
+ return;
98
+ }
99
+ this.contactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
70
100
  newContactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
71
- const newBridgedFormValueContainer = yield new BridgedFormValuesContainer(this.responsible, newContactFormValuesContainer, this.interpreter, this.contact === this.contactFormValuesContainer.currentContact ? newContactFormValuesContainer.currentContact : this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, this.changeListeners, this.interpreterContext).init();
72
- this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer));
73
- return newBridgedFormValueContainer;
74
- });
101
+ const newBridgedFormValueContainer = new BridgedFormValuesContainer(this.responsible, newContactFormValuesContainer, this.interpreter, this.contact === this.contactFormValuesContainer.currentContact ? newContactFormValuesContainer.currentContact : this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, this.changeListeners, this.interpreterContext, this.dependenciesCache);
102
+ const initPromise = newBridgedFormValueContainer.init(changedKeys, this.dependentValuesComputationIteration);
103
+ this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer, changedKeys));
104
+ initPromise.catch((e) => {
105
+ console.log('Error while initializing new BridgedFormValuesContainer', e);
106
+ });
107
+ };
75
108
  this.contactFormValuesContainer.registerChangeListener(this.mutateAndNotify);
76
109
  this.contact = contact !== null && contact !== void 0 ? contact : contactFormValuesContainer.currentContact;
77
110
  }
111
+ /* init can be called several times on the same instance but the initialisation will only be done once */
78
112
  init() {
79
- return __awaiter(this, void 0, void 0, function* () {
113
+ return __awaiter(this, arguments, void 0, function* (changedKeys = null, pendingComputationIteration) {
80
114
  if (this.contactFormValuesContainer.mustBeInitialised()) {
81
115
  yield this.computeInitialValues();
82
116
  }
83
- yield this.computeDependentValues();
117
+ let changedKeysByInit = [];
118
+ if (pendingComputationIteration) {
119
+ const changes = yield pendingComputationIteration;
120
+ if (changes.length > 0) {
121
+ this.quietlyApplyChangesOnContactFormValueContainer(changes);
122
+ changedKeysByInit = yield this.computeDependentValues([...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []), ...changes.map(([, metadata]) => metadata.label)]);
123
+ }
124
+ else {
125
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
126
+ }
127
+ }
128
+ else {
129
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
130
+ }
131
+ //After all the silent updates, we need a last one that causes a new BridgedFormValuesContainer to be created and broadcasted to the listeners, so that they get the final values with all the dependencies computed
132
+ this.contactFormValuesContainer.changeListeners.forEach((l) => notify(l, this.contactFormValuesContainer, changedKeysByInit, changedKeysByInit.length > 0));
84
133
  return this;
85
134
  });
86
135
  }
@@ -99,12 +148,10 @@ export class BridgedFormValuesContainer {
99
148
  unregisterChangeListener(listener) {
100
149
  this.changeListeners = this.changeListeners.filter((l) => l !== listener);
101
150
  }
102
- getDefaultValue(label) {
103
- return __awaiter(this, void 0, void 0, function* () {
104
- var _a;
105
- const formula = (_a = this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).find(({ metadata }) => metadata.label === label)) === null || _a === void 0 ? void 0 : _a.formula;
106
- return formula ? this.convertRawValue(yield this.compute(formula)) : undefined;
107
- });
151
+ getDefaultValueProvider(label) {
152
+ var _a;
153
+ const formula = (_a = this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).find(({ metadata }) => metadata.label === label)) === null || _a === void 0 ? void 0 : _a.formula;
154
+ return formula ? () => __awaiter(this, void 0, void 0, function* () { return this.convertRawValue(yield this.compute(formula)); }) : undefined;
108
155
  }
109
156
  getValues(revisionsFilter) {
110
157
  return Object.entries(this.contactFormValuesContainer.getValues((id, history) => revisionsFilter(id, history
@@ -198,7 +245,8 @@ export class BridgedFormValuesContainer {
198
245
  try {
199
246
  const currentValue = this.getValues(revisionsFilter);
200
247
  if (!currentValue || !Object.keys(currentValue).length) {
201
- const newValue = this.convertRawValue((yield this.compute(formula)));
248
+ const computedValue = (yield this.compute(formula)).value;
249
+ const newValue = computedValue ? this.convertRawValue(computedValue) : undefined;
202
250
  if (newValue !== undefined) {
203
251
  const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
204
252
  if (newValue && !newValue.content[lng] && newValue.content['*']) {
@@ -225,39 +273,76 @@ export class BridgedFormValuesContainer {
225
273
  });
226
274
  }
227
275
  //This method mutates the BridgedFormValuesContainer but can only be called from the constructor
228
- computeDependentValues() {
276
+ computeDependentValues(changedKeys) {
229
277
  return __awaiter(this, void 0, void 0, function* () {
230
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
231
- yield Promise.all(this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
232
- var _b;
233
- try {
234
- const currentValue = this.getValues(revisionsFilter);
235
- const newValue = this.convertRawValue((yield this.compute(formula)));
236
- if (newValue !== undefined || currentValue != undefined) {
237
- const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
238
- if (newValue && !newValue.content[lng] && newValue.content['*']) {
239
- newValue.content[lng] = newValue.content['*'];
240
- }
241
- if (newValue) {
242
- delete newValue.content['*'];
243
- }
244
- const interceptor = (fvc) => {
245
- const currentContact = this.contactFormValuesContainer.currentContact;
246
- this.contactFormValuesContainer = fvc;
247
- if (this.contact === currentContact) {
248
- this.contact = fvc.currentContact;
278
+ const iterate = (changedKeys, iterationCount) => __awaiter(this, void 0, void 0, function* () {
279
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
280
+ console.log(`Starting iteration ${iterationCount} with changed keys : ${changedKeys ? changedKeys.join(', ') : 'all'}`);
281
+ 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
+ var _b, _c;
283
+ try {
284
+ if (!changedKeys || !this.dependenciesCache[formula] || this.dependenciesCache[formula].some((d) => changedKeys.includes(d))) {
285
+ const currentValue = this.getValues(revisionsFilter);
286
+ try {
287
+ const computationResult = yield this.compute(formula);
288
+ this.dependenciesCache[formula] = [...((_b = this.dependenciesCache[formula]) !== null && _b !== void 0 ? _b : []), ...computationResult.dependencies].filter((d, idx, array) => array.indexOf(d) === idx);
289
+ const newValue = computationResult.value ? this.convertRawValue(computationResult.value) : undefined;
290
+ if (newValue !== undefined || (currentValue != undefined && Object.keys(currentValue).length > 0 && currentValue[Object.keys(currentValue)[0]][0].value)) {
291
+ const lng = (_c = this.language) !== null && _c !== void 0 ? _c : 'en';
292
+ if (newValue && !newValue.content[lng] && newValue.content['*']) {
293
+ newValue.content[lng] = newValue.content['*'];
294
+ }
295
+ if (newValue) {
296
+ delete newValue.content['*'];
297
+ }
298
+ return [Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, lng, newValue];
299
+ }
249
300
  }
250
- };
251
- setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, lng, newValue, Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, interceptor);
301
+ catch (e) {
302
+ console.log(`Error while computing formula : ${formula}`, e);
303
+ }
304
+ }
252
305
  }
253
- }
254
- catch (e) {
255
- console.log(`Error while computing formula : ${formula}`, e);
256
- }
257
- })));
306
+ catch (e) {
307
+ console.log(`Error while computing formula : ${formula}`, e);
308
+ }
309
+ return null;
310
+ }))).then((results) => results.filter((r) => !!r));
311
+ }
312
+ else {
313
+ return [];
314
+ }
315
+ });
316
+ let latestKeys = changedKeys;
317
+ let iterationCount = 0;
318
+ const allChangedKeys = [];
319
+ while (true) {
320
+ if (latestKeys != null && latestKeys.length === 0) {
321
+ this.dependentValuesComputationIteration = undefined;
322
+ break;
323
+ }
324
+ const changes = yield (this.dependentValuesComputationIteration = iterate(latestKeys, iterationCount++));
325
+ latestKeys = this.quietlyApplyChangesOnContactFormValueContainer(changes);
326
+ allChangedKeys.push(...latestKeys);
258
327
  }
328
+ return allChangedKeys;
259
329
  });
260
330
  }
331
+ quietlyApplyChangesOnContactFormValueContainer(changes) {
332
+ const allChangedKeys = [];
333
+ const interceptor = (fvc, changedKeys) => {
334
+ const currentContact = this.contactFormValuesContainer.currentContact;
335
+ this.contactFormValuesContainer = fvc;
336
+ if (this.contact === currentContact) {
337
+ this.contact = fvc.currentContact;
338
+ }
339
+ allChangedKeys.push(...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []));
340
+ };
341
+ changes.forEach(([id, metadata, language, newValue]) => {
342
+ setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, language, newValue !== null && newValue !== void 0 ? newValue : undefined, id, metadata, interceptor);
343
+ });
344
+ return allChangedKeys;
345
+ }
261
346
  setValue(label, language, fv, id, metadata) {
262
347
  setValueOnContactFormValuesContainer(this.contactFormValuesContainer, label, language, fv, id, metadata);
263
348
  }
@@ -276,9 +361,10 @@ export class BridgedFormValuesContainer {
276
361
  getVersionedValuesForKey(key) {
277
362
  return this.getValues((id, history) => { var _a, _b, _c; return (((_b = (_a = history === null || history === void 0 ? void 0 : history[0]) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.label) && key === history[0].value.label ? [(_c = history === null || history === void 0 ? void 0 : history[0]) === null || _c === void 0 ? void 0 : _c.revision] : []); });
278
363
  }
279
- compute(formula, sandbox) {
364
+ compute(formula) {
280
365
  return __awaiter(this, void 0, void 0, function* () {
281
366
  var _a;
367
+ const dependencies = new Set();
282
368
  // noinspection JSUnusedGlobalSymbols
283
369
  const parseContent = (content, toString = false) => {
284
370
  var _a, _b;
@@ -346,10 +432,16 @@ export class BridgedFormValuesContainer {
346
432
  if (!!nativeValue) {
347
433
  return nativeValue;
348
434
  }
349
- return key === 'self' ? proxy : this.interpreterContext[key] ? this.interpreterContext[key]() : Object.values(this.getVersionedValuesForKey(key)).map((v) => { var _a; return (_a = v[0]) === null || _a === void 0 ? void 0 : _a.value; });
435
+ if (key === 'self') {
436
+ return proxy;
437
+ }
438
+ else {
439
+ dependencies.add(key.toString());
440
+ return this.interpreterContext[key] ? this.interpreterContext[key]() : Object.values(this.getVersionedValuesForKey(key)).map((v) => { var _a; return (_a = v[0]) === null || _a === void 0 ? void 0 : _a.value; });
441
+ }
350
442
  },
351
443
  });
352
- return (_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, sandbox !== null && sandbox !== void 0 ? sandbox : proxy);
444
+ return { value: yield ((_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, proxy)), dependencies: Array.from(dependencies) };
353
445
  });
354
446
  }
355
447
  getChildren() {
@@ -360,28 +452,22 @@ export class BridgedFormValuesContainer {
360
452
  });
361
453
  }
362
454
  getValidationErrors() {
363
- return __awaiter(this, void 0, void 0, function* () {
364
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
365
- // noinspection ES6MissingAwait
366
- return yield this.validatorsProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).reduce((resPromise_1, _a) => __awaiter(this, [resPromise_1, _a], void 0, function* (resPromise, { metadata, validators }) {
367
- return yield validators.reduce((resPromise_2, _a) => __awaiter(this, [resPromise_2, _a], void 0, function* (resPromise, { validation, message }) {
368
- const res = yield resPromise;
369
- try {
370
- if (!(yield this.compute(validation))) {
371
- res.push([metadata, message]);
372
- }
373
- }
374
- catch (e) {
375
- console.log(`Error while computing validation : ${validation}`, e);
376
- }
377
- return res;
378
- }), resPromise);
379
- }), Promise.resolve([]));
380
- }
381
- else {
382
- return [];
383
- }
384
- });
455
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
456
+ return this.validatorsProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).flatMap(({ metadata, validators }) => validators.map((_a) => __awaiter(this, [_a], void 0, function* ({ validation, message }) {
457
+ try {
458
+ if (!(yield this.compute(validation))) {
459
+ return [metadata, message];
460
+ }
461
+ }
462
+ catch (e) {
463
+ console.log(`Error while computing validation : ${validation}`, e);
464
+ }
465
+ return null;
466
+ })));
467
+ }
468
+ else {
469
+ return [];
470
+ }
385
471
  }
386
472
  addChild(anchorId, templateId, label) {
387
473
  return __awaiter(this, void 0, void 0, function* () {
@@ -477,7 +563,7 @@ export class ContactFormValuesContainer {
477
563
  const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.map((c) => {
478
564
  return c.rootForm.id === childFormValueContainer.rootForm.id ? newValue : c;
479
565
  }), this.formFactory, this.formRecycler);
480
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
566
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, [] /* no changed keys except the anchor*/));
481
567
  },
482
568
  ];
483
569
  }
@@ -512,12 +598,10 @@ export class ContactFormValuesContainer {
512
598
  });
513
599
  }
514
600
  getValidationErrors() {
515
- return __awaiter(this, void 0, void 0, function* () {
516
- throw new Error('Validation not supported at contact level');
517
- });
601
+ throw new Error('Validation not supported at contact level');
518
602
  }
519
- getDefaultValue() {
520
- return Promise.resolve(undefined);
603
+ getDefaultValueProvider() {
604
+ return undefined;
521
605
  }
522
606
  getValues(revisionsFilter) {
523
607
  return Object.entries(this.getServicesInHistory(revisionsFilter)).reduce((acc, [id, history]) => history.length
@@ -563,19 +647,19 @@ export class ContactFormValuesContainer {
563
647
  meta.codes && (newService.codes = normalizeCodes(meta.codes));
564
648
  meta.tags && (newService.tags = normalizeCodes(meta.tags));
565
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);
566
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
650
+ this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label] /* only the label is guaranteed to be changed, but it's the only info we have at this point */));
567
651
  }
568
652
  }
569
653
  setValue(label, language, value, id, metadata, changeListenersOverrider) {
570
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
654
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
571
655
  const service = (id && ((_b = (_a = this.getServicesInHistory((sid, history) => (sid === id ? history.map((x) => x.revision) : []))[id]) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value)) || this.serviceFactory(label, id);
572
656
  if (!service.id) {
573
657
  throw new Error('Service id must be defined');
574
658
  }
575
- console.log('Setting value of service', service.id, 'with', value, 'and metadata', metadata);
576
- const newContent = (_c = value === null || value === void 0 ? void 0 : value.content) === null || _c === void 0 ? void 0 : _c[language];
659
+ console.log(`Setting value of service ${service.label} [${service.id}] to ${Object.entries((_c = value === null || value === void 0 ? void 0 : value.content) !== null && _c !== void 0 ? _c : {}).map(([k, c]) => `${k}: ${JSON.stringify(contentToPrimitiveType(k, c))}`)} and md`, metadata);
660
+ const newContent = (_d = value === null || value === void 0 ? void 0 : value.content) === null || _d === void 0 ? void 0 : _d[language];
577
661
  const newCodes = (value === null || value === void 0 ? void 0 : value.codes) ? normalizeCodes(value.codes) : [];
578
- if (!isContentEqual((_d = service.content) === null || _d === void 0 ? void 0 : _d[language], newContent) || (newCodes && !areCodesEqual(newCodes, (_e = service.codes) !== null && _e !== void 0 ? _e : []))) {
662
+ if (!isContentEqual((_e = service.content) === null || _e === void 0 ? void 0 : _e[language], newContent) || (newCodes && !areCodesEqual(newCodes, (_f = service.codes) !== null && _f !== void 0 ? _f : []))) {
579
663
  const newService = new DecryptedService(Object.assign(Object.assign({}, service), { modified: Date.now() }));
580
664
  const newContents = newContent
581
665
  ? Object.assign(Object.assign({}, (service.content || {})), { [language]: newContent }) : Object.assign({}, (service.content || {}));
@@ -584,8 +668,8 @@ export class ContactFormValuesContainer {
584
668
  }
585
669
  let newCurrentContact;
586
670
  if (!Object.entries(newContents).filter(([, cnt]) => cnt !== undefined).length) {
587
- newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_f = this.currentContact.subContacts) !== null && _f !== void 0 ? _f : []).some((sc) => sc.formId === this.rootForm.id)
588
- ? ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).map((sc) => {
671
+ newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).some((sc) => sc.formId === this.rootForm.id)
672
+ ? ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).map((sc) => {
589
673
  var _a;
590
674
  if (sc.formId === this.rootForm.id) {
591
675
  return new DecryptedSubContact(Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([new ServiceLink({ serviceId: service.id })]) }));
@@ -594,24 +678,24 @@ export class ContactFormValuesContainer {
594
678
  return sc;
595
679
  }
596
680
  })
597
- : ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).concat(new DecryptedSubContact({
681
+ : ((_j = this.currentContact.subContacts) !== null && _j !== void 0 ? _j : []).concat(new DecryptedSubContact({
598
682
  formId: this.rootForm.id,
599
683
  services: [new ServiceLink({ serviceId: service.id })],
600
- })), services: ((_j = this.currentContact.services) !== null && _j !== void 0 ? _j : []).some((s) => s.id === service.id)
601
- ? ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).filter((s) => s.id !== service.id)
602
- : [...((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : [])] }));
684
+ })), services: ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).some((s) => s.id === service.id)
685
+ ? ((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : []).filter((s) => s.id !== service.id)
686
+ : [...((_m = this.currentContact.services) !== null && _m !== void 0 ? _m : [])] }));
603
687
  }
604
688
  else {
605
689
  newService.content = newContents;
606
690
  newService.codes = newCodes;
607
691
  if (metadata) {
608
- newService.responsible = (_m = metadata.responsible) !== null && _m !== void 0 ? _m : newService.responsible;
609
- newService.valueDate = (_o = metadata.valueDate) !== null && _o !== void 0 ? _o : newService.valueDate;
692
+ newService.responsible = (_o = metadata.responsible) !== null && _o !== void 0 ? _o : newService.responsible;
693
+ newService.valueDate = (_p = metadata.valueDate) !== null && _p !== void 0 ? _p : newService.valueDate;
610
694
  newService.tags = metadata.tags ? normalizeCodes(metadata.tags) : newService.tags;
611
- newService.label = (_p = metadata.label) !== null && _p !== void 0 ? _p : newService.label;
695
+ newService.label = (_q = metadata.label) !== null && _q !== void 0 ? _q : newService.label;
612
696
  }
613
- newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_q = this.currentContact.subContacts) !== null && _q !== void 0 ? _q : []).some((sc) => sc.formId === this.rootForm.id)
614
- ? ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).map((sc) => {
697
+ newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).some((sc) => sc.formId === this.rootForm.id)
698
+ ? ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).map((sc) => {
615
699
  var _a;
616
700
  if (sc.formId === this.rootForm.id) {
617
701
  return new DecryptedSubContact(Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([new ServiceLink({ serviceId: service.id })]) }));
@@ -620,15 +704,15 @@ export class ContactFormValuesContainer {
620
704
  return sc;
621
705
  }
622
706
  })
623
- : ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).concat(new DecryptedSubContact({
707
+ : ((_t = this.currentContact.subContacts) !== null && _t !== void 0 ? _t : []).concat(new DecryptedSubContact({
624
708
  formId: this.rootForm.id,
625
709
  services: [new ServiceLink({ serviceId: service.id })],
626
- })), services: ((_t = this.currentContact.services) !== null && _t !== void 0 ? _t : []).some((s) => s.id === service.id)
627
- ? ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).map((s) => (s.id === service.id ? newService : s))
628
- : [...((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []), newService] }));
710
+ })), services: ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).some((s) => s.id === service.id)
711
+ ? ((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []).map((s) => (s.id === service.id ? newService : s))
712
+ : [...((_w = this.currentContact.services) !== null && _w !== void 0 ? _w : []), newService] }));
629
713
  }
630
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);
631
- changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
715
+ changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer, [label]) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [label]));
632
716
  }
633
717
  }
634
718
  delete(serviceId) {
@@ -638,8 +722,33 @@ export class ContactFormValuesContainer {
638
722
  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
639
723
  ? new DecryptedService(Object.assign(Object.assign({}, service), { endOfLife: Date.now() }))
640
724
  : s) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
641
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
725
+ this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, []));
726
+ }
727
+ }
728
+ toMarkdownTable() {
729
+ var _a, _b, _c;
730
+ const tableRows = [];
731
+ for (const [, versions] of Object.entries(this.indexedServices)) {
732
+ if (!versions.length)
733
+ continue;
734
+ const service = versions[0].value;
735
+ const label = (_b = (_a = service.label) !== null && _a !== void 0 ? _a : service.id) !== null && _b !== void 0 ? _b : '';
736
+ const modifiedStr = service.modified ? new Date(service.modified).toISOString() : '';
737
+ const contentParts = [];
738
+ for (const [lng, cnt] of Object.entries((_c = service.content) !== null && _c !== void 0 ? _c : {})) {
739
+ const primitive = contentToPrimitiveType(lng, cnt);
740
+ if (primitive) {
741
+ contentParts.push(primitiveTypeToString(primitive));
742
+ }
743
+ }
744
+ tableRows.push([label, modifiedStr, contentParts.join(', ')]);
642
745
  }
746
+ const headers = ['Label', 'Modified', 'Content'];
747
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...tableRows.map((r) => r[i].length)));
748
+ const pad = (s, w) => s + ' '.repeat(w - s.length);
749
+ const formatRow = (cells) => '| ' + cells.map((c, i) => pad(c, colWidths[i])).join(' | ') + ' |';
750
+ const separator = '|' + colWidths.map((w) => '-'.repeat(w + 2)).join('|') + '|';
751
+ return [formatRow(headers), separator, ...tableRows.map(formatRow)].join('\n');
643
752
  }
644
753
  compute() {
645
754
  return __awaiter(this, void 0, void 0, function* () {
@@ -682,7 +791,7 @@ export class ContactFormValuesContainer {
682
791
  const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], false);
683
792
  const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners);
684
793
  newContactFormValuesContainer.registerChildFormValuesContainer(childFVC);
685
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
794
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, []));
686
795
  });
687
796
  }
688
797
  getServiceInCurrentContact(id) {
@@ -693,7 +802,7 @@ export class ContactFormValuesContainer {
693
802
  removeChild(container) {
694
803
  return __awaiter(this, void 0, void 0, function* () {
695
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);
696
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
805
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, []));
697
806
  });
698
807
  }
699
808
  }