@configura/web-api 1.6.0-alpha.0 → 1.6.0-iotest.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/CfgProduct.d.ts +12 -31
  2. package/dist/CfgProduct.js +41 -130
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +4 -2
  5. package/dist/io/CfgHistoryManager.d.ts +30 -0
  6. package/dist/io/CfgHistoryManager.js +62 -0
  7. package/dist/io/CfgHistoryToProdConfConnector.d.ts +10 -0
  8. package/dist/io/CfgHistoryToProdConfConnector.js +20 -0
  9. package/dist/io/CfgIOManager.d.ts +29 -0
  10. package/dist/io/CfgIOManager.js +89 -0
  11. package/dist/io/CfgIOProdConfConnector.d.ts +33 -0
  12. package/dist/io/CfgIOProdConfConnector.js +100 -0
  13. package/dist/io/CfgWindowMessageManager.d.ts +13 -0
  14. package/dist/io/CfgWindowMessageManager.js +28 -0
  15. package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +13 -0
  16. package/dist/io/CfgWindowMessageToProdConfConnector.js +17 -0
  17. package/dist/productConfiguration/CfgFeature.d.ts +2 -5
  18. package/dist/productConfiguration/CfgFeature.js +7 -44
  19. package/dist/productConfiguration/CfgOption.d.ts +1 -12
  20. package/dist/productConfiguration/CfgOption.js +3 -30
  21. package/dist/productConfiguration/CfgProductConfiguration.d.ts +4 -5
  22. package/dist/productConfiguration/CfgProductConfiguration.js +8 -26
  23. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +95 -24
  24. package/dist/tests/testData/testDataCachedGetProduct.js +19 -8
  25. package/dist/tests/testData/testDataProductAggregatedPrice.js +23 -12
  26. package/dist/tests/testData/testDataUpcharge.js +48 -16
  27. package/dist/utilitiesCatalogueData.js +4 -3
  28. package/package.json +3 -3
  29. package/dist/syncGroups/SyncGroupsApplier.d.ts +0 -20
  30. package/dist/syncGroups/SyncGroupsApplier.js +0 -518
  31. package/dist/syncGroups/SyncGroupsApplyMode.d.ts +0 -15
  32. package/dist/syncGroups/SyncGroupsApplyMode.js +0 -15
  33. package/dist/syncGroups/SyncGroupsHandler.d.ts +0 -30
  34. package/dist/syncGroups/SyncGroupsHandler.js +0 -71
  35. package/dist/syncGroups/SyncGroupsState.d.ts +0 -20
  36. package/dist/syncGroups/SyncGroupsState.js +0 -61
  37. package/dist/syncGroups/SyncGroupsTransaction.d.ts +0 -50
  38. package/dist/syncGroups/SyncGroupsTransaction.js +0 -106
  39. package/dist/tests/testData/testDataOptions.d.ts +0 -13
  40. package/dist/tests/testData/testDataOptions.js +0 -60
@@ -2,14 +2,13 @@ import { AggregatedLoadingObservable, LengthUnit, Observable, SingleArgCallback
2
2
  import { AdditionalProductConfiguration, 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
- import { SyncGroupsApplyMode } from "./syncGroups/SyncGroupsApplyMode.js";
9
- import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
10
8
  import { CfgProductData, RootNodeSource } from "./utilitiesCatalogueData.js";
11
9
  export declare type CfgProductChangeNotification = {
12
10
  freshRef: CfgProduct;
11
+ committed: boolean;
13
12
  };
14
13
  export declare type CfgProductSettings = {
15
14
  /**
@@ -26,12 +25,6 @@ export declare type CfgProductSettings = {
26
25
  * believe is a rare use case.
27
26
  */
28
27
  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.
33
- */
34
- syncGroupsApplyMode: SyncGroupsApplyMode | undefined;
35
28
  };
36
29
  /**
37
30
  * This enum is used internally in the SDK and is not expected by be used directly by integrators.
@@ -56,12 +49,6 @@ export declare type CfgPrice = {
56
49
  currency: string;
57
50
  fractionDigits: number;
58
51
  };
59
- export declare type CfgPathSegment = string;
60
- export declare type CfgPath = CfgPathSegment[];
61
- export declare type RevalidateResult = {
62
- wasAborted: boolean;
63
- requestDidValidate: boolean;
64
- };
65
52
  /**
66
53
  * This class is meant to only be used through CfgProduct. It should never be instantiated on its
67
54
  * own. Normally the internal state of this class should never be directly modified. CfgProduct is
@@ -82,7 +69,6 @@ export declare class _CfgProductInternal {
82
69
  readonly parent: _CfgProductInternal | undefined;
83
70
  readonly transform: Transform | undefined;
84
71
  anchor: MeasureParam | undefined;
85
- private readonly _syncGroupHandler;
86
72
  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>;
87
73
  private constructor();
88
74
  readonly root: _CfgProductInternal;
@@ -127,24 +113,17 @@ export declare class _CfgProductInternal {
127
113
  * It does not affect the visibility of anything in the 3D view at all.
128
114
  */
129
115
  get visible(): boolean;
130
- _notifyAllOfChange: (bubbleMode: CfgProductBubbleMode) => Promise<void>;
116
+ _notifyAllOfChange: (bubbleMode: CfgProductBubbleMode, committed: boolean) => Promise<void>;
131
117
  /** Called when a child (additional product or the configuration) has changed. */
132
118
  private _childHasChanged;
133
119
  /** Called by child to tell its parent that it has changed. */
134
- _additionalProductHasChanged: (freshRef: CfgProduct, bubbleMode: CfgProductBubbleMode) => Promise<void>;
120
+ _additionalProductHasChanged: (freshRef: CfgProduct, bubbleMode: CfgProductBubbleMode, committed: boolean) => Promise<void>;
135
121
  /** Called by the configuration to tell its parent that it has changed. */
136
- _configurationHasChanged: (freshRef: CfgProductConfiguration, bubbleMode: ProductConfigurationBubbleMode) => Promise<void>;
122
+ _configurationHasChanged: (freshRef: CfgProductConfiguration, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
137
123
  getApiSelection: () => AdditionalProductConfiguration;
138
124
  setApiSelection: (s: AdditionalProductConfiguration, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
139
- copyFrom: (otherProduct: _CfgProductInternal, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
140
- private _setApiSelectionWithOtherProduct;
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;
125
+ getApiSelectionAsString: () => string;
126
+ setFromApiSelectionString: (str: string, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
148
127
  structureCompare: (other: _CfgProductInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
149
128
  tryMatchSelection: (other: _CfgProductInternal, descriptionMatch?: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
150
129
  /** Only features in selected options and selected additional products. */
@@ -155,7 +134,7 @@ export declare class _CfgProductInternal {
155
134
  * product in isolation. The validation result is applied on the configuration. Then additional
156
135
  * products are synced (unloaded, loaded etc.) Finally the changes bubble up the tree.
157
136
  */
158
- _revalidate: (bubbleMode: CfgProductBubbleMode, productLoader: ProductLoader) => Promise<RevalidateResult>;
137
+ _revalidate: (bubbleMode: CfgProductBubbleMode, productLoader: ProductLoader, committed: boolean) => Promise<boolean>;
159
138
  /**
160
139
  * Based on this configuration find what additional products should be shown and not, unload
161
140
  * (i.e. destroy) those that should no longer be shown, load the new ones.
@@ -167,7 +146,7 @@ export declare class CfgProduct {
167
146
  static make(productLoader: ProductLoader, lang: string, catId: CatalogueParams, partNumber: string, settings?: Partial<CfgProductSettings>): Promise<CfgProduct>;
168
147
  /**
169
148
  * Makes an object wrapping the passed object. This is not a clone method, it is a method to
170
- * make a new outer reference. Like a shallow copy. We use this to help frameworks that are
149
+ * make a new outer reference. Like a shallow copy./ We use this to help frameworks that are
171
150
  * build around using equals to detect change.
172
151
  */
173
152
  static _makeNewRefFrom(source: _CfgProductInternal): CfgProduct;
@@ -254,6 +233,8 @@ export declare class CfgProduct {
254
233
  */
255
234
  getApiSelection: () => AdditionalProductConfiguration;
256
235
  setApiSelection: (s: AdditionalProductConfiguration, doValidate?: boolean) => Promise<boolean>;
236
+ getApiSelectionAsString: () => string;
237
+ setFromApiSelectionString: (str: string, doValidate?: boolean) => Promise<boolean>;
257
238
  listenForChange: (l: SingleArgCallback<CfgProductChangeNotification>) => void;
258
239
  stopListenForChange: (l: SingleArgCallback<CfgProductChangeNotification>) => void;
259
240
  stopAllListenForChange: () => void;
@@ -9,19 +9,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { AggregatedLoadingObservable, 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
- import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
18
16
  import { comparePricesObjects, correctDefaultsOnCatalogueParams, makeProductKey, } from "./utilitiesCatalogueData.js";
19
17
  function completeSettings(incompleteSettings) {
20
18
  var _a, _b;
21
19
  return {
22
20
  strictSelectOneSelectionCount: (_a = incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.strictSelectOneSelectionCount) !== null && _a !== void 0 ? _a : false,
23
21
  strictSetApiSelectionMatch: (_b = incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.strictSetApiSelectionMatch) !== null && _b !== void 0 ? _b : false,
24
- syncGroupsApplyMode: incompleteSettings === null || incompleteSettings === void 0 ? void 0 : incompleteSettings.syncGroupsApplyMode,
25
22
  };
26
23
  }
27
24
  /**
@@ -53,7 +50,7 @@ function isDescriptionMatch(l, r) {
53
50
  * the class that should be used and interacted with.
54
51
  */
55
52
  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) {
53
+ constructor(initSuccess, initFail, _productLoaderRaw, lang, catId, partNumber, settings, optional, selected, rootFeatureRefs, allRawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, refKey, refDescription, parent, root, transform, anchor) {
57
54
  this._productLoaderRaw = _productLoaderRaw;
58
55
  this.lang = lang;
59
56
  this.catId = catId;
@@ -68,7 +65,6 @@ export class _CfgProductInternal {
68
65
  this.parent = parent;
69
66
  this.transform = transform;
70
67
  this.anchor = anchor;
71
- this._syncGroupHandler = _syncGroupHandler;
72
68
  this._destroyed = false;
73
69
  this.additionalProducts = [];
74
70
  this.changeObservable = new Observable();
@@ -80,31 +76,31 @@ export class _CfgProductInternal {
80
76
  additionalProduct.destroy();
81
77
  }
82
78
  };
83
- this._notifyAllOfChange = (bubbleMode) => __awaiter(this, void 0, void 0, function* () {
79
+ this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
84
80
  if (bubbleMode === CfgProductBubbleMode.Stop) {
85
81
  return;
86
82
  }
87
83
  const parent = this.parent;
88
84
  const freshRef = CfgProduct._makeNewRefFrom(this);
89
- this.changeObservable.notifyAll({ freshRef });
85
+ this.changeObservable.notifyAll({ freshRef, committed });
90
86
  if (parent !== undefined) {
91
87
  yield parent._additionalProductHasChanged(freshRef, bubbleMode === CfgProductBubbleMode.OneLevel
92
88
  ? CfgProductBubbleMode.Stop
93
- : bubbleMode);
89
+ : bubbleMode, committed);
94
90
  }
95
91
  });
96
92
  /** Called when a child (additional product or the configuration) has changed. */
97
- this._childHasChanged = (bubbleMode) => __awaiter(this, void 0, void 0, function* () {
93
+ this._childHasChanged = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
98
94
  if (bubbleMode === CfgProductBubbleMode.ToRootAndBubbleSelected &&
99
95
  this.optional &&
100
96
  !this.selected) {
101
97
  yield this.setSelected(true, bubbleMode);
102
98
  return;
103
99
  }
104
- yield this._notifyAllOfChange(bubbleMode);
100
+ yield this._notifyAllOfChange(bubbleMode, committed);
105
101
  });
106
102
  /** Called by child to tell its parent that it has changed. */
107
- this._additionalProductHasChanged = (freshRef, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
103
+ this._additionalProductHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
108
104
  const i = this.additionalProducts.findIndex((a) => a.isBackedBySame(freshRef));
109
105
  if (i !== -1) {
110
106
  // Child additional product might not be found. This probably means that propagate
@@ -114,34 +110,31 @@ export class _CfgProductInternal {
114
110
  // C no longer is part of the tree. Odd, but fully permitted.
115
111
  this.additionalProducts[i] = freshRef;
116
112
  }
117
- yield this._childHasChanged(bubbleMode);
113
+ yield this._childHasChanged(bubbleMode, committed);
118
114
  });
119
115
  /** Called by the configuration to tell its parent that it has changed. */
120
- this._configurationHasChanged = (freshRef, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
116
+ this._configurationHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
121
117
  this._configuration = freshRef;
122
118
  switch (bubbleMode) {
123
119
  case ProductConfigurationBubbleMode.ValidateAndBubbleSelected:
124
120
  // The revalidate call will continue the bubble
125
- yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, this._productLoaderRaw);
126
- return;
127
- case ProductConfigurationBubbleMode.BubbleSelected:
128
- yield this._childHasChanged(CfgProductBubbleMode.ToRootAndBubbleSelected);
121
+ yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, this._productLoaderRaw, committed);
129
122
  return;
130
123
  case ProductConfigurationBubbleMode.Validate:
131
124
  // The revalidate call will continue the bubble
132
- yield this._revalidate(CfgProductBubbleMode.ToRoot, this._productLoaderRaw);
125
+ yield this._revalidate(CfgProductBubbleMode.ToRoot, this._productLoaderRaw, committed);
133
126
  return;
134
127
  case ProductConfigurationBubbleMode.ToParentProduct:
135
128
  // Do not continue bubble as we have reached the parent CfgProduct
136
129
  return;
137
130
  case ProductConfigurationBubbleMode.OneLevel:
138
- yield this._childHasChanged(CfgProductBubbleMode.OneLevel);
131
+ yield this._childHasChanged(CfgProductBubbleMode.OneLevel, committed);
139
132
  return;
140
133
  case ProductConfigurationBubbleMode.Stop:
141
- yield this._childHasChanged(CfgProductBubbleMode.Stop);
134
+ yield this._childHasChanged(CfgProductBubbleMode.Stop, committed);
142
135
  return;
143
136
  case ProductConfigurationBubbleMode.ToRoot:
144
- yield this._childHasChanged(CfgProductBubbleMode.ToRoot);
137
+ yield this._childHasChanged(CfgProductBubbleMode.ToRoot, committed);
145
138
  return;
146
139
  }
147
140
  });
@@ -152,26 +145,13 @@ export class _CfgProductInternal {
152
145
  additionalProducts: this.additionalProducts.map((additionalProduct) => additionalProduct.getApiSelection()),
153
146
  });
154
147
  this.setApiSelection = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
155
- return this._setApiSelectionWithOtherProduct(s, doValidate, productLoaderForGroupedLoad, undefined);
156
- });
157
- this.copyFrom = (otherProduct, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
158
- return yield this._setApiSelectionWithOtherProduct(otherProduct.getApiSelection(), doValidate, productLoaderForGroupedLoad, otherProduct);
159
- });
160
- this._setApiSelectionWithOtherProduct = (s, doValidate, productLoaderForGroupedLoad, sourceProduct) => __awaiter(this, void 0, void 0, function* () {
161
148
  // Wrap with cache will make getProduct for this function call use the same server call
162
149
  // for the same product with the same params. Used for getProduct (when a new additional
163
150
  // product is loaded) and postValidate.
164
151
  productLoaderForGroupedLoad =
165
152
  productLoaderForGroupedLoad || wrapWithCache(this._productLoaderRaw);
166
- let change = false;
167
- if (sourceProduct !== undefined) {
168
- this._rawProductData = sourceProduct.rawProductData;
169
- change = true; // We can not know if this is an actual change, so we assume it is
170
- }
171
153
  const configurationChange = yield this.configuration._internal.setApiSelection(s.selOptions, false);
172
- if (configurationChange) {
173
- change = true;
174
- }
154
+ let change = configurationChange;
175
155
  if (this.optional) {
176
156
  if (yield this.setSelected(s.selected !== false, CfgProductBubbleMode.Stop)) {
177
157
  change = true;
@@ -185,14 +165,8 @@ export class _CfgProductInternal {
185
165
  if (apiSelectionAdditionalProductsCount !== additionalProductsCount) {
186
166
  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
167
  }
188
- 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
- }
193
- if ((yield Promise.all(apiSelectionAdditionalProducts.map((apiSelectionAdditionalProduct, index) => {
194
- var _a;
195
- const refKey = apiSelectionAdditionalProduct.refKey;
168
+ if ((yield Promise.all(apiSelectionAdditionalProducts.map((apiSelectionChild) => {
169
+ const refKey = apiSelectionChild.refKey;
196
170
  if (refKey === undefined) {
197
171
  throw new Error("Additional product api configurations must have refKey.");
198
172
  }
@@ -200,30 +174,26 @@ export class _CfgProductInternal {
200
174
  if (i === -1) {
201
175
  throw new Error(`Additional product not found. This product: "${this.key}". refKey of not found additional product: "${refKey}"`);
202
176
  }
203
- let sourceProductAdditionalProduct = undefined;
204
- if (sourceProductAdditionalProducts !== undefined) {
205
- sourceProductAdditionalProduct =
206
- (_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
- }
210
- }
211
177
  const additionalProduct = additionalProducts.splice(i, 1)[0]; // Splicing like this is okay because this is done synchronous. The setCon. is what is async.
212
- return additionalProduct._internal._setApiSelectionWithOtherProduct(apiSelectionAdditionalProduct, doValidate, productLoaderForGroupedLoad, sourceProductAdditionalProduct);
178
+ return additionalProduct._internal.setApiSelection(apiSelectionChild, doValidate, productLoaderForGroupedLoad);
213
179
  }))).some((b) => b)) {
214
180
  change = true;
215
181
  }
216
182
  if (doValidate && configurationChange) {
217
- yield this._revalidate(CfgProductBubbleMode.ToRoot, productLoaderForGroupedLoad);
183
+ yield this._revalidate(CfgProductBubbleMode.ToRoot, productLoaderForGroupedLoad, true);
218
184
  }
219
185
  else if (change) {
220
186
  // As setApiSelection is done recursively each level takes care of its own notifications
221
187
  // so we only need to bubble one level to notify this and swap out the reference in the
222
188
  // parent.
223
- yield this._notifyAllOfChange(CfgProductBubbleMode.OneLevel);
189
+ yield this._notifyAllOfChange(CfgProductBubbleMode.OneLevel, true);
224
190
  }
225
191
  return change;
226
192
  });
193
+ this.getApiSelectionAsString = () => JSON.stringify(this.getApiSelection(), undefined, "");
194
+ this.setFromApiSelectionString = (str, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
195
+ return this.setApiSelection(JSON.parse(decodeURIComponent(str)), doValidate, productLoaderForGroupedLoad);
196
+ });
227
197
  this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => {
228
198
  if (!this.configuration.structureCompare(other.configuration, strictOrder, descriptionMatch)) {
229
199
  return false;
@@ -246,10 +216,10 @@ export class _CfgProductInternal {
246
216
  const configurationChange = yield this.configuration._internal.tryMatchSelection(other.configuration._internal, descriptionMatch, false);
247
217
  if (configurationChange) {
248
218
  change = true;
249
- yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, productLoaderForGroupedLoad);
219
+ yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, productLoaderForGroupedLoad, true);
250
220
  }
251
221
  else if (change) {
252
- yield this._notifyAllOfChange(CfgProductBubbleMode.ToRootAndBubbleSelected);
222
+ yield this._notifyAllOfChange(CfgProductBubbleMode.ToRootAndBubbleSelected, true);
253
223
  }
254
224
  const thisAdditionalProducts = this.additionalProducts;
255
225
  const otherAdditionalProducts = other.additionalProducts;
@@ -298,13 +268,12 @@ export class _CfgProductInternal {
298
268
  * product in isolation. The validation result is applied on the configuration. Then additional
299
269
  * products are synced (unloaded, loaded etc.) Finally the changes bubble up the tree.
300
270
  */
301
- this._revalidate = (bubbleMode, productLoader) => __awaiter(this, void 0, void 0, function* () {
271
+ this._revalidate = (bubbleMode, productLoader, committed) => __awaiter(this, void 0, void 0, function* () {
302
272
  const { _configuration: configuration } = this;
303
273
  const token = this.loadingObservable.startChildLoading();
304
274
  this._revalidateInProgressToken = token;
305
275
  try {
306
276
  const response = yield productLoader.postValidate(Object.assign(Object.assign({ lang: this.lang }, correctDefaultsOnCatalogueParams(this.catId)), { partNumber: this.partNumber }), { selOptions: configuration.getApiSelection() });
307
- const requestDidValidate = response.validated;
308
277
  // The revalidateInProgressToken is used to know if some other revalidate
309
278
  // call has happened after this call, thereby making this call obsolete.
310
279
  // This is a bit crude in that it does not actually cancel previous validate
@@ -313,7 +282,7 @@ export class _CfgProductInternal {
313
282
  // of all, the heavy work happens on the server, and that work will not be
314
283
  // cancelled even if we would cancel the call.
315
284
  if (this._revalidateInProgressToken !== token) {
316
- return { wasAborted: true, requestDidValidate };
285
+ return false;
317
286
  }
318
287
  // After a successful validate-call we will always assume there
319
288
  // is a change. It would be possible to compare relevant parts
@@ -321,7 +290,7 @@ export class _CfgProductInternal {
321
290
  // syndAndLoad, however the code comparing productData would be fragile
322
291
  // and likely to break if new data-fields were added.
323
292
  if (this._destroyed) {
324
- return { wasAborted: true, requestDidValidate };
293
+ return false;
325
294
  }
326
295
  const { productData, rootFeatureRefs } = response;
327
296
  const pricesUpdated = !comparePricesObjects(this.prices, productData.partsData.prices);
@@ -336,10 +305,10 @@ export class _CfgProductInternal {
336
305
  yield configuration._internal.setApiSelection(productData.partsData.selOptions || [], false);
337
306
  yield this._syncAndLoadAdditionalProducts(productLoader);
338
307
  if (this._destroyed) {
339
- return { wasAborted: true, requestDidValidate };
308
+ return false;
340
309
  }
341
- yield this._notifyAllOfChange(bubbleMode);
342
- return { wasAborted: false, requestDidValidate };
310
+ yield this._notifyAllOfChange(bubbleMode, committed);
311
+ return true;
343
312
  }
344
313
  catch (e) {
345
314
  throw e;
@@ -403,7 +372,7 @@ export class _CfgProductInternal {
403
372
  this.loadingObservable.stopChildLoading(token);
404
373
  }
405
374
  });
406
- this.root = root !== null && root !== void 0 ? root : this;
375
+ this.root = root || this;
407
376
  this.key = makeProductKey(catId, refKey || partNumber);
408
377
  this._selected = optional ? selected : undefined;
409
378
  this.isAdditionalProduct = parent !== undefined;
@@ -415,10 +384,9 @@ export class _CfgProductInternal {
415
384
  clone(parent, root) {
416
385
  return __awaiter(this, void 0, void 0, function* () {
417
386
  const product = yield new Promise((initSuccess, initFail) => {
418
- var _a;
419
387
  const p = new _CfgProductInternal(() => {
420
388
  initSuccess(p);
421
- }, 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());
389
+ }, 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);
422
390
  });
423
391
  for (const additionalProduct of this.additionalProducts) {
424
392
  product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
@@ -497,7 +465,7 @@ export class _CfgProductInternal {
497
465
  return false;
498
466
  }
499
467
  this._selected = v;
500
- yield this._notifyAllOfChange(bubbleMode);
468
+ yield this._notifyAllOfChange(bubbleMode, true);
501
469
  return true;
502
470
  });
503
471
  }
@@ -530,62 +498,6 @@ export class _CfgProductInternal {
530
498
  ? this.visibleIfAdditionalProduct
531
499
  : this.visibleIfMainProduct;
532
500
  }
533
- get syncGroupHandler() {
534
- return this.root._syncGroupHandler;
535
- }
536
- get path() {
537
- if (this.parent === undefined || this.refKey === undefined) {
538
- return [];
539
- }
540
- return [...this.parent.path, "p", this.refKey];
541
- }
542
- getFromPath(path) {
543
- path = path.slice();
544
- const s = path.shift();
545
- switch (s) {
546
- case undefined:
547
- return this;
548
- case "p":
549
- const refKey = path.shift();
550
- const additionalProduct = this.additionalProducts.find((p) => p.refKey === refKey);
551
- if (additionalProduct === undefined) {
552
- throw new Error(`Additional product not found "p, ${refKey}, ${path.join(", ")}"`);
553
- }
554
- return additionalProduct._internal.getFromPath(path);
555
- case "c":
556
- return this.configuration._internal.getFromPath(path);
557
- default:
558
- throw new Error(`Unexpected path segment ${s}`);
559
- }
560
- }
561
- getProductFromPath(path) {
562
- const p = this.getFromPath(path);
563
- if (p instanceof _CfgProductInternal) {
564
- return p;
565
- }
566
- throw new Error(`Path did not lead to a Product "${p.path.join(", ")}"`);
567
- }
568
- getProductConfigurationFromPath(path) {
569
- const c = this.getFromPath(path);
570
- if (c instanceof _CfgProductConfigurationInternal) {
571
- return c;
572
- }
573
- throw new Error(`Path did not lead to a ProductConfiguration "${c.path.join(", ")}"`);
574
- }
575
- getFeatureFromPath(path) {
576
- const f = this.getFromPath(path);
577
- if (f instanceof _CfgFeatureInternal) {
578
- return f;
579
- }
580
- throw new Error(`Path did not lead to a Feature "${f.path.join(", ")}"`);
581
- }
582
- getOptionFromPath(path) {
583
- const o = this.getFromPath(path);
584
- if (o instanceof _CfgOptionInternal) {
585
- return o;
586
- }
587
- throw new Error(`Path did not lead to a Option "${o.path.join(", ")}"`);
588
- }
589
501
  }
590
502
  _CfgProductInternal.make = (productLoaderRaw, productLoaderForGroupedLoad, // Used when instantiating the current product
591
503
  lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescription, parent, root, transform, anchor) => __awaiter(void 0, void 0, void 0, function* () {
@@ -594,7 +506,6 @@ lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescr
594
506
  // at this initial load.
595
507
  productLoaderForGroupedLoad =
596
508
  productLoaderForGroupedLoad || wrapWithCache(productLoaderRaw);
597
- const syncGroupHandler = root === undefined ? SyncGroupsHandler.make(settings.syncGroupsApplyMode) : undefined;
598
509
  const productResponse = yield productLoaderForGroupedLoad.getProduct(Object.assign(Object.assign({ lang }, correctDefaultsOnCatalogueParams(catId)), { partNumber }));
599
510
  const { productData, rootFeatureRefs, features: allRawFeatures, uuid, unit, } = productResponse;
600
511
  const product = yield new Promise((initSuccess, initFail) => {
@@ -603,11 +514,9 @@ lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescr
603
514
  // But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
604
515
  // Feel free to find a nicer more readable solution :)
605
516
  initSuccess(p);
606
- }, initFail, productLoaderRaw, lang, catId, partNumber, settings, optional, !optional, rootFeatureRefs, allRawFeatures, uuid, unit, productData, productData.partsData.selOptions || [], loadingObservable, refKey, refDescription, parent, root, transform, anchor, syncGroupHandler);
517
+ }, initFail, productLoaderRaw, lang, catId, partNumber, settings, optional, !optional, rootFeatureRefs, allRawFeatures, uuid, unit, productData, productData.partsData.selOptions || [], loadingObservable, refKey, refDescription, parent, root, transform, anchor);
607
518
  });
608
519
  yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
609
- // Product is guaranteed to be root
610
- yield (syncGroupHandler === null || syncGroupHandler === void 0 ? void 0 : syncGroupHandler.init(product, productLoaderForGroupedLoad));
611
520
  return product;
612
521
  });
613
522
  export class CfgProduct {
@@ -649,6 +558,8 @@ export class CfgProduct {
649
558
  */
650
559
  this.getApiSelection = () => this._internal.getApiSelection();
651
560
  this.setApiSelection = (s, doValidate = false) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setApiSelection(s, doValidate); });
561
+ this.getApiSelectionAsString = () => this._internal.getApiSelectionAsString();
562
+ this.setFromApiSelectionString = (str, doValidate = false) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setFromApiSelectionString(str, doValidate); });
652
563
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
653
564
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
654
565
  this.stopAllListenForChange = () => this._internal.changeObservable.stopAllListen();
@@ -663,7 +574,7 @@ export class CfgProduct {
663
574
  }
664
575
  /**
665
576
  * Makes an object wrapping the passed object. This is not a clone method, it is a method to
666
- * make a new outer reference. Like a shallow copy. We use this to help frameworks that are
577
+ * make a new outer reference. Like a shallow copy./ We use this to help frameworks that are
667
578
  * build around using equals to detect change.
668
579
  */
669
580
  static _makeNewRefFrom(source) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
+ export * from "./io/CfgHistoryManager.js";
4
+ export * from "./io/CfgHistoryToProdConfConnector.js";
5
+ export * from "./io/CfgWindowMessageManager.js";
6
+ export * from "./io/CfgWindowMessageToProdConfConnector.js";
3
7
  export * from "./material/CfgMaterialMapping.js";
4
8
  export * from "./material/CfgMtrlApplication.js";
5
9
  export * from "./material/CfgMtrlApplicationSource.js";
@@ -11,8 +15,6 @@ export * from "./productConfiguration/CfgProductConfiguration.js";
11
15
  export * from "./productConfiguration/filters.js";
12
16
  export * from "./productConfiguration/productParamsGenerator.js";
13
17
  export * from "./productLoader.js";
14
- export * from "./syncGroups/SyncGroupsApplyMode.js";
15
- export * from "./syncGroups/SyncGroupsHandler.js";
16
18
  export * from "./tasks/formats.js";
17
19
  export * from "./tasks/TaskHandler.js";
18
20
  export * from "./utilitiesCatalogueData.js";
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
+ export * from "./io/CfgHistoryManager.js";
4
+ export * from "./io/CfgHistoryToProdConfConnector.js";
5
+ export * from "./io/CfgWindowMessageManager.js";
6
+ export * from "./io/CfgWindowMessageToProdConfConnector.js";
3
7
  export * from "./material/CfgMaterialMapping.js";
4
8
  export * from "./material/CfgMtrlApplication.js";
5
9
  export * from "./material/CfgMtrlApplicationSource.js";
@@ -11,8 +15,6 @@ export * from "./productConfiguration/CfgProductConfiguration.js";
11
15
  export * from "./productConfiguration/filters.js";
12
16
  export * from "./productConfiguration/productParamsGenerator.js";
13
17
  export * from "./productLoader.js";
14
- export * from "./syncGroups/SyncGroupsApplyMode.js";
15
- export * from "./syncGroups/SyncGroupsHandler.js";
16
18
  export * from "./tasks/formats.js";
17
19
  export * from "./tasks/TaskHandler.js";
18
20
  export * from "./utilitiesCatalogueData.js";
@@ -0,0 +1,30 @@
1
+ import { CfgIOManager } from "./CfgIOManager.js";
2
+ export declare type CfgHistoryManagerSendData<D> = {
3
+ message: D;
4
+ qsKeyValues: Map<string, string | undefined> | undefined;
5
+ };
6
+ /**
7
+ * Instantiating the class will use the history api to update your
8
+ * url with configuration changes
9
+ * Only handles configuration, not product
10
+ */
11
+ export declare class CfgHistoryManager<D extends {
12
+ initial: boolean;
13
+ }> extends CfgIOManager<"popstate", CfgHistoryManagerSendData<D>> {
14
+ private readonly _useHistoryPush;
15
+ /**
16
+ * @param _useHistoryPush As opposed to replace. Push makes the web browser navigation buttons navigate configuration changes. Replace just updates the URL.
17
+ */
18
+ constructor(_useHistoryPush: boolean);
19
+ protected doSend(messageKey: string, data: CfgHistoryManagerSendData<D>): void;
20
+ private static _makeUpdatedUrl;
21
+ private static _makeUpdatedQueryString;
22
+ /**
23
+ * @returns The current query string as a Map
24
+ */
25
+ static _currentQsKeyValues(): Map<string, string>;
26
+ private static _makeUpdatedState;
27
+ protected readonly eventType = "popstate";
28
+ protected getDataFromEvent(event: PopStateEvent): unknown;
29
+ }
30
+ //# sourceMappingURL=CfgHistoryManager.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { mapQueryString, unmapQueryString } from "@configura/web-utilities";
2
+ import { CfgIOManager } from "./CfgIOManager.js";
3
+ /**
4
+ * Instantiating the class will use the history api to update your
5
+ * url with configuration changes
6
+ * Only handles configuration, not product
7
+ */
8
+ export class CfgHistoryManager extends CfgIOManager {
9
+ /**
10
+ * @param _useHistoryPush As opposed to replace. Push makes the web browser navigation buttons navigate configuration changes. Replace just updates the URL.
11
+ */
12
+ constructor(_useHistoryPush) {
13
+ super();
14
+ this._useHistoryPush = _useHistoryPush;
15
+ this.eventType = "popstate";
16
+ }
17
+ doSend(messageKey, data) {
18
+ const { qsKeyValues, message } = data;
19
+ const newUrl = qsKeyValues === undefined ? null : CfgHistoryManager._makeUpdatedUrl(qsKeyValues);
20
+ const newState = CfgHistoryManager._makeUpdatedState(message, messageKey);
21
+ if (!message.initial && this._useHistoryPush) {
22
+ window.history.pushState(newState, "", newUrl);
23
+ }
24
+ else {
25
+ window.history.replaceState(newState, "", newUrl);
26
+ }
27
+ }
28
+ static _makeUpdatedUrl(qsKeyValues) {
29
+ const qs = this._makeUpdatedQueryString(qsKeyValues);
30
+ return `${window.location.origin}${window.location.pathname}${qs ? "?" : ""}${qs}${window.location.hash}`;
31
+ }
32
+ static _makeUpdatedQueryString(qsKeyValues) {
33
+ const currentKeyValues = this._currentQsKeyValues();
34
+ for (const [key, value] of qsKeyValues) {
35
+ if (value === undefined) {
36
+ currentKeyValues.delete(key);
37
+ }
38
+ else {
39
+ currentKeyValues.set(key, value);
40
+ }
41
+ }
42
+ return unmapQueryString(currentKeyValues);
43
+ }
44
+ /**
45
+ * @returns The current query string as a Map
46
+ */
47
+ static _currentQsKeyValues() {
48
+ return mapQueryString(window.location.search);
49
+ }
50
+ static _makeUpdatedState(message, messageKey) {
51
+ let messages = {};
52
+ const currentState = window.history.state;
53
+ if (CfgIOManager.isIOContainer(currentState)) {
54
+ messages = currentState.messages;
55
+ }
56
+ messages[messageKey] = message;
57
+ return CfgIOManager.makeContainer(messages);
58
+ }
59
+ getDataFromEvent(event) {
60
+ return event.state;
61
+ }
62
+ }
@@ -0,0 +1,10 @@
1
+ import { CfgHistoryManager, CfgHistoryManagerSendData } from "./CfgHistoryManager.js";
2
+ import { CfgIOProdConfConnector, CfgProdConfMessage } from "./CfgIOProdConfConnector.js";
3
+ export declare const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
4
+ export declare class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector<"popstate", CfgHistoryManagerSendData<CfgProdConfMessage>, CfgHistoryManager<CfgProdConfMessage>> {
5
+ private readonly _qsKey;
6
+ constructor(manager: CfgHistoryManager<CfgProdConfMessage>, _qsKey?: string, doValidate?: boolean);
7
+ protected getInitialProdConf(): string | undefined;
8
+ protected makeSendData(prodConfAsString: string, initial: boolean): CfgHistoryManagerSendData<CfgProdConfMessage>;
9
+ }
10
+ //# sourceMappingURL=CfgHistoryToProdConfConnector.d.ts.map