@configura/web-api 2.0.0-alpha.20 → 2.0.0-alpha.22

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 (32) hide show
  1. package/.eslintrc.json +1 -14
  2. package/dist/CatalogueAPI.d.ts +41 -0
  3. package/dist/CatalogueAPI.js +1 -0
  4. package/dist/CfgProduct.d.ts +29 -15
  5. package/dist/CfgProduct.js +172 -55
  6. package/dist/ConfigurationConverter.d.ts +4 -0
  7. package/dist/ConfigurationConverter.js +9 -0
  8. package/dist/io/CfgHistoryManager.js +0 -6
  9. package/dist/io/CfgHistoryToProdConfConnector.d.ts +6 -2
  10. package/dist/io/CfgHistoryToProdConfConnector.js +11 -8
  11. package/dist/io/CfgIOProdConfConnector.d.ts +17 -9
  12. package/dist/io/CfgIOProdConfConnector.js +48 -57
  13. package/dist/io/CfgObservableStateToProdConfConnector.d.ts +2 -2
  14. package/dist/io/CfgObservableStateToProdConfConnector.js +3 -3
  15. package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +2 -2
  16. package/dist/io/CfgWindowMessageToProdConfConnector.js +3 -3
  17. package/dist/productConfiguration/CfgFeature.d.ts +5 -1
  18. package/dist/productConfiguration/CfgFeature.js +13 -0
  19. package/dist/productConfiguration/CfgOption.d.ts +6 -1
  20. package/dist/productConfiguration/CfgOption.js +17 -0
  21. package/dist/productLoader.js +1 -1
  22. package/dist/syncGroups/SyncGroupsHandler.d.ts +5 -1
  23. package/dist/syncGroups/SyncGroupsHandler.js +9 -2
  24. package/dist/syncGroups/SyncGroupsState.d.ts +5 -1
  25. package/dist/syncGroups/SyncGroupsState.js +44 -2
  26. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +14 -10
  27. package/dist/tests/testData/testDataCachedGetProduct.js +2 -1
  28. package/dist/tests/testData/testDataCachedPostValidate.js +1 -0
  29. package/dist/tests/testData/testDataProductAggregatedPrice.js +2 -1
  30. package/dist/tests/testData/testDataUpcharge.js +1 -0
  31. package/dist/utilitiesNumericValues.js +13 -8
  32. package/package.json +3 -3
@@ -9,7 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { AggregatedLoadingObservable, assert, assertDefined, augmentErrorMessage, compareArrays, count, Observable, toLengthUnit, } from "@configura/web-utilities";
11
11
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
12
- import { convertDtoProductConfToV1 } from "./ConfigurationConverter.js";
12
+ import { convertDtoProductConfToV1, isAdditionalProductConfiguration, isProductConf, } from "./ConfigurationConverter.js";
13
+ import { CfgProdConfParts } from "./index.js";
13
14
  import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
14
15
  import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfiguration.js";
15
16
  import { collectAdditionalProductRefs } from "./productConfiguration/utilitiesProductConfiguration.js";
@@ -52,7 +53,7 @@ function isDescriptionMatch(l, r) {
52
53
  * the class that should be used and interacted with.
53
54
  */
54
55
  export class _CfgProductInternal {
55
- constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
56
+ constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, notes, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
56
57
  var _a;
57
58
  this._productLoaderRaw = _productLoaderRaw;
58
59
  this.prodParams = prodParams;
@@ -66,6 +67,7 @@ export class _CfgProductInternal {
66
67
  this._syncGroupHandler = _syncGroupHandler;
67
68
  this._destroyed = false;
68
69
  this.additionalProducts = [];
70
+ this._notes = new Map();
69
71
  this.changeObservable = new Observable();
70
72
  /** Mark this and its descendants as destroyed and remove all listeners */
71
73
  this.destroy = () => {
@@ -103,7 +105,7 @@ export class _CfgProductInternal {
103
105
  if (bubbleMode === CfgProductBubbleMode.ToRootAndBubbleSelected &&
104
106
  this.optional &&
105
107
  !this.selected) {
106
- yield this.setSelected(true, bubbleMode);
108
+ yield this.setSelected(true, bubbleMode, false);
107
109
  return;
108
110
  }
109
111
  yield this._notifyAllOfChange(bubbleMode, committed);
@@ -150,18 +152,26 @@ export class _CfgProductInternal {
150
152
  return;
151
153
  }
152
154
  });
153
- this.getDtoConf = (includeExtendedData, includeProductParams) => {
155
+ this.getDtoConf = (include) => {
156
+ var _a;
154
157
  const conf = {};
155
- const features = this.configuration._internal.getDtoConf(includeExtendedData);
158
+ const features = this.configuration._internal.getDtoConf((include & CfgProdConfParts.ExtendedData) === CfgProdConfParts.ExtendedData);
156
159
  if (0 < features.length) {
157
160
  conf.features = features;
158
161
  }
159
- if (includeProductParams) {
162
+ if ((include & CfgProdConfParts.ProdParams) === CfgProdConfParts.ProdParams) {
160
163
  conf.prodParams = this.prodParams;
161
164
  }
165
+ // Only store the syncGroupState for the root product. The same state
166
+ // is used for the entire product, including the additional product,
167
+ // so no need to store it for additional products.
168
+ if ((include & CfgProdConfParts.SyncGroupState) === CfgProdConfParts.SyncGroupState &&
169
+ this.parent === undefined) {
170
+ conf.syncGroupState = (_a = this.syncGroupHandler) === null || _a === void 0 ? void 0 : _a.getCompactSyncGroupState();
171
+ }
162
172
  const additionalProducts = this.additionalProducts;
163
173
  if (0 < additionalProducts.length) {
164
- conf.additionalProducts = additionalProducts.map((p) => p._internal.getDtoConf(includeExtendedData, includeProductParams));
174
+ conf.additionalProducts = additionalProducts.map((p) => p._internal.getDtoConf(include));
165
175
  }
166
176
  if (this.isAdditionalProduct) {
167
177
  const refKey = this.refKey;
@@ -175,15 +185,25 @@ export class _CfgProductInternal {
175
185
  return conf;
176
186
  };
177
187
  this.setDtoConf = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
188
+ // The DtoProdConf format can contain a sync group state, but
189
+ // not the DtoAdditionalProductConfiguration format. So we apply
190
+ // any passed state here.
191
+ if (this.root === this) {
192
+ const syncGroupHandler = this.syncGroupHandler;
193
+ const newSyncGroupState = s.syncGroupState;
194
+ if (syncGroupHandler !== undefined && newSyncGroupState !== undefined) {
195
+ syncGroupHandler.setCompactSyncGroupState(newSyncGroupState);
196
+ }
197
+ }
178
198
  return yield this.setApiSelection(convertDtoProductConfToV1(s), doValidate, productLoaderForGroupedLoad);
179
199
  });
180
200
  this.setApiSelection = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
181
201
  return yield this._setApiSelectionWithOtherProduct(s, doValidate, productLoaderForGroupedLoad, undefined);
182
202
  });
183
203
  this.copyFrom = (source, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
184
- return yield this._setApiSelectionWithOtherProduct(convertDtoProductConfToV1(source.getDtoConf(false, false)), doValidate, productLoaderForGroupedLoad, source);
204
+ return yield this._setApiSelectionWithOtherProduct(convertDtoProductConfToV1(source.getDtoConf(CfgProdConfParts.NoExtra)), doValidate, productLoaderForGroupedLoad, source);
185
205
  });
186
- this._setApiSelectionWithOtherProduct = (s, doValidate, productLoaderForGroupedLoad, sourceProduct) => __awaiter(this, void 0, void 0, function* () {
206
+ this._setApiSelectionWithOtherProduct = (productConfiguration, doValidate, productLoaderForGroupedLoad, sourceProduct) => __awaiter(this, void 0, void 0, function* () {
187
207
  // Wrap with cache will make getProduct for this function call use the same server call
188
208
  // for the same product with the same params. Used for getProduct (when a new additional
189
209
  // product is loaded) and postValidate.
@@ -201,18 +221,32 @@ export class _CfgProductInternal {
201
221
  if (this.configuration._internal.populateFeatures(sourceProduct.configuration.rootFeatureRefs)) {
202
222
  change = true;
203
223
  }
224
+ const targetNotes = this._notes;
225
+ const sourceNotes = sourceProduct._notes;
226
+ for (const targetKey of targetNotes.keys()) {
227
+ if (!sourceNotes.has(targetKey)) {
228
+ targetNotes.delete(targetKey);
229
+ change = true;
230
+ }
231
+ }
232
+ for (const [sourceKey, sourceNote] of sourceNotes) {
233
+ if (!targetNotes.has(sourceKey)) {
234
+ targetNotes.set(sourceKey, sourceNote);
235
+ change = true;
236
+ }
237
+ }
204
238
  }
205
- const configurationChange = yield this.configuration._internal.setApiSelection(s.selOptions, false);
239
+ const configurationChange = yield this.configuration._internal.setApiSelection(productConfiguration.selOptions, false);
206
240
  if (configurationChange) {
207
241
  change = true;
208
242
  }
209
243
  if (this.optional) {
210
- if (yield this.setSelected(s.selected !== false, CfgProductBubbleMode.Stop)) {
244
+ if (yield this.setSelected(productConfiguration.selected !== false, CfgProductBubbleMode.Stop, false)) {
211
245
  change = true;
212
246
  }
213
247
  }
214
- yield this._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
215
- const apiSelectionAdditionalProducts = s.additionalProducts || [];
248
+ yield this._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad, productConfiguration);
249
+ const apiSelectionAdditionalProducts = productConfiguration.additionalProducts || [];
216
250
  const additionalProducts = this.additionalProducts.slice();
217
251
  const additionalProductsCount = additionalProducts.length;
218
252
  const apiSelectionAdditionalProductsCount = apiSelectionAdditionalProducts.length;
@@ -265,7 +299,7 @@ export class _CfgProductInternal {
265
299
  productLoaderForGroupedLoad || wrapWithCache(this._productLoaderRaw);
266
300
  let change = false;
267
301
  if (this.optional && other.optional) {
268
- if (yield this.setSelected(other.selected, CfgProductBubbleMode.Stop)) {
302
+ if (yield this.setSelected(other.selected, CfgProductBubbleMode.Stop, false)) {
269
303
  change = true;
270
304
  }
271
305
  }
@@ -351,7 +385,10 @@ export class _CfgProductInternal {
351
385
  if (this._destroyed) {
352
386
  return false;
353
387
  }
354
- const { productData, rootFeatureRefs, features } = response;
388
+ const { productData, rootFeatureRefs, features, notes } = response;
389
+ if (notes !== undefined) {
390
+ this.addNotes(notes.values());
391
+ }
355
392
  const pricesUpdated = !comparePricesObjects(this.prices, productData.partsData.prices);
356
393
  this._rawProductData = productData;
357
394
  configuration._internal.addRawFeatures(features, true);
@@ -363,7 +400,7 @@ export class _CfgProductInternal {
363
400
  this._configuration = CfgProductConfiguration._makeNewRefFrom(this._configuration._internal);
364
401
  }
365
402
  yield configuration._internal.setApiSelection(productData.partsData.selOptions || [], false);
366
- yield this._syncAndLoadAdditionalProducts(productLoader);
403
+ yield this._syncAndLoadAdditionalProducts(productLoader, undefined);
367
404
  if (this._destroyed) {
368
405
  return false;
369
406
  }
@@ -381,7 +418,7 @@ export class _CfgProductInternal {
381
418
  * Based on this configuration find what additional products should be shown and not, unload
382
419
  * (i.e. destroy) those that should no longer be shown, load the new ones.
383
420
  */
384
- this._syncAndLoadAdditionalProducts = (productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
421
+ this._syncAndLoadAdditionalProducts = (productLoaderForGroupedLoad, initialProductConfiguration) => __awaiter(this, void 0, void 0, function* () {
385
422
  const { _productLoaderRaw: productLoaderRaw, rawProductData: productData, configuration, additionalProducts: currentAdditionalProducts, } = this;
386
423
  const additionalProductRefs = [
387
424
  ...(productData.additionalProductRefs || []),
@@ -423,10 +460,17 @@ export class _CfgProductInternal {
423
460
  change = true;
424
461
  }
425
462
  const newAdditionalProducts = yield Promise.all(additionalProductRefs.map((p) => (() => __awaiter(this, void 0, void 0, function* () {
463
+ var _c;
426
464
  const additionalProductRef = p.prodRef;
465
+ const refKey = additionalProductRef.refKey;
466
+ const additionalProductInitialProductConfiguration = (_c = initialProductConfiguration === null || initialProductConfiguration === void 0 ? void 0 : initialProductConfiguration.additionalProducts) === null || _c === void 0 ? void 0 : _c.find((aP) => refKey === aP.refKey);
467
+ if (initialProductConfiguration !== undefined &&
468
+ additionalProductInitialProductConfiguration === undefined) {
469
+ console.warn(`Did not find initial product configuration for additional product with refKey ${refKey}`);
470
+ }
427
471
  return {
428
472
  originalIndex: p.originalIndex,
429
- product: CfgProduct._makeNewRefFrom(yield _CfgProductInternal.make(productLoaderRaw, productLoaderForGroupedLoad, Object.assign(Object.assign({}, additionalProductRef.catId), { cid: this.prodParams.cid, lang: this.prodParams.lang, partNumber: additionalProductRef.partNumber }), this.settings, additionalProductRef.optional === true, this.loadingObservable, this, this.root, additionalProductRef)),
473
+ product: CfgProduct._makeNewRefFrom(yield _CfgProductInternal.make(productLoaderRaw, productLoaderForGroupedLoad, Object.assign(Object.assign({}, additionalProductRef.catId), { cid: this.prodParams.cid, lang: this.prodParams.lang, partNumber: additionalProductRef.partNumber }), this.settings, additionalProductRef.optional === true, this.loadingObservable, this, this.root, additionalProductRef, additionalProductInitialProductConfiguration)),
430
474
  };
431
475
  }))()));
432
476
  if (this._destroyed) {
@@ -445,6 +489,9 @@ export class _CfgProductInternal {
445
489
  this.key = makeProductKey(Object.assign(Object.assign({}, prodParams), { partNumber: (_a = _additionalProductRef === null || _additionalProductRef === void 0 ? void 0 : _additionalProductRef.refKey) !== null && _a !== void 0 ? _a : prodParams.partNumber }));
446
490
  this._selected = optional ? selected : undefined;
447
491
  this.isAdditionalProduct = _additionalProductRef !== undefined;
492
+ if (notes !== undefined) {
493
+ this.addNotes(notes);
494
+ }
448
495
  this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, rawFeatures, apiSelection, this, this.root);
449
496
  }
450
497
  get selected() {
@@ -462,7 +509,7 @@ export class _CfgProductInternal {
462
509
  var _a;
463
510
  const p = new _CfgProductInternal(() => {
464
511
  initSuccess(p);
465
- }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.rawFeatures, this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
512
+ }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.rawFeatures, this._notes.values(), this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
466
513
  });
467
514
  for (const additionalProduct of this.additionalProducts) {
468
515
  product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
@@ -481,6 +528,41 @@ export class _CfgProductInternal {
481
528
  this._selected = p.optional ? false : undefined;
482
529
  }
483
530
  }
531
+ /**
532
+ * Return a DtoNode using noteRef as a key.
533
+ * Throws an error if no note is found.
534
+ */
535
+ getNote(noteRef) {
536
+ const note = this._notes.get(noteRef);
537
+ if (note === undefined) {
538
+ throw new Error(`Note with noteRef ${noteRef} not found.`);
539
+ }
540
+ return note;
541
+ }
542
+ /**
543
+ * noteRefs is a list of keys coming from CfgOption, CfgFeature or CfgProduct.
544
+ * The keys are used to get a DtoNote[] from notes at CfgProduct.
545
+ */
546
+ getNotes(noteRefs) {
547
+ return noteRefs.map((noteRef) => this.getNote(noteRef));
548
+ }
549
+ addNotes(notes) {
550
+ for (const note of notes) {
551
+ const code = note.code;
552
+ if (!code) {
553
+ throw new Error("Note with no code");
554
+ }
555
+ this._notes.set(code, note);
556
+ }
557
+ }
558
+ get notes() {
559
+ var _a;
560
+ return this.getNotes((_a = this.rawProductData.noteRefs) !== null && _a !== void 0 ? _a : []);
561
+ }
562
+ get miscFiles() {
563
+ var _a;
564
+ return (_a = this._rawProductData.miscFiles) !== null && _a !== void 0 ? _a : [];
565
+ }
484
566
  get hasRootFeaturesChanged() {
485
567
  return (this._configuration._internal.hasRootFeaturesChanged ||
486
568
  this.additionalProducts.some((p) => p._internal.hasRootFeaturesChanged));
@@ -559,26 +641,29 @@ export class _CfgProductInternal {
559
641
  get optional() {
560
642
  return this._selected !== undefined;
561
643
  }
562
- setSelected(v, bubbleMode) {
644
+ setSelected(selected, bubbleMode, interactive) {
563
645
  return __awaiter(this, void 0, void 0, function* () {
564
646
  if (!this.optional) {
565
647
  console.warn("This product is not optional. Nothing will happen");
566
648
  return false;
567
649
  }
568
- if (this._selected === v) {
650
+ if (this._selected === selected) {
569
651
  return false;
570
652
  }
571
- // Vitally important that this happens before the call to reset. An optional
572
- // additional product is always deselected at start, so this way the reset won't cause
573
- // infinite loops
574
- this._selected = v;
575
- if (!v) {
576
- yield this.reset();
577
- }
578
- if (v) {
579
- const syncGroupHandler = this.syncGroupHandler;
580
- if (syncGroupHandler !== undefined) {
581
- yield syncGroupHandler.init(this.root, wrapWithCache(this._productLoaderRaw));
653
+ // Vitally important that this happens before the call to reset,
654
+ // so that the reset won't cause infinite loops
655
+ this._selected = selected;
656
+ if (interactive) {
657
+ if (selected) {
658
+ const syncGroupHandler = this.syncGroupHandler;
659
+ if (syncGroupHandler !== undefined) {
660
+ yield syncGroupHandler.init(this.root, wrapWithCache(this._productLoaderRaw));
661
+ }
662
+ }
663
+ else {
664
+ yield this.reset();
665
+ // In case a passed initial configuration has made it reset to selected
666
+ this._selected = selected;
582
667
  }
583
668
  }
584
669
  yield this._notifyAllOfChange(bubbleMode, true);
@@ -633,18 +718,43 @@ export class _CfgProductInternal {
633
718
  }
634
719
  }
635
720
  _CfgProductInternal.make = (productLoaderRaw, productLoaderForGroupedLoad, // Used when instantiating the current product
636
- prodParams, settings, optional, loadingObservable, parent, root, additionalProductRef) => __awaiter(void 0, void 0, void 0, function* () {
721
+ prodParams, settings, optional, loadingObservable, parent, root, additionalProductRef, initialProductConfiguration) => __awaiter(void 0, void 0, void 0, function* () {
637
722
  // Wrap with cache will make getProduct for this function call use the same server call
638
723
  // for the same product with the same params. Not retained for future calls, only used
639
724
  // at this initial load.
640
725
  productLoaderForGroupedLoad =
641
726
  productLoaderForGroupedLoad || wrapWithCache(productLoaderRaw);
642
- const syncGroupHandler = root === undefined
643
- ? SyncGroupsHandler.make(settings.syncGroupsApplyMode, loadingObservable)
644
- : undefined;
727
+ let syncGroupHandler = undefined;
728
+ // No root means we are root. We only create SyncGroupsHandler if this is the root product
729
+ if (root === undefined) {
730
+ let initialSyncGroupsState = undefined;
731
+ // DtoProductConf supports containing the sync group state, but the old
732
+ // DtoAdditionalProductConfiguration does not
733
+ if (initialProductConfiguration !== undefined &&
734
+ isProductConf(initialProductConfiguration)) {
735
+ initialSyncGroupsState = initialProductConfiguration.syncGroupState;
736
+ }
737
+ syncGroupHandler = SyncGroupsHandler.make(settings.syncGroupsApplyMode, loadingObservable, initialSyncGroupsState);
738
+ }
645
739
  try {
646
- const productResponse = yield productLoaderForGroupedLoad.getProduct(correctDefaultsOnCatalogueParams(prodParams));
647
- const { productData, rootFeatureRefs, features: rawFeatures, uuid, unit, } = productResponse;
740
+ const defaultCorrectedProdParams = correctDefaultsOnCatalogueParams(prodParams);
741
+ let initialProductConfigurationV1 = undefined;
742
+ if (initialProductConfiguration !== undefined) {
743
+ if (isProductConf(initialProductConfiguration)) {
744
+ initialProductConfigurationV1 = convertDtoProductConfToV1(initialProductConfiguration);
745
+ }
746
+ else if (isAdditionalProductConfiguration(initialProductConfiguration)) {
747
+ initialProductConfigurationV1 = initialProductConfiguration;
748
+ }
749
+ }
750
+ const productResponse = yield (initialProductConfigurationV1
751
+ ? productLoaderForGroupedLoad.postValidate(defaultCorrectedProdParams, {
752
+ knownFeatureCodes: [],
753
+ selOptions: initialProductConfigurationV1.selOptions,
754
+ })
755
+ : productLoaderForGroupedLoad.getProduct(defaultCorrectedProdParams));
756
+ const { productData, rootFeatureRefs, features: rawFeatures, notes, uuid, unit, } = productResponse;
757
+ const initiallySelected = !optional || (initialProductConfigurationV1 === null || initialProductConfigurationV1 === void 0 ? void 0 : initialProductConfigurationV1.selected) === true;
648
758
  const product = yield new Promise((initSuccess, initFail) => {
649
759
  var _a;
650
760
  const p = new _CfgProductInternal(() => {
@@ -652,12 +762,16 @@ prodParams, settings, optional, loadingObservable, parent, root, additionalProdu
652
762
  // But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
653
763
  // Feel free to find a nicer more readable solution :)
654
764
  initSuccess(p);
655
- }, initFail, productLoaderRaw, prodParams, settings, optional, !optional, rootFeatureRefs, rawFeatures, uuid, unit, productData, (_a = productData.partsData.selOptions) !== null && _a !== void 0 ? _a : [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
765
+ }, initFail, productLoaderRaw, prodParams, settings, optional, initiallySelected, rootFeatureRefs !== null && rootFeatureRefs !== void 0 ? rootFeatureRefs : [], rawFeatures, notes === null || notes === void 0 ? void 0 : notes.values(), uuid, unit, productData, (_a = productData.partsData.selOptions) !== null && _a !== void 0 ? _a : [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
656
766
  });
657
- yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
767
+ yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad, initialProductConfigurationV1);
658
768
  product._initialClone = yield product.clone();
659
- if (syncGroupHandler !== undefined) {
660
- // As syncGroupHandler is only set for root product we know that we will init with root
769
+ if (syncGroupHandler !== undefined && !initialProductConfiguration) {
770
+ // As syncGroupHandler is only set for root product we know that we will init with root.
771
+ // If we have an initialProductConfiguration we do not run init for the syncGroups.
772
+ // The idea with an initial configuration is that the product should look as it did when
773
+ // the configuration was saved. Not running init does that. Also, the DtoProductConf
774
+ // object can contain a sync state which is then used to populate the sync state.
661
775
  yield syncGroupHandler.init(product, productLoaderForGroupedLoad);
662
776
  }
663
777
  return product;
@@ -682,7 +796,7 @@ export class CfgProduct {
682
796
  * Setting this does not cause a validation call as toggling an optional additional product is
683
797
  * assumed to always be legal.
684
798
  */
685
- this.setSelected = (v) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setSelected(v, CfgProductBubbleMode.ToRootAndBubbleSelected); });
799
+ this.setSelected = (v) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setSelected(v, CfgProductBubbleMode.ToRootAndBubbleSelected, true); });
686
800
  /**
687
801
  * Experimental. Additional products lacks descriptions or keys that are suitably for structure
688
802
  * compare, so we use strict-order when trying to match the additional products. This makes
@@ -705,7 +819,7 @@ export class CfgProduct {
705
819
  * @deprecated getDtoConf provides a newer format.
706
820
  * @see getDtoConf
707
821
  */
708
- this.getApiSelection = () => convertDtoProductConfToV1(this._internal.getDtoConf(false, false), true);
822
+ this.getApiSelection = () => convertDtoProductConfToV1(this._internal.getDtoConf(CfgProdConfParts.NoExtra), true);
709
823
  /**
710
824
  * Applies the configuration (selections) in the passed object onto the product recursively
711
825
  * including product configuration, optional products and additional products.
@@ -723,16 +837,13 @@ export class CfgProduct {
723
837
  * - Makes less assumptions about the structure in the Product being unchanging over time. In
724
838
  * particular, the Feature codes are included in the data, so that changes to what Features
725
839
  * are used in a Product is less likely to lead to unexpected results.
726
- * - You can request ExtendedData and/or ProductParams to be included in the result. This extra
727
- * data is ignored when passed back into the API, but it can be very useful for external
728
- * applications.
840
+ * - You can request ExtendedData, ProductParams and/or SyncGroupState to be included in the
841
+ * result. This extra data is ignored when passed back into the API, but it can be very useful
842
+ * for external applications.
729
843
  * The other version (getApiSelection) has the advantage of using a format directly compatible with the API:s.
730
- * @param includeExtendedData Includes extra data which is not an actual part of the configuration,
731
- * i.e. units and groupCodes
732
- * @param includeProductParams Includes what Product this was generated for, and the same for any
733
- * Additional Products.
844
+ * @param include Includes extra data which is not an actual part of the configuration
734
845
  */
735
- this.getDtoConf = (includeExtendedData = false, includeProductParams = false) => this._internal.getDtoConf(includeExtendedData, includeProductParams);
846
+ this.getDtoConf = (include = CfgProdConfParts.NoExtra) => this._internal.getDtoConf(include);
736
847
  /**
737
848
  * A newer alternative version of setApiSelection.
738
849
  * @param doValidate Makes a server side validation call. These are necessary to ensure that
@@ -746,9 +857,9 @@ export class CfgProduct {
746
857
  this.stopListenForLoading = (l) => this._internal.loadingObservable.stopListen(l);
747
858
  this.stopAllListenForLoading = () => this._internal.loadingObservable.stopAllListen();
748
859
  }
749
- static make(productLoader, prodParams, settings) {
860
+ static make(productLoader, prodParams, settings, initialProductConfiguration) {
750
861
  return __awaiter(this, void 0, void 0, function* () {
751
- return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, prodParams, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined));
862
+ return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, prodParams, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined, initialProductConfiguration));
752
863
  });
753
864
  }
754
865
  /**
@@ -774,6 +885,12 @@ export class CfgProduct {
774
885
  get refKey() {
775
886
  return this._internal.refKey;
776
887
  }
888
+ get notes() {
889
+ return this._internal.notes;
890
+ }
891
+ get miscFiles() {
892
+ return this._internal.miscFiles;
893
+ }
777
894
  get prodParams() {
778
895
  return this._internal.prodParams;
779
896
  }
@@ -811,7 +928,7 @@ export class CfgProduct {
811
928
  /**
812
929
  * Please note that this relates to the visibility in the Configuration tree.
813
930
  * It does not affect the visibility of anything in the 3D view at all.
814
- * Visibility is affects the Configuration for this Product, but any Additional Products
931
+ * Visibility affects the Configuration for this Product, but any Additional Products
815
932
  * will not be affected.
816
933
  */
817
934
  get visible() {
@@ -1,4 +1,8 @@
1
1
  import { DtoAdditionalProductConf, DtoAdditionalProductConfiguration, DtoFeatureConf, DtoProductConf, DtoSelectedOption } from "./CatalogueAPI.js";
2
+ /** Is the newer version of product configuration */
3
+ export declare const isProductConf: (value: DtoAdditionalProductConfiguration | DtoProductConf) => value is DtoAdditionalProductConf;
4
+ /** Is the older version of product configuration */
5
+ export declare const isAdditionalProductConfiguration: (value: DtoAdditionalProductConfiguration | DtoProductConf) => value is DtoAdditionalProductConfiguration;
2
6
  export declare const isDtoProductConfAdditional: (value: DtoProductConf) => value is DtoAdditionalProductConf;
3
7
  export declare const convertDtoProductConfToV1: (conf: DtoProductConf, silenceWarnings?: boolean) => DtoAdditionalProductConfiguration;
4
8
  export declare const convertDtoFeatureConfsToSelOptions: (features: DtoFeatureConf[], silenceWarnings?: boolean) => DtoSelectedOption[];
@@ -1,3 +1,7 @@
1
+ /** Is the newer version of product configuration */
2
+ export const isProductConf = (value) => !("selOptions" in value);
3
+ /** Is the older version of product configuration */
4
+ export const isAdditionalProductConfiguration = (value) => "selOptions" in value;
1
5
  export const isDtoProductConfAdditional = (value) => "refKey" in value;
2
6
  // As this has potential to flood the terminal we only inform once
3
7
  let hasInformedAboutProdParams = false;
@@ -90,6 +94,11 @@ for (const [long, short] of [
90
94
  ["numericValue", "n"],
91
95
  ["groupCode", "g"],
92
96
  ["unit", "u"],
97
+ ["syncGroupState", "sgs"],
98
+ ["selectOne", "so"],
99
+ ["selectMany", "sm"],
100
+ ["syncCode", "sc"],
101
+ ["optionCode", "oc"],
93
102
  ]) {
94
103
  shortToLong.set(short, long);
95
104
  longToShort.set(long, short);
@@ -59,12 +59,6 @@ export class CfgHistoryManager extends CfgWindowEventManager {
59
59
  */
60
60
  send(messageKey, data) {
61
61
  const { qsKeyValues, message, mode } = data;
62
- const warnings = this.getWarnings();
63
- if (warnings.length !== 0) {
64
- console.warn("History updating blocked by warnings");
65
- warnings.forEach((w) => console.warn(w));
66
- return;
67
- }
68
62
  for (const keyValue of qsKeyValues) {
69
63
  this._aggregatedQsKeyValues.set(keyValue[0], keyValue[1]);
70
64
  }
@@ -7,12 +7,16 @@ import { CfgIOProdConfConnector, CfgProdConfMessage } from "./CfgIOProdConfConne
7
7
  export declare class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector<CfgHistoryManagerSendData<CfgProdConfMessage>> {
8
8
  private readonly _mode;
9
9
  private readonly _qsKey;
10
+ private static getInitialProdConf;
11
+ static make(manager: CfgHistoryManager, mode: HistoryMode, qsKey?: string): {
12
+ instance: CfgHistoryToProdConfConnector;
13
+ initial: DtoProductConf | undefined;
14
+ };
10
15
  /**
11
16
  * @param _mode
12
17
  * @param _qsKey The Query String key for product configuration.
13
18
  */
14
- constructor(manager: CfgHistoryManager, _mode: HistoryMode, _qsKey?: string);
15
- protected getInitialProdConf(): DtoProductConf | undefined;
19
+ private constructor();
16
20
  protected makeSendData(conf: DtoProductConf, initial: boolean): CfgHistoryManagerSendData<CfgProdConfMessage>;
17
21
  }
18
22
  //# sourceMappingURL=CfgHistoryToProdConfConnector.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { augmentErrorMessage } from "@configura/web-utilities";
2
2
  import { compactStringToDtoProductConf, dtoProductConfigurationToCompactString, } from "../ConfigurationConverter.js";
3
3
  import { CfgHistoryManager } from "./CfgHistoryManager.js";
4
- import { CfgIOProdConfConnector, CfgProdConfMessageVersions, getHighestVersionProdConfMessage, isCfgProdConfMessageV2, STAGE_PROD_CONF_MESSAGE_KEY, } from "./CfgIOProdConfConnector.js";
4
+ import { CfgIOProdConfConnector, CfgProdConfMessageVersions, CfgProdConfParts, getHighestVersionProdConfMessage, isCfgProdConfMessageV2, STAGE_PROD_CONF_MESSAGE_KEY, } from "./CfgIOProdConfConnector.js";
5
5
  /**
6
6
  * Instantiating this will make the browser history (and URL) update with the product configuration.
7
7
  */
@@ -10,12 +10,12 @@ export class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector {
10
10
  * @param _mode
11
11
  * @param _qsKey The Query String key for product configuration.
12
12
  */
13
- constructor(manager, _mode, _qsKey = STAGE_PROD_CONF_MESSAGE_KEY) {
14
- super(manager, false, false);
13
+ constructor(manager, _mode, _qsKey) {
14
+ super(manager, CfgProdConfParts.SyncGroupState);
15
15
  this._mode = _mode;
16
16
  this._qsKey = _qsKey;
17
17
  }
18
- getInitialProdConf() {
18
+ static getInitialProdConf(qsKey) {
19
19
  // First try to use the state, if that doesn't work use the query string
20
20
  const initialMessage = CfgHistoryManager.getMessageFromCurrentHistoryState(STAGE_PROD_CONF_MESSAGE_KEY);
21
21
  if (initialMessage !== undefined) {
@@ -25,7 +25,7 @@ export class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector {
25
25
  }
26
26
  }
27
27
  try {
28
- const s = CfgHistoryManager.currentQsKeyValues().get(this._qsKey);
28
+ const s = CfgHistoryManager.currentQsKeyValues().get(qsKey);
29
29
  if (s === undefined) {
30
30
  return undefined;
31
31
  }
@@ -35,12 +35,15 @@ export class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector {
35
35
  throw augmentErrorMessage(err, "Failed read configuration from query string");
36
36
  }
37
37
  }
38
+ static make(manager, mode, qsKey = STAGE_PROD_CONF_MESSAGE_KEY) {
39
+ const initial = this.getInitialProdConf(qsKey);
40
+ const instance = new CfgHistoryToProdConfConnector(manager, mode, qsKey);
41
+ return { instance, initial };
42
+ }
38
43
  makeSendData(conf, initial) {
39
44
  return {
40
45
  message: CfgIOProdConfConnector.makeMessage(conf, initial, CfgProdConfMessageVersions.V2dot0),
41
- qsKeyValues: new Map([
42
- [STAGE_PROD_CONF_MESSAGE_KEY, dtoProductConfigurationToCompactString(conf)],
43
- ]),
46
+ qsKeyValues: new Map([[this._qsKey, dtoProductConfigurationToCompactString(conf)]]),
44
47
  mode: this._mode,
45
48
  };
46
49
  }
@@ -22,6 +22,17 @@ export declare enum CfgProdConfMessageVersions {
22
22
  V1dot0 = 1,
23
23
  V2dot0 = 2
24
24
  }
25
+ /**
26
+ * @param ExtendedData Includes extra data, i.e. units and groupCodes
27
+ * @param ProductParams Includes what Product this was generated for, and the same for any Additional Products.
28
+ * @param SyncGroupState Includes the current sync group state
29
+ */
30
+ export declare enum CfgProdConfParts {
31
+ NoExtra = 0,
32
+ ExtendedData = 1,
33
+ ProdParams = 2,
34
+ SyncGroupState = 4
35
+ }
25
36
  export declare const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
26
37
  declare type ProdConfMessageCallback = (message: CfgProdConfMessage) => Promise<void>;
27
38
  declare type ProdConfCallback = (conf: DtoProductConf) => Promise<void>;
@@ -30,28 +41,25 @@ declare type ProdConfCallback = (conf: DtoProductConf) => Promise<void>;
30
41
  */
31
42
  export declare abstract class CfgIOProdConfConnector<S> implements CfgIOWarningSupplier {
32
43
  protected readonly _ioManager: CfgIOManager<S>;
33
- private readonly _includeExtendedDataInSend;
34
- private readonly _includeProdParamsInSend;
44
+ private readonly _includeInSend;
35
45
  protected _product: CfgProduct | undefined;
36
46
  private _stopListenToMessage;
37
47
  private _stopListenToProdConf;
38
- constructor(_ioManager: CfgIOManager<S>, _includeExtendedDataInSend: boolean, // Only for v2.0
39
- _includeProdParamsInSend: boolean);
48
+ constructor(_ioManager: CfgIOManager<S>, _includeInSend: CfgProdConfParts);
40
49
  destroy(): void;
41
50
  getWarnings(): string[];
42
51
  setProduct: (product: CfgProduct | undefined) => Promise<void>;
43
52
  private _send;
44
- protected getInitialProdConf(): DtoProductConf | undefined;
45
53
  protected abstract makeSendData(conf: DtoProductConf, initial: boolean): S;
46
- static makeMessage(conf: DtoProductConf, initial: boolean, sendVersions: CfgProdConfMessageVersions): CfgProdConfMessage;
47
- static makeMessageListener(callback: ProdConfMessageCallback): (message: unknown) => Promise<void>;
54
+ static makeMessage: (conf: DtoProductConf, initial: boolean, sendVersions: CfgProdConfMessageVersions) => CfgProdConfMessage;
55
+ static makeMessageListener: (callback: ProdConfMessageCallback) => (message: unknown) => Promise<void>;
48
56
  /**
49
57
  * Register the callback to listen for Product Configuration messages
50
58
  * @returns A function which when called will cancel listening
51
59
  */
52
60
  static listenForMessage<S>(callback: ProdConfMessageCallback, ioManager: CfgIOManager<S>): () => void;
53
- static makeProdConfListener(callback: ProdConfCallback, includeExtendedDataInSend: boolean, includeProdParamsInSend: boolean): (n: CfgProductChangeNotification) => void;
54
- static listenForProdConf(product: CfgProduct, callback: ProdConfCallback, includeExtendedDataInSend: boolean, includeProdParamsInSend: boolean): () => void;
61
+ static makeProdConfListener: (callback: ProdConfCallback, includeInSend: CfgProdConfParts) => (n: CfgProductChangeNotification) => void;
62
+ static listenForProdConf(product: CfgProduct, callback: ProdConfCallback, includeInSend: CfgProdConfParts): () => void;
55
63
  }
56
64
  export {};
57
65
  //# sourceMappingURL=CfgIOProdConfConnector.d.ts.map