@configura/web-api 1.6.1-alpha.0 → 1.6.1-alpha.4

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.
@@ -1,9 +1,9 @@
1
1
  import { AggregatedLoadingObservable, LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { AdditionalProductConfiguration, CatalogueParams, MeasureParam, MtrlApplication, Prices, Transform } from "./CatalogueAPI.js";
2
+ import { AdditionalProductConfiguration, AdditionalProductRef, CatalogueParams, MeasureParam, MtrlApplication, Prices, Transform } from "./CatalogueAPI.js";
3
3
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
4
4
  import { _CfgFeatureInternal } from "./productConfiguration/CfgFeature.js";
5
- import { ProductConfigurationBubbleMode, _CfgOptionInternal } from "./productConfiguration/CfgOption.js";
6
- import { CfgProductConfiguration, _CfgProductConfigurationInternal } from "./productConfiguration/CfgProductConfiguration.js";
5
+ import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
6
+ import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfiguration.js";
7
7
  import { ProductLoader } from "./productLoader.js";
8
8
  import { SyncGroupsApplyMode } from "./syncGroups/SyncGroupsApplyMode.js";
9
9
  import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
@@ -20,16 +20,17 @@ export declare type CfgProductSettings = {
20
20
  */
21
21
  strictSelectOneSelectionCount: boolean;
22
22
  /**
23
- * Activating this will make setAPI throw an error if the number of actually selected options
24
- * on Features (excluding Group) are not exactly equal to the number of options passed in.
25
- * Note: This check is not always reliable for Options with multiple Features each, which we
26
- * believe is a rare use case.
27
- */
28
- strictSetApiSelectionMatch: boolean;
29
- /**
30
- * Controls if SyncGroups are applied Fast or Strict. Fast keeps the number of validate calls
31
- * to the server down, Strict is closer to how CET works. We recommend you use Fast as cases
32
- * where the results differ should be rare in real use cases.
23
+ * Controls if SyncGroups are applied Faster or Stricter.
24
+ *
25
+ * Fast - Tries to minimize the number of validates calls to the AI lowering the response times
26
+ * for selecting options. Might not always give the expected result for complex products.
27
+ *
28
+ * Strict - Apply the SyncGroups rules in a stricter fashion to be as close to CET as possible,
29
+ * which might result in longer response times and more validation calls to the API when
30
+ * selecting options.
31
+ *
32
+ * The SDK will default to Strict, but we recommend that you try out Fast since cases where the
33
+ * results differ should be rare in most real uses cases and the speedup can be quite large.
33
34
  */
34
35
  syncGroupsApplyMode: SyncGroupsApplyMode | undefined;
35
36
  };
@@ -56,8 +57,6 @@ export declare type CfgPrice = {
56
57
  currency: string;
57
58
  fractionDigits: number;
58
59
  };
59
- export declare type CfgPathSegment = string;
60
- export declare type CfgPath = CfgPathSegment[];
61
60
  export declare type RevalidateResult = {
62
61
  wasAborted: boolean;
63
62
  requestDidValidate: boolean;
@@ -77,13 +76,10 @@ export declare class _CfgProductInternal {
77
76
  private readonly _rawUnit;
78
77
  private _rawProductData;
79
78
  readonly loadingObservable: AggregatedLoadingObservable;
80
- readonly refKey: string | undefined;
81
- readonly refDescription: string | undefined;
82
79
  readonly parent: _CfgProductInternal | undefined;
83
- readonly transform: Transform | undefined;
84
- anchor: MeasureParam | undefined;
80
+ private _additionalProductRef;
85
81
  private readonly _syncGroupHandler;
86
- static make: (productLoaderRaw: ProductLoader, productLoaderForGroupedLoad: ProductLoader | undefined, lang: string, catId: CatalogueParams, partNumber: string, settings: CfgProductSettings, optional: boolean, loadingObservable: AggregatedLoadingObservable, refKey: string | undefined, refDescription: string | undefined, parent: _CfgProductInternal | undefined, root: _CfgProductInternal | undefined, transform: Transform | undefined, anchor: MeasureParam | undefined) => Promise<_CfgProductInternal>;
82
+ static make: (productLoaderRaw: ProductLoader, productLoaderForGroupedLoad: ProductLoader | undefined, lang: string, catId: CatalogueParams, partNumber: string, settings: CfgProductSettings, optional: boolean, loadingObservable: AggregatedLoadingObservable, parent: _CfgProductInternal | undefined, root: _CfgProductInternal | undefined, additionalProductRef: AdditionalProductRef | undefined) => Promise<_CfgProductInternal>;
87
83
  private constructor();
88
84
  readonly root: _CfgProductInternal;
89
85
  private _destroyed;
@@ -96,6 +92,7 @@ export declare class _CfgProductInternal {
96
92
  readonly isAdditionalProduct: boolean;
97
93
  clone(parent?: _CfgProductInternal, root?: _CfgProductInternal): Promise<_CfgProductInternal>;
98
94
  destroy: () => void;
95
+ _updateAdditionalProdRef(p: AdditionalProductRef): void;
99
96
  get description(): string | undefined;
100
97
  get rootNodeSources(): RootNodeSource[] | undefined;
101
98
  get mtrlApplications(): MtrlApplication[] | undefined;
@@ -105,6 +102,9 @@ export declare class _CfgProductInternal {
105
102
  private _measureDefinitions;
106
103
  get measureDefinitions(): CfgMeasureDefinition[];
107
104
  private _unit;
105
+ get refKey(): string | undefined;
106
+ get transform(): Transform | undefined;
107
+ get anchor(): MeasureParam | undefined;
108
108
  /** @throws an error if the actual unit sent by the server was not a LengthUnit */
109
109
  get unit(): LengthUnit;
110
110
  get aggregatedPrice(): CfgPrice;
@@ -136,15 +136,9 @@ export declare class _CfgProductInternal {
136
136
  _configurationHasChanged: (freshRef: CfgProductConfiguration, bubbleMode: ProductConfigurationBubbleMode) => Promise<void>;
137
137
  getApiSelection: () => AdditionalProductConfiguration;
138
138
  setApiSelection: (s: AdditionalProductConfiguration, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
139
- copyFrom: (otherProduct: _CfgProductInternal, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
139
+ copyFrom: (source: _CfgProductInternal, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
140
140
  private _setApiSelectionWithOtherProduct;
141
141
  get syncGroupHandler(): SyncGroupsHandler | undefined;
142
- get path(): CfgPath;
143
- getFromPath(path: CfgPath): _CfgProductInternal | _CfgProductConfigurationInternal | _CfgFeatureInternal | _CfgOptionInternal;
144
- getProductFromPath(path: CfgPath): _CfgProductInternal;
145
- getProductConfigurationFromPath(path: CfgPath): _CfgProductConfigurationInternal;
146
- getFeatureFromPath(path: CfgPath): _CfgFeatureInternal;
147
- getOptionFromPath(path: CfgPath): _CfgOptionInternal;
148
142
  structureCompare: (other: _CfgProductInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
149
143
  tryMatchSelection: (other: _CfgProductInternal, descriptionMatch?: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
150
144
  /** Only features in selected options and selected additional products. */
@@ -7,20 +7,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { AggregatedLoadingObservable, compareArrays, count, Observable, toLengthUnit, } from "@configura/web-utilities";
10
+ import { AggregatedLoadingObservable, assert, assertDefined, compareArrays, count, Observable, toLengthUnit, } from "@configura/web-utilities";
11
11
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
12
- import { _CfgFeatureInternal } from "./productConfiguration/CfgFeature.js";
13
- import { ProductConfigurationBubbleMode, _CfgOptionInternal, } from "./productConfiguration/CfgOption.js";
14
- import { CfgProductConfiguration, _CfgProductConfigurationInternal, } from "./productConfiguration/CfgProductConfiguration.js";
12
+ import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
13
+ import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfiguration.js";
15
14
  import { collectAdditionalProductRefs } from "./productConfiguration/utilitiesProductConfiguration.js";
16
15
  import { wrapWithCache } from "./productLoader.js";
17
16
  import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
18
- import { comparePricesObjects, correctDefaultsOnCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
17
+ import { comparePricesObjects, correctDefaultsOnCatalogueParams, isSameCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
19
18
  function completeSettings(incompleteSettings) {
20
- var _a, _b;
19
+ var _a;
21
20
  return {
22
21
  strictSelectOneSelectionCount: (_a = incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.strictSelectOneSelectionCount) !== null && _a !== void 0 ? _a : false,
23
- strictSetApiSelectionMatch: (_b = incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.strictSetApiSelectionMatch) !== null && _b !== void 0 ? _b : false,
24
22
  syncGroupsApplyMode: incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.syncGroupsApplyMode,
25
23
  };
26
24
  }
@@ -53,7 +51,8 @@ function isDescriptionMatch(l, r) {
53
51
  * the class that should be used and interacted with.
54
52
  */
55
53
  export class _CfgProductInternal {
56
- constructor(initSuccess, initFail, _productLoaderRaw, lang, catId, partNumber, settings, optional, selected, rootFeatureRefs, allRawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, refKey, refDescription, parent, root, transform, anchor, _syncGroupHandler) {
54
+ constructor(initSuccess, initFail, _productLoaderRaw, lang, catId, partNumber, settings, optional, selected, rootFeatureRefs, allRawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
55
+ var _a;
57
56
  this._productLoaderRaw = _productLoaderRaw;
58
57
  this.lang = lang;
59
58
  this.catId = catId;
@@ -63,11 +62,8 @@ export class _CfgProductInternal {
63
62
  this._rawUnit = _rawUnit;
64
63
  this._rawProductData = _rawProductData;
65
64
  this.loadingObservable = loadingObservable;
66
- this.refKey = refKey;
67
- this.refDescription = refDescription;
68
65
  this.parent = parent;
69
- this.transform = transform;
70
- this.anchor = anchor;
66
+ this._additionalProductRef = _additionalProductRef;
71
67
  this._syncGroupHandler = _syncGroupHandler;
72
68
  this._destroyed = false;
73
69
  this.additionalProducts = [];
@@ -154,8 +150,8 @@ export class _CfgProductInternal {
154
150
  this.setApiSelection = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
155
151
  return this._setApiSelectionWithOtherProduct(s, doValidate, productLoaderForGroupedLoad, undefined);
156
152
  });
157
- this.copyFrom = (otherProduct, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
158
- return yield this._setApiSelectionWithOtherProduct(otherProduct.getApiSelection(), doValidate, productLoaderForGroupedLoad, otherProduct);
153
+ this.copyFrom = (source, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
154
+ return yield this._setApiSelectionWithOtherProduct(source.getApiSelection(), doValidate, productLoaderForGroupedLoad, source);
159
155
  });
160
156
  this._setApiSelectionWithOtherProduct = (s, doValidate, productLoaderForGroupedLoad, sourceProduct) => __awaiter(this, void 0, void 0, function* () {
161
157
  // Wrap with cache will make getProduct for this function call use the same server call
@@ -166,6 +162,7 @@ export class _CfgProductInternal {
166
162
  let change = false;
167
163
  if (sourceProduct !== undefined) {
168
164
  this._rawProductData = sourceProduct.rawProductData;
165
+ this.configuration._internal.populateFeatures(sourceProduct.configuration.rootFeatureRefs);
169
166
  change = true; // We can not know if this is an actual change, so we assume it is
170
167
  }
171
168
  const configurationChange = yield this.configuration._internal.setApiSelection(s.selOptions, false);
@@ -186,27 +183,19 @@ export class _CfgProductInternal {
186
183
  throw new Error(`Additional products are not same length. This product: "${this.key}". This product additional products count: ${additionalProductsCount}. Passed apiSelection additional products count: ${apiSelectionAdditionalProductsCount}`);
187
184
  }
188
185
  const sourceProductAdditionalProducts = sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.additionalProducts;
189
- if (sourceProductAdditionalProducts &&
190
- additionalProductsCount !== sourceProductAdditionalProducts.length) {
191
- throw new Error(`Passed sourceProduct does not have the same number of additional products as this.`);
192
- }
186
+ assert(!sourceProductAdditionalProducts ||
187
+ additionalProductsCount === sourceProductAdditionalProducts.length, `Passed sourceProduct does not have the same number of additional products as this.`);
193
188
  if ((yield Promise.all(apiSelectionAdditionalProducts.map((apiSelectionAdditionalProduct, index) => {
194
189
  var _a;
195
190
  const refKey = apiSelectionAdditionalProduct.refKey;
196
- if (refKey === undefined) {
197
- throw new Error("Additional product api configurations must have refKey.");
198
- }
191
+ assertDefined(refKey, "Additional product api configurations must have refKey.");
199
192
  const i = additionalProducts.findIndex((a) => refKey === a.refKey);
200
- if (i === -1) {
201
- throw new Error(`Additional product not found. This product: "${this.key}". refKey of not found additional product: "${refKey}"`);
202
- }
193
+ assert(i !== -1, `Additional product not found. This product: "${this.key}". refKey of not found additional product: "${refKey}"`);
203
194
  let sourceProductAdditionalProduct = undefined;
204
195
  if (sourceProductAdditionalProducts !== undefined) {
205
196
  sourceProductAdditionalProduct =
206
197
  (_a = sourceProductAdditionalProducts.find((a) => refKey === a.refKey)) === null || _a === void 0 ? void 0 : _a._internal;
207
- if (sourceProductAdditionalProduct === undefined) {
208
- throw new Error("Additional product not found in sourceProduct");
209
- }
198
+ assertDefined(sourceProductAdditionalProduct, "Additional product not found in sourceProduct");
210
199
  }
211
200
  const additionalProduct = additionalProducts.splice(i, 1)[0]; // Splicing like this is okay because this is done synchronous. The setCon. is what is async.
212
201
  return additionalProduct._internal._setApiSelectionWithOtherProduct(apiSelectionAdditionalProduct, doValidate, productLoaderForGroupedLoad, sourceProductAdditionalProduct);
@@ -372,14 +361,19 @@ export class _CfgProductInternal {
372
361
  let i = currentAdditionalProducts.length;
373
362
  while (i--) {
374
363
  const currentAdditionalProduct = currentAdditionalProducts[i];
375
- const refKey = currentAdditionalProduct.refKey;
376
- const j = additionalProductRefs.findIndex((p) => p.prodRef.refKey === refKey);
364
+ const j = additionalProductRefs.findIndex((p) => {
365
+ const prodRef = p.prodRef;
366
+ return (prodRef.refKey === currentAdditionalProduct.refKey &&
367
+ prodRef.partNumber === currentAdditionalProduct.partNumber &&
368
+ isSameCatalogueParams(prodRef.catId, currentAdditionalProduct.catId));
369
+ });
377
370
  if (j === -1) {
378
371
  currentAdditionalProduct.destroy();
379
372
  currentAdditionalProducts.splice(i, 1);
380
373
  change = true;
381
374
  }
382
375
  else {
376
+ currentAdditionalProduct._internal._updateAdditionalProdRef(additionalProductRefs[j].prodRef);
383
377
  additionalProductRefs.splice(j, 1);
384
378
  }
385
379
  }
@@ -392,7 +386,7 @@ export class _CfgProductInternal {
392
386
  const additionalProductRef = p.prodRef;
393
387
  return {
394
388
  originalIndex: p.originalIndex,
395
- product: CfgProduct._makeNewRefFrom(yield _CfgProductInternal.make(productLoaderRaw, productLoaderForGroupedLoad, lang, additionalProductRef.catId, additionalProductRef.partNumber, this.settings, additionalProductRef.optional === true, this.loadingObservable, additionalProductRef.refKey, additionalProductRef.refDescription, this, this.root, additionalProductRef.transform, additionalProductRef.anchor)),
389
+ product: CfgProduct._makeNewRefFrom(yield _CfgProductInternal.make(productLoaderRaw, productLoaderForGroupedLoad, lang, additionalProductRef.catId, additionalProductRef.partNumber, this.settings, additionalProductRef.optional === true, this.loadingObservable, this, this.root, additionalProductRef)),
396
390
  };
397
391
  }))()));
398
392
  if (this._destroyed) {
@@ -411,7 +405,7 @@ export class _CfgProductInternal {
411
405
  }
412
406
  });
413
407
  this.root = root !== null && root !== void 0 ? root : this;
414
- this.key = makeProductKey(catId, refKey || partNumber);
408
+ this.key = makeProductKey(catId, (_a = _additionalProductRef === null || _additionalProductRef === void 0 ? void 0 : _additionalProductRef.refKey) !== null && _a !== void 0 ? _a : partNumber);
415
409
  this._selected = optional ? selected : undefined;
416
410
  this.isAdditionalProduct = parent !== undefined;
417
411
  this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, allRawFeatures, apiSelection, this, this.root);
@@ -425,7 +419,7 @@ export class _CfgProductInternal {
425
419
  var _a;
426
420
  const p = new _CfgProductInternal(() => {
427
421
  initSuccess(p);
428
- }, initFail, this._productLoaderRaw, this.lang, this.catId, this.partNumber, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.allRawFeatures, this.uuid, this._rawUnit, this._rawProductData, this.configuration.getApiSelection(), new AggregatedLoadingObservable(), this.refKey, this.refDescription, parent, root, this.transform, this.anchor, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
422
+ }, initFail, this._productLoaderRaw, this.lang, this.catId, this.partNumber, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.allRawFeatures, this.uuid, this._rawUnit, this._rawProductData, this.configuration.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
429
423
  });
430
424
  for (const additionalProduct of this.additionalProducts) {
431
425
  product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
@@ -433,8 +427,15 @@ export class _CfgProductInternal {
433
427
  return product;
434
428
  });
435
429
  }
430
+ _updateAdditionalProdRef(p) {
431
+ this._additionalProductRef = p;
432
+ if (p.optional !== this.optional) {
433
+ this._selected = p.optional ? false : undefined;
434
+ }
435
+ }
436
436
  get description() {
437
- return this.refDescription || this._rawProductData.description;
437
+ var _a, _b;
438
+ return (_b = (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.refDescription) !== null && _b !== void 0 ? _b : this._rawProductData.description;
438
439
  }
439
440
  get rootNodeSources() {
440
441
  return this._rawProductData.models;
@@ -460,6 +461,18 @@ export class _CfgProductInternal {
460
461
  }
461
462
  return this._measureDefinitions;
462
463
  }
464
+ get refKey() {
465
+ var _a;
466
+ return (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.refKey;
467
+ }
468
+ get transform() {
469
+ var _a;
470
+ return (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.transform;
471
+ }
472
+ get anchor() {
473
+ var _a;
474
+ return (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.anchor;
475
+ }
463
476
  /** @throws an error if the actual unit sent by the server was not a LengthUnit */
464
477
  get unit() {
465
478
  if (this._unit === undefined) {
@@ -540,68 +553,17 @@ export class _CfgProductInternal {
540
553
  get syncGroupHandler() {
541
554
  return this.root._syncGroupHandler;
542
555
  }
543
- get path() {
544
- if (this.parent === undefined || this.refKey === undefined) {
545
- return [];
546
- }
547
- return [...this.parent.path, "p", this.refKey];
548
- }
549
- getFromPath(path) {
550
- path = path.slice();
551
- const s = path.shift();
552
- switch (s) {
553
- case undefined:
554
- return this;
555
- case "p":
556
- const refKey = path.shift();
557
- const additionalProduct = this.additionalProducts.find((p) => p.refKey === refKey);
558
- if (additionalProduct === undefined) {
559
- throw new Error(`Additional product not found "p, ${refKey}, ${path.join(", ")}"`);
560
- }
561
- return additionalProduct._internal.getFromPath(path);
562
- case "c":
563
- return this.configuration._internal.getFromPath(path);
564
- default:
565
- throw new Error(`Unexpected path segment ${s}`);
566
- }
567
- }
568
- getProductFromPath(path) {
569
- const p = this.getFromPath(path);
570
- if (p instanceof _CfgProductInternal) {
571
- return p;
572
- }
573
- throw new Error(`Path did not lead to a Product "${p.path.join(", ")}"`);
574
- }
575
- getProductConfigurationFromPath(path) {
576
- const c = this.getFromPath(path);
577
- if (c instanceof _CfgProductConfigurationInternal) {
578
- return c;
579
- }
580
- throw new Error(`Path did not lead to a ProductConfiguration "${c.path.join(", ")}"`);
581
- }
582
- getFeatureFromPath(path) {
583
- const f = this.getFromPath(path);
584
- if (f instanceof _CfgFeatureInternal) {
585
- return f;
586
- }
587
- throw new Error(`Path did not lead to a Feature "${f.path.join(", ")}"`);
588
- }
589
- getOptionFromPath(path) {
590
- const o = this.getFromPath(path);
591
- if (o instanceof _CfgOptionInternal) {
592
- return o;
593
- }
594
- throw new Error(`Path did not lead to a Option "${o.path.join(", ")}"`);
595
- }
596
556
  }
597
557
  _CfgProductInternal.make = (productLoaderRaw, productLoaderForGroupedLoad, // Used when instantiating the current product
598
- lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescription, parent, root, transform, anchor) => __awaiter(void 0, void 0, void 0, function* () {
558
+ lang, catId, partNumber, settings, optional, loadingObservable, parent, root, additionalProductRef) => __awaiter(void 0, void 0, void 0, function* () {
599
559
  // Wrap with cache will make getProduct for this function call use the same server call
600
560
  // for the same product with the same params. Not retained for future calls, only used
601
561
  // at this initial load.
602
562
  productLoaderForGroupedLoad =
603
563
  productLoaderForGroupedLoad || wrapWithCache(productLoaderRaw);
604
- const syncGroupHandler = root === undefined ? SyncGroupsHandler.make(settings.syncGroupsApplyMode) : undefined;
564
+ const syncGroupHandler = root === undefined
565
+ ? SyncGroupsHandler.make(settings.syncGroupsApplyMode, loadingObservable)
566
+ : undefined;
605
567
  const productResponse = yield productLoaderForGroupedLoad.getProduct(Object.assign(Object.assign({ lang }, correctDefaultsOnCatalogueParams(catId)), { partNumber }));
606
568
  const { productData, rootFeatureRefs, features: allRawFeatures, uuid, unit, } = productResponse;
607
569
  const product = yield new Promise((initSuccess, initFail) => {
@@ -610,7 +572,7 @@ lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescr
610
572
  // But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
611
573
  // Feel free to find a nicer more readable solution :)
612
574
  initSuccess(p);
613
- }, initFail, productLoaderRaw, lang, catId, partNumber, settings, optional, !optional, rootFeatureRefs, allRawFeatures, uuid, unit, productData, productData.partsData.selOptions || [], loadingObservable, refKey, refDescription, parent, root, transform, anchor, syncGroupHandler);
575
+ }, initFail, productLoaderRaw, lang, catId, partNumber, settings, optional, !optional, rootFeatureRefs, allRawFeatures, uuid, unit, productData, productData.partsData.selOptions || [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
614
576
  });
615
577
  yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
616
578
  // Product is guaranteed to be root
@@ -665,7 +627,7 @@ export class CfgProduct {
665
627
  }
666
628
  static make(productLoader, lang, catId, partNumber, settings) {
667
629
  return __awaiter(this, void 0, void 0, function* () {
668
- return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, lang, catId, partNumber, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined, undefined, undefined, undefined));
630
+ return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, lang, catId, partNumber, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined));
669
631
  });
670
632
  }
671
633
  /**
@@ -1,6 +1,6 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
2
  import { Feature, SelectedOption, SyncGroup } from "../CatalogueAPI.js";
3
- import { CfgPath, CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
3
+ import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { CfgOption, ProductConfigurationBubbleMode, _CfgOptionInternal } from "./CfgOption.js";
6
6
  import { _CfgProductConfigurationInternal } from "./CfgProductConfiguration.js";
@@ -96,8 +96,6 @@ export declare class _CfgFeatureInternal {
96
96
  setApiSelection: (apiOptionSelectionMap: {
97
97
  [index: string]: SelectedOption;
98
98
  } | undefined) => Promise<boolean>;
99
- get path(): CfgPath;
100
- getFromPath(path: CfgPath): _CfgFeatureInternal | _CfgOptionInternal;
101
99
  /** Pushes to refresh stretch. Does not cause validation. */
102
100
  pushStretch: () => Promise<boolean>;
103
101
  structureCompare: (other: _CfgFeatureInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { compareArrays, convertLength, count, Observable, someMatch, toLengthUnit, } from "@configura/web-utilities";
10
+ import { assertDefined, compareArrays, convertLength, count, Observable, someMatch, toLengthUnit, } from "@configura/web-utilities";
11
11
  import { CfgProduct } from "../CfgProduct.js";
12
12
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
13
13
  import { CfgMtrlApplicationSource } from "../material/CfgMtrlApplicationSource.js";
@@ -189,18 +189,6 @@ export class _CfgFeatureInternal {
189
189
  console.warn(wrongCountWarning);
190
190
  }
191
191
  }
192
- if (!isGroup) {
193
- const apiSelectionCount = Object.keys(apiOptionSelectionMap).length;
194
- if (selectionCount !== apiSelectionCount) {
195
- const wrongCountWarning = `All provided Options are expected to be selected. Feature key: "${this.key}". Expected: ${apiSelectionCount} Actual: ${selectionCount}`;
196
- if (this.rootProduct.settings.strictSetApiSelectionMatch) {
197
- throw new Error(wrongCountWarning);
198
- }
199
- else {
200
- console.warn(wrongCountWarning);
201
- }
202
- }
203
- }
204
192
  }
205
193
  if (change) {
206
194
  if (isAllOptionsAffectedByAnySelection) {
@@ -311,10 +299,8 @@ export class _CfgFeatureInternal {
311
299
  ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups) {
312
300
  const product = this.rootProduct;
313
301
  const syncGroupHandler = product.syncGroupHandler;
314
- if (syncGroupHandler === undefined) {
315
- throw new Error(`No sync group handler when bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
316
- }
317
- return yield syncGroupHandler.selectOption(product, optionInternal.path, on, wrapWithCache(product._productLoaderRaw));
302
+ assertDefined(syncGroupHandler, `Sync group handler is required for bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
303
+ return yield syncGroupHandler.selectOption(product, optionInternal, on, wrapWithCache(product._productLoaderRaw));
318
304
  }
319
305
  if (!on) {
320
306
  if (this.selectionType === SelectionType.Group) {
@@ -502,23 +488,6 @@ export class _CfgFeatureInternal {
502
488
  }
503
489
  return this._options;
504
490
  }
505
- get path() {
506
- return [...this.parent.path, this.code];
507
- }
508
- getFromPath(path) {
509
- path = path.slice();
510
- const s = path.shift();
511
- switch (s) {
512
- case undefined:
513
- return this;
514
- default:
515
- const option = this.options.find((o) => o.code === s);
516
- if (option === undefined) {
517
- throw new Error(`Option not found ${s}, ${path.join(", ")}`);
518
- }
519
- return option._internal.getFromPath(path);
520
- }
521
- }
522
491
  /**
523
492
  * Make fresh references to all options on this feature.
524
493
  * Also includes currently selected options.
@@ -1,6 +1,6 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
2
  import { Feature, Option, SelectedOption } from "../CatalogueAPI.js";
3
- import { CfgPath, CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
3
+ import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { NumericValuesSelection } from "../utilitiesNumericValues.js";
6
6
  import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
@@ -14,19 +14,19 @@ export declare enum ProductConfigurationBubbleMode {
14
14
  */
15
15
  BubbleSelected = "BubbleSelected",
16
16
  /**
17
- * Bubble to the closest CfgProduct, let it revalidate, then that will continue
18
- * the bubble after validate.
17
+ * Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
18
+ * after validate.
19
19
  */
20
20
  Validate = "Validate",
21
21
  /**
22
- * Bubble to the closest CfgProduct, let it revalidate, then that will continue
23
- * the bubble after validate. If this is select it will turns on all ancestors all the way up.
22
+ * Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
23
+ * after validate. If this is select it will turn on all ancestors all the way up.
24
24
  * So with this mode it is possible to select an option where its parents are not selected.
25
25
  */
26
26
  ValidateAndBubbleSelected = "ValidateAndBubbleSelected",
27
27
  /**
28
- * Like ValidateAndBubbleSelected, but SyncGroups are applied after
29
- * ValidateAndBubbleSelected has been done
28
+ * Like ValidateAndBubbleSelected, but SyncGroups are applied after ValidateAndBubbleSelected
29
+ * has been done
30
30
  */
31
31
  ValidateAndBubbleSelectedAndApplySyncGroups = "ValidateAndBubbleSelectedAndApplySyncGroups",
32
32
  /**
@@ -53,10 +53,9 @@ export declare enum ProductConfigurationBubbleMode {
53
53
  ToRoot = "ToRoot"
54
54
  }
55
55
  /**
56
- * This class is meant to only be used through CfgOption. It should
57
- * never be instantiated on its own. Normally the internal state of this class
58
- * should never be directly modified. CfgOption is the class that
59
- * should be used and interacted with.
56
+ * This class is only meant to be used through CfgOption. It should never be instantiated on its
57
+ * own. Normally the internal state of this class should never be directly modified. CfgOption is
58
+ * the class that should be used and interacted with.
60
59
  */
61
60
  export declare class _CfgOptionInternal {
62
61
  readonly rawOption: Option;
@@ -80,6 +79,7 @@ export declare class _CfgOptionInternal {
80
79
  get unit(): LengthUnit;
81
80
  get description(): string;
82
81
  get selected(): boolean;
82
+ get selectedChangeInProgress(): boolean;
83
83
  get ancestorsSelected(): boolean;
84
84
  get mtrlApplications(): CfgMtrlApplication[];
85
85
  get thumbnail(): string | undefined;
@@ -90,8 +90,6 @@ export declare class _CfgOptionInternal {
90
90
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode) => Promise<void>;
91
91
  getApiSelection: () => SelectedOption;
92
92
  setApiSelection: (apiOptionSelection: SelectedOption | undefined) => Promise<boolean>;
93
- get path(): CfgPath;
94
- getFromPath(path: CfgPath): _CfgFeatureInternal | _CfgOptionInternal;
95
93
  structureCompare: (other: _CfgOptionInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
96
94
  tryMatchSelection: (other: CfgOption, descriptionMatch?: boolean) => Promise<boolean>;
97
95
  keyMatch: (other: _CfgOptionInternal, descriptionMatch?: boolean) => boolean;
@@ -127,8 +125,21 @@ export declare class CfgOption {
127
125
  get unit(): LengthUnit;
128
126
  get description(): string;
129
127
  get selected(): boolean;
128
+ /**
129
+ * Selection state is in progress to be changed. This can be used in GUI
130
+ * to display the state as transitioning, or as already changed.
131
+ * If selectedChangeInProgress and:
132
+ * selected is true, it means that this is about to get unselected
133
+ * selected is false, it means that this is about to get selected
134
+ */
135
+ get selectedChangeInProgress(): boolean;
130
136
  /** Are all ancestors up to the CfgProductConfiguration selected? Includes self. */
131
137
  get ancestorsSelected(): boolean;
138
+ /**
139
+ * Selects this Option.
140
+ * Only Options belonging to Features that are "select many" can be deselected.
141
+ * Calling this will cause a validation call to the server.
142
+ */
132
143
  setSelected: (on: boolean) => Promise<boolean>;
133
144
  get thumbnail(): string | undefined;
134
145
  get upcharge(): number | undefined;