@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.
- package/.eslintrc.json +1 -14
- package/dist/CatalogueAPI.d.ts +41 -0
- package/dist/CatalogueAPI.js +1 -0
- package/dist/CfgProduct.d.ts +29 -15
- package/dist/CfgProduct.js +172 -55
- package/dist/ConfigurationConverter.d.ts +4 -0
- package/dist/ConfigurationConverter.js +9 -0
- package/dist/io/CfgHistoryManager.js +0 -6
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +6 -2
- package/dist/io/CfgHistoryToProdConfConnector.js +11 -8
- package/dist/io/CfgIOProdConfConnector.d.ts +17 -9
- package/dist/io/CfgIOProdConfConnector.js +48 -57
- package/dist/io/CfgObservableStateToProdConfConnector.d.ts +2 -2
- package/dist/io/CfgObservableStateToProdConfConnector.js +3 -3
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +2 -2
- package/dist/io/CfgWindowMessageToProdConfConnector.js +3 -3
- package/dist/productConfiguration/CfgFeature.d.ts +5 -1
- package/dist/productConfiguration/CfgFeature.js +13 -0
- package/dist/productConfiguration/CfgOption.d.ts +6 -1
- package/dist/productConfiguration/CfgOption.js +17 -0
- package/dist/productLoader.js +1 -1
- package/dist/syncGroups/SyncGroupsHandler.d.ts +5 -1
- package/dist/syncGroups/SyncGroupsHandler.js +9 -2
- package/dist/syncGroups/SyncGroupsState.d.ts +5 -1
- package/dist/syncGroups/SyncGroupsState.js +44 -2
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +14 -10
- package/dist/tests/testData/testDataCachedGetProduct.js +2 -1
- package/dist/tests/testData/testDataCachedPostValidate.js +1 -0
- package/dist/tests/testData/testDataProductAggregatedPrice.js +2 -1
- package/dist/tests/testData/testDataUpcharge.js +1 -0
- package/dist/utilitiesNumericValues.js +13 -8
- package/package.json +3 -3
package/dist/CfgProduct.js
CHANGED
|
@@ -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 = (
|
|
155
|
+
this.getDtoConf = (include) => {
|
|
156
|
+
var _a;
|
|
154
157
|
const conf = {};
|
|
155
|
-
const features = this.configuration._internal.getDtoConf(
|
|
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 (
|
|
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(
|
|
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(
|
|
204
|
+
return yield this._setApiSelectionWithOtherProduct(convertDtoProductConfToV1(source.getDtoConf(CfgProdConfParts.NoExtra)), doValidate, productLoaderForGroupedLoad, source);
|
|
185
205
|
});
|
|
186
|
-
this._setApiSelectionWithOtherProduct = (
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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 ===
|
|
650
|
+
if (this._selected === selected) {
|
|
569
651
|
return false;
|
|
570
652
|
}
|
|
571
|
-
// Vitally important that this happens before the call to reset
|
|
572
|
-
//
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
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
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
|
647
|
-
|
|
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,
|
|
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(
|
|
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
|
|
727
|
-
* data is ignored when passed back into the API, but it can be very useful
|
|
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
|
|
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 = (
|
|
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
|
|
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(
|
|
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
|
|
14
|
-
super(manager,
|
|
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(
|
|
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
|
|
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>,
|
|
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)
|
|
47
|
-
static makeMessageListener(callback: ProdConfMessageCallback)
|
|
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,
|
|
54
|
-
static listenForProdConf(product: CfgProduct, callback: ProdConfCallback,
|
|
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
|