@configura/web-api 2.0.0-alpha.9 → 2.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -14
- package/dist/CatalogueAPI.d.ts +103 -32
- package/dist/CatalogueAPI.js +62 -6
- package/dist/CfgProduct.d.ts +90 -14
- package/dist/CfgProduct.js +266 -56
- package/dist/CfgReferencePathHelper.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/io/CfgHistoryManager.d.ts +33 -1
- package/dist/io/CfgHistoryManager.js +68 -6
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +11 -10
- package/dist/io/CfgHistoryToProdConfConnector.js +32 -38
- package/dist/io/CfgIOManager.d.ts +5 -0
- package/dist/io/CfgIOManager.js +20 -1
- package/dist/io/CfgIOProdConfConnector.d.ts +17 -18
- package/dist/io/CfgIOProdConfConnector.js +52 -58
- package/dist/io/CfgIOWarningSupplier.d.ts +4 -0
- package/dist/io/CfgIOWarningSupplier.js +1 -0
- package/dist/io/CfgObservableStateToProdConfConnector.d.ts +4 -4
- package/dist/io/CfgObservableStateToProdConfConnector.js +3 -3
- package/dist/io/CfgWindowMessageManager.js +4 -0
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +4 -4
- package/dist/io/CfgWindowMessageToProdConfConnector.js +3 -3
- package/dist/productConfiguration/CfgFeature.d.ts +12 -7
- package/dist/productConfiguration/CfgFeature.js +33 -14
- package/dist/productConfiguration/CfgOption.d.ts +16 -10
- package/dist/productConfiguration/CfgOption.js +46 -18
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +27 -16
- package/dist/productConfiguration/CfgProductConfiguration.js +53 -29
- package/dist/productConfiguration/filters.d.ts +6 -4
- package/dist/productConfiguration/filters.js +94 -23
- package/dist/productConfiguration/productParamsGenerator.d.ts +3 -3
- package/dist/productConfiguration/utilitiesProductConfiguration.d.ts +1 -1
- package/dist/productConfiguration/utilitiesProductConfiguration.js +11 -4
- package/dist/productLoader.d.ts +3 -3
- package/dist/productLoader.js +1 -1
- package/dist/syncGroups/SyncGroupsHandler.d.ts +9 -2
- package/dist/syncGroups/SyncGroupsHandler.js +15 -4
- package/dist/syncGroups/SyncGroupsState.d.ts +5 -1
- package/dist/syncGroups/SyncGroupsState.js +44 -2
- package/dist/syncGroups/SyncGroupsTransaction.js +34 -21
- package/dist/tasks/TaskHandler.d.ts +2 -2
- package/dist/tasks/TaskHandler.js +2 -1
- package/dist/tests/testData/dummyProductForTest.d.ts +2 -2
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +14 -9
- package/dist/tests/testData/testDataCachedGetProduct.js +2 -0
- package/dist/tests/testData/testDataCachedPostValidate.js +2 -0
- package/dist/tests/testData/testDataProductAggregatedPrice.js +3 -1
- package/dist/tests/testData/testDataUpcharge.js +2 -0
- package/dist/utilitiesCatalogueData.d.ts +14 -9
- package/dist/utilitiesCatalogueData.js +7 -0
- package/dist/utilitiesCataloguePermission.d.ts +4 -4
- package/dist/utilitiesConfiguration.d.ts +29 -0
- package/dist/utilitiesConfiguration.js +200 -0
- package/dist/utilitiesNumericValues.js +13 -8
- package/package.json +3 -3
- package/dist/ConfigurationConverter.d.ts +0 -5
- package/dist/ConfigurationConverter.js +0 -72
package/dist/CfgProduct.js
CHANGED
|
@@ -9,13 +9,13 @@ 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 { convertDtoConfProdToV1 } from "./ConfigurationConverter.js";
|
|
13
12
|
import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
|
|
14
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 {
|
|
17
|
+
import { compareCfgProductData, correctDefaultsOnCatalogueParams, isSameCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
|
|
18
|
+
import { CfgProdConfParts, convertDtoProductConfToV1, isAdditionalProductConfiguration, isProductConf, } from "./utilitiesConfiguration.js";
|
|
19
19
|
function completeSettings(incompleteSettings) {
|
|
20
20
|
var _a;
|
|
21
21
|
return {
|
|
@@ -52,7 +52,7 @@ function isDescriptionMatch(l, r) {
|
|
|
52
52
|
* the class that should be used and interacted with.
|
|
53
53
|
*/
|
|
54
54
|
export class _CfgProductInternal {
|
|
55
|
-
constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs,
|
|
55
|
+
constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, notes, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
|
|
56
56
|
var _a;
|
|
57
57
|
this._productLoaderRaw = _productLoaderRaw;
|
|
58
58
|
this.prodParams = prodParams;
|
|
@@ -66,15 +66,26 @@ export class _CfgProductInternal {
|
|
|
66
66
|
this._syncGroupHandler = _syncGroupHandler;
|
|
67
67
|
this._destroyed = false;
|
|
68
68
|
this.additionalProducts = [];
|
|
69
|
+
this._notes = new Map();
|
|
69
70
|
this.changeObservable = new Observable();
|
|
71
|
+
/** Mark this and its descendants as destroyed and remove all listeners */
|
|
70
72
|
this.destroy = () => {
|
|
73
|
+
var _a;
|
|
71
74
|
this._destroyed = true;
|
|
72
75
|
this.changeObservable.stopAllListen();
|
|
73
76
|
this.configuration.stopAllListenForChange();
|
|
74
|
-
for (const additionalProduct of this.additionalProducts
|
|
77
|
+
for (const additionalProduct of (_a = this.additionalProducts) !== null && _a !== void 0 ? _a : []) {
|
|
75
78
|
additionalProduct.destroy();
|
|
76
79
|
}
|
|
77
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* Reset will reset the product to its initial state
|
|
83
|
+
*/
|
|
84
|
+
this.reset = () => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
if (this._initialClone !== undefined) {
|
|
86
|
+
yield this.copyFrom(this._initialClone, true);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
78
89
|
this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
79
90
|
if (bubbleMode === CfgProductBubbleMode.Stop) {
|
|
80
91
|
return;
|
|
@@ -93,7 +104,7 @@ export class _CfgProductInternal {
|
|
|
93
104
|
if (bubbleMode === CfgProductBubbleMode.ToRootAndBubbleSelected &&
|
|
94
105
|
this.optional &&
|
|
95
106
|
!this.selected) {
|
|
96
|
-
yield this.setSelected(true, bubbleMode);
|
|
107
|
+
yield this.setSelected(true, bubbleMode, false);
|
|
97
108
|
return;
|
|
98
109
|
}
|
|
99
110
|
yield this._notifyAllOfChange(bubbleMode, committed);
|
|
@@ -140,18 +151,26 @@ export class _CfgProductInternal {
|
|
|
140
151
|
return;
|
|
141
152
|
}
|
|
142
153
|
});
|
|
143
|
-
this.getDtoConf = (
|
|
154
|
+
this.getDtoConf = (include) => {
|
|
155
|
+
var _a;
|
|
144
156
|
const conf = {};
|
|
145
|
-
const features = this.configuration._internal.getDtoConf(
|
|
157
|
+
const features = this.configuration._internal.getDtoConf((include & CfgProdConfParts.ExtendedData) === CfgProdConfParts.ExtendedData);
|
|
146
158
|
if (0 < features.length) {
|
|
147
159
|
conf.features = features;
|
|
148
160
|
}
|
|
149
|
-
if (
|
|
161
|
+
if ((include & CfgProdConfParts.ProdParams) === CfgProdConfParts.ProdParams) {
|
|
150
162
|
conf.prodParams = this.prodParams;
|
|
151
163
|
}
|
|
164
|
+
// Only store the syncGroupState for the root product. The same state
|
|
165
|
+
// is used for the entire product, including the additional product,
|
|
166
|
+
// so no need to store it for additional products.
|
|
167
|
+
if ((include & CfgProdConfParts.SyncGroupState) === CfgProdConfParts.SyncGroupState &&
|
|
168
|
+
this.parent === undefined) {
|
|
169
|
+
conf.syncGroupState = (_a = this.syncGroupHandler) === null || _a === void 0 ? void 0 : _a.getCompactSyncGroupState();
|
|
170
|
+
}
|
|
152
171
|
const additionalProducts = this.additionalProducts;
|
|
153
172
|
if (0 < additionalProducts.length) {
|
|
154
|
-
conf.additionalProducts = additionalProducts.map((p) => p._internal.getDtoConf(
|
|
173
|
+
conf.additionalProducts = additionalProducts.map((p) => p._internal.getDtoConf(include));
|
|
155
174
|
}
|
|
156
175
|
if (this.isAdditionalProduct) {
|
|
157
176
|
const refKey = this.refKey;
|
|
@@ -165,15 +184,25 @@ export class _CfgProductInternal {
|
|
|
165
184
|
return conf;
|
|
166
185
|
};
|
|
167
186
|
this.setDtoConf = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
|
|
168
|
-
|
|
187
|
+
// The DtoProdConf format can contain a sync group state, but
|
|
188
|
+
// not the DtoAdditionalProductConfiguration format. So we apply
|
|
189
|
+
// any passed state here.
|
|
190
|
+
if (this.root === this) {
|
|
191
|
+
const syncGroupHandler = this.syncGroupHandler;
|
|
192
|
+
const newSyncGroupState = s.syncGroupState;
|
|
193
|
+
if (syncGroupHandler !== undefined && newSyncGroupState !== undefined) {
|
|
194
|
+
syncGroupHandler.setCompactSyncGroupState(newSyncGroupState);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return yield this.setApiSelection(convertDtoProductConfToV1(s), doValidate, productLoaderForGroupedLoad);
|
|
169
198
|
});
|
|
170
199
|
this.setApiSelection = (s, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
|
|
171
200
|
return yield this._setApiSelectionWithOtherProduct(s, doValidate, productLoaderForGroupedLoad, undefined);
|
|
172
201
|
});
|
|
173
202
|
this.copyFrom = (source, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
return yield this._setApiSelectionWithOtherProduct(
|
|
203
|
+
return yield this._setApiSelectionWithOtherProduct(convertDtoProductConfToV1(source.getDtoConf(CfgProdConfParts.NoExtra)), doValidate, productLoaderForGroupedLoad, source);
|
|
175
204
|
});
|
|
176
|
-
this._setApiSelectionWithOtherProduct = (
|
|
205
|
+
this._setApiSelectionWithOtherProduct = (productConfiguration, doValidate, productLoaderForGroupedLoad, sourceProduct) => __awaiter(this, void 0, void 0, function* () {
|
|
177
206
|
// Wrap with cache will make getProduct for this function call use the same server call
|
|
178
207
|
// for the same product with the same params. Used for getProduct (when a new additional
|
|
179
208
|
// product is loaded) and postValidate.
|
|
@@ -181,21 +210,42 @@ export class _CfgProductInternal {
|
|
|
181
210
|
productLoaderForGroupedLoad || wrapWithCache(this._productLoaderRaw);
|
|
182
211
|
let change = false;
|
|
183
212
|
if (sourceProduct !== undefined) {
|
|
184
|
-
this._rawProductData
|
|
185
|
-
|
|
186
|
-
|
|
213
|
+
if (!compareCfgProductData(this._rawProductData, sourceProduct.rawProductData)) {
|
|
214
|
+
this._rawProductData = sourceProduct.rawProductData;
|
|
215
|
+
change = true;
|
|
216
|
+
}
|
|
217
|
+
if (this.configuration._internal.addRawFeatures(sourceProduct.configuration.rawFeatures, false)) {
|
|
218
|
+
change = true;
|
|
219
|
+
}
|
|
220
|
+
if (this.configuration._internal.populateFeatures(sourceProduct.configuration.rootFeatureRefs)) {
|
|
221
|
+
change = true;
|
|
222
|
+
}
|
|
223
|
+
const targetNotes = this._notes;
|
|
224
|
+
const sourceNotes = sourceProduct._notes;
|
|
225
|
+
for (const targetKey of targetNotes.keys()) {
|
|
226
|
+
if (!sourceNotes.has(targetKey)) {
|
|
227
|
+
targetNotes.delete(targetKey);
|
|
228
|
+
change = true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
for (const [sourceKey, sourceNote] of sourceNotes) {
|
|
232
|
+
if (!targetNotes.has(sourceKey)) {
|
|
233
|
+
targetNotes.set(sourceKey, sourceNote);
|
|
234
|
+
change = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
187
237
|
}
|
|
188
|
-
const configurationChange = yield this.configuration._internal.setApiSelection(
|
|
238
|
+
const configurationChange = yield this.configuration._internal.setApiSelection(productConfiguration.selOptions, false);
|
|
189
239
|
if (configurationChange) {
|
|
190
240
|
change = true;
|
|
191
241
|
}
|
|
192
242
|
if (this.optional) {
|
|
193
|
-
if (yield this.setSelected(
|
|
243
|
+
if (yield this.setSelected(productConfiguration.selected !== false, CfgProductBubbleMode.Stop, false)) {
|
|
194
244
|
change = true;
|
|
195
245
|
}
|
|
196
246
|
}
|
|
197
|
-
yield this._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
|
|
198
|
-
const apiSelectionAdditionalProducts =
|
|
247
|
+
yield this._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad, productConfiguration);
|
|
248
|
+
const apiSelectionAdditionalProducts = productConfiguration.additionalProducts || [];
|
|
199
249
|
const additionalProducts = this.additionalProducts.slice();
|
|
200
250
|
const additionalProductsCount = additionalProducts.length;
|
|
201
251
|
const apiSelectionAdditionalProductsCount = apiSelectionAdditionalProducts.length;
|
|
@@ -248,7 +298,7 @@ export class _CfgProductInternal {
|
|
|
248
298
|
productLoaderForGroupedLoad || wrapWithCache(this._productLoaderRaw);
|
|
249
299
|
let change = false;
|
|
250
300
|
if (this.optional && other.optional) {
|
|
251
|
-
if (yield this.setSelected(other.selected, CfgProductBubbleMode.Stop)) {
|
|
301
|
+
if (yield this.setSelected(other.selected, CfgProductBubbleMode.Stop, false)) {
|
|
252
302
|
change = true;
|
|
253
303
|
}
|
|
254
304
|
}
|
|
@@ -312,7 +362,10 @@ export class _CfgProductInternal {
|
|
|
312
362
|
const token = this.loadingObservable.startChildLoading();
|
|
313
363
|
this._revalidateInProgressToken = token;
|
|
314
364
|
try {
|
|
315
|
-
const response = yield productLoader.postValidate(correctDefaultsOnCatalogueParams(this.prodParams), {
|
|
365
|
+
const response = yield productLoader.postValidate(correctDefaultsOnCatalogueParams(this.prodParams), {
|
|
366
|
+
selOptions: configuration._internal.getApiSelection(),
|
|
367
|
+
knownFeatureCodes: configuration.rawFeatures.map((f) => f.code),
|
|
368
|
+
});
|
|
316
369
|
// The revalidateInProgressToken is used to know if some other revalidate
|
|
317
370
|
// call has happened after this call, thereby making this call obsolete.
|
|
318
371
|
// This is a bit crude in that it does not actually cancel previous validate
|
|
@@ -331,18 +384,17 @@ export class _CfgProductInternal {
|
|
|
331
384
|
if (this._destroyed) {
|
|
332
385
|
return false;
|
|
333
386
|
}
|
|
334
|
-
const { productData, rootFeatureRefs } = response;
|
|
335
|
-
|
|
387
|
+
const { productData, rootFeatureRefs, features, notes } = response;
|
|
388
|
+
if (notes !== undefined) {
|
|
389
|
+
this.addNotes(notes.values());
|
|
390
|
+
}
|
|
336
391
|
this._rawProductData = productData;
|
|
392
|
+
configuration._internal.addRawFeatures(features, true);
|
|
337
393
|
if (rootFeatureRefs !== undefined) {
|
|
338
394
|
configuration._internal.populateFeatures(rootFeatureRefs);
|
|
339
395
|
}
|
|
340
|
-
if (pricesUpdated) {
|
|
341
|
-
this._configuration._internal._freshRefDescendants();
|
|
342
|
-
this._configuration = CfgProductConfiguration._makeNewRefFrom(this._configuration._internal);
|
|
343
|
-
}
|
|
344
396
|
yield configuration._internal.setApiSelection(productData.partsData.selOptions || [], false);
|
|
345
|
-
yield this._syncAndLoadAdditionalProducts(productLoader);
|
|
397
|
+
yield this._syncAndLoadAdditionalProducts(productLoader, undefined);
|
|
346
398
|
if (this._destroyed) {
|
|
347
399
|
return false;
|
|
348
400
|
}
|
|
@@ -350,7 +402,7 @@ export class _CfgProductInternal {
|
|
|
350
402
|
return true;
|
|
351
403
|
}
|
|
352
404
|
catch (e) {
|
|
353
|
-
throw augmentErrorMessage(e,
|
|
405
|
+
throw augmentErrorMessage(e, `Validate product configuration request (${this.prodParams.partNumber}) failure`);
|
|
354
406
|
}
|
|
355
407
|
finally {
|
|
356
408
|
this.loadingObservable.stopChildLoading(token);
|
|
@@ -360,7 +412,7 @@ export class _CfgProductInternal {
|
|
|
360
412
|
* Based on this configuration find what additional products should be shown and not, unload
|
|
361
413
|
* (i.e. destroy) those that should no longer be shown, load the new ones.
|
|
362
414
|
*/
|
|
363
|
-
this._syncAndLoadAdditionalProducts = (productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
|
|
415
|
+
this._syncAndLoadAdditionalProducts = (productLoaderForGroupedLoad, initialProductConfiguration) => __awaiter(this, void 0, void 0, function* () {
|
|
364
416
|
const { _productLoaderRaw: productLoaderRaw, rawProductData: productData, configuration, additionalProducts: currentAdditionalProducts, } = this;
|
|
365
417
|
const additionalProductRefs = [
|
|
366
418
|
...(productData.additionalProductRefs || []),
|
|
@@ -402,10 +454,17 @@ export class _CfgProductInternal {
|
|
|
402
454
|
change = true;
|
|
403
455
|
}
|
|
404
456
|
const newAdditionalProducts = yield Promise.all(additionalProductRefs.map((p) => (() => __awaiter(this, void 0, void 0, function* () {
|
|
457
|
+
var _c;
|
|
405
458
|
const additionalProductRef = p.prodRef;
|
|
459
|
+
const refKey = additionalProductRef.refKey;
|
|
460
|
+
const additionalProductInitialProductConfiguration = (_c = initialProductConfiguration === null || initialProductConfiguration === void 0 ? void 0 : initialProductConfiguration.additionalProducts) === null || _c === void 0 ? void 0 : _c.find((aP) => refKey === aP.refKey);
|
|
461
|
+
if (initialProductConfiguration !== undefined &&
|
|
462
|
+
additionalProductInitialProductConfiguration === undefined) {
|
|
463
|
+
console.warn(`Did not find initial product configuration for additional product with refKey ${refKey}`);
|
|
464
|
+
}
|
|
406
465
|
return {
|
|
407
466
|
originalIndex: p.originalIndex,
|
|
408
|
-
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)),
|
|
467
|
+
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)),
|
|
409
468
|
};
|
|
410
469
|
}))()));
|
|
411
470
|
if (this._destroyed) {
|
|
@@ -423,19 +482,28 @@ export class _CfgProductInternal {
|
|
|
423
482
|
this.root = root !== null && root !== void 0 ? root : this;
|
|
424
483
|
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 }));
|
|
425
484
|
this._selected = optional ? selected : undefined;
|
|
426
|
-
this.isAdditionalProduct =
|
|
427
|
-
|
|
485
|
+
this.isAdditionalProduct = _additionalProductRef !== undefined;
|
|
486
|
+
if (notes !== undefined) {
|
|
487
|
+
this.addNotes(notes);
|
|
488
|
+
}
|
|
489
|
+
this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, rawFeatures, apiSelection, this, this.root);
|
|
428
490
|
}
|
|
429
491
|
get selected() {
|
|
430
492
|
return this._selected !== false;
|
|
431
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Please note that cloning an additional product will make the clone believe is is
|
|
496
|
+
* an additional product, even if it has no parent and root.
|
|
497
|
+
* Providing the parent and root of what you clone as arguments is unwise as it will
|
|
498
|
+
* make changes you do on the clone be propagated up to the original non-clone root product.
|
|
499
|
+
*/
|
|
432
500
|
clone(parent, root) {
|
|
433
501
|
return __awaiter(this, void 0, void 0, function* () {
|
|
434
502
|
const product = yield new Promise((initSuccess, initFail) => {
|
|
435
503
|
var _a;
|
|
436
504
|
const p = new _CfgProductInternal(() => {
|
|
437
505
|
initSuccess(p);
|
|
438
|
-
}, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.
|
|
506
|
+
}, 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());
|
|
439
507
|
});
|
|
440
508
|
for (const additionalProduct of this.additionalProducts) {
|
|
441
509
|
product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
|
|
@@ -443,12 +511,56 @@ export class _CfgProductInternal {
|
|
|
443
511
|
return product;
|
|
444
512
|
});
|
|
445
513
|
}
|
|
514
|
+
/**
|
|
515
|
+
* Internal use. Used when this product is an additional product, and
|
|
516
|
+
* changing a parent product has made the settings for this product
|
|
517
|
+
* change.
|
|
518
|
+
*/
|
|
446
519
|
_updateAdditionalProdRef(p) {
|
|
447
520
|
this._additionalProductRef = p;
|
|
448
521
|
if (p.optional !== this.optional) {
|
|
449
522
|
this._selected = p.optional ? false : undefined;
|
|
450
523
|
}
|
|
451
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Return a DtoNode using noteRef as a key.
|
|
527
|
+
* Throws an error if no note is found.
|
|
528
|
+
*/
|
|
529
|
+
getNote(noteRef) {
|
|
530
|
+
const note = this._notes.get(noteRef);
|
|
531
|
+
if (note === undefined) {
|
|
532
|
+
throw new Error(`Note with noteRef ${noteRef} not found.`);
|
|
533
|
+
}
|
|
534
|
+
return note;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* noteRefs is a list of keys coming from CfgOption, CfgFeature or CfgProduct.
|
|
538
|
+
* The keys are used to get a DtoNote[] from notes at CfgProduct.
|
|
539
|
+
*/
|
|
540
|
+
getNotes(noteRefs) {
|
|
541
|
+
return noteRefs.map((noteRef) => this.getNote(noteRef));
|
|
542
|
+
}
|
|
543
|
+
addNotes(notes) {
|
|
544
|
+
for (const note of notes) {
|
|
545
|
+
const code = note.code;
|
|
546
|
+
if (!code) {
|
|
547
|
+
throw new Error("Note with no code");
|
|
548
|
+
}
|
|
549
|
+
this._notes.set(code, note);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
get notes() {
|
|
553
|
+
var _a;
|
|
554
|
+
return this.getNotes((_a = this.rawProductData.noteRefs) !== null && _a !== void 0 ? _a : []);
|
|
555
|
+
}
|
|
556
|
+
get miscFiles() {
|
|
557
|
+
var _a;
|
|
558
|
+
return (_a = this._rawProductData.miscFiles) !== null && _a !== void 0 ? _a : [];
|
|
559
|
+
}
|
|
560
|
+
get hasRootFeaturesChanged() {
|
|
561
|
+
return (this._configuration._internal.hasRootFeaturesChanged ||
|
|
562
|
+
this.additionalProducts.some((p) => p._internal.hasRootFeaturesChanged));
|
|
563
|
+
}
|
|
452
564
|
get description() {
|
|
453
565
|
var _a, _b;
|
|
454
566
|
return (_b = (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.refDescription) !== null && _b !== void 0 ? _b : this._rawProductData.description;
|
|
@@ -523,16 +635,31 @@ export class _CfgProductInternal {
|
|
|
523
635
|
get optional() {
|
|
524
636
|
return this._selected !== undefined;
|
|
525
637
|
}
|
|
526
|
-
setSelected(
|
|
638
|
+
setSelected(selected, bubbleMode, interactive) {
|
|
527
639
|
return __awaiter(this, void 0, void 0, function* () {
|
|
528
640
|
if (!this.optional) {
|
|
529
641
|
console.warn("This product is not optional. Nothing will happen");
|
|
530
642
|
return false;
|
|
531
643
|
}
|
|
532
|
-
if (this._selected ===
|
|
644
|
+
if (this._selected === selected) {
|
|
533
645
|
return false;
|
|
534
646
|
}
|
|
535
|
-
this
|
|
647
|
+
// Vitally important that this happens before the call to reset,
|
|
648
|
+
// so that the reset won't cause infinite loops
|
|
649
|
+
this._selected = selected;
|
|
650
|
+
if (interactive) {
|
|
651
|
+
if (selected) {
|
|
652
|
+
const syncGroupHandler = this.syncGroupHandler;
|
|
653
|
+
if (syncGroupHandler !== undefined) {
|
|
654
|
+
yield syncGroupHandler.init(this.root, wrapWithCache(this._productLoaderRaw));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
yield this.reset();
|
|
659
|
+
// In case a passed initial configuration has made it reset to selected
|
|
660
|
+
this._selected = selected;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
536
663
|
yield this._notifyAllOfChange(bubbleMode, true);
|
|
537
664
|
return true;
|
|
538
665
|
});
|
|
@@ -585,33 +712,66 @@ export class _CfgProductInternal {
|
|
|
585
712
|
}
|
|
586
713
|
}
|
|
587
714
|
_CfgProductInternal.make = (productLoaderRaw, productLoaderForGroupedLoad, // Used when instantiating the current product
|
|
588
|
-
prodParams, settings, optional, loadingObservable, parent, root, additionalProductRef) => __awaiter(void 0, void 0, void 0, function* () {
|
|
715
|
+
prodParams, settings, optional, loadingObservable, parent, root, additionalProductRef, initialProductConfiguration) => __awaiter(void 0, void 0, void 0, function* () {
|
|
589
716
|
// Wrap with cache will make getProduct for this function call use the same server call
|
|
590
717
|
// for the same product with the same params. Not retained for future calls, only used
|
|
591
718
|
// at this initial load.
|
|
592
719
|
productLoaderForGroupedLoad =
|
|
593
720
|
productLoaderForGroupedLoad || wrapWithCache(productLoaderRaw);
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
721
|
+
let syncGroupHandler = undefined;
|
|
722
|
+
// No root means we are root. We only create SyncGroupsHandler if this is the root product
|
|
723
|
+
if (root === undefined) {
|
|
724
|
+
let initialSyncGroupsState = undefined;
|
|
725
|
+
// DtoProductConf supports containing the sync group state, but the old
|
|
726
|
+
// DtoAdditionalProductConfiguration does not
|
|
727
|
+
if (initialProductConfiguration !== undefined &&
|
|
728
|
+
isProductConf(initialProductConfiguration)) {
|
|
729
|
+
initialSyncGroupsState = initialProductConfiguration.syncGroupState;
|
|
730
|
+
}
|
|
731
|
+
syncGroupHandler = SyncGroupsHandler.make(settings.syncGroupsApplyMode, loadingObservable, initialSyncGroupsState);
|
|
732
|
+
}
|
|
597
733
|
try {
|
|
598
|
-
const
|
|
599
|
-
|
|
734
|
+
const defaultCorrectedProdParams = correctDefaultsOnCatalogueParams(prodParams);
|
|
735
|
+
let initialProductConfigurationV1 = undefined;
|
|
736
|
+
if (initialProductConfiguration !== undefined) {
|
|
737
|
+
if (isProductConf(initialProductConfiguration)) {
|
|
738
|
+
initialProductConfigurationV1 = convertDtoProductConfToV1(initialProductConfiguration);
|
|
739
|
+
}
|
|
740
|
+
else if (isAdditionalProductConfiguration(initialProductConfiguration)) {
|
|
741
|
+
initialProductConfigurationV1 = initialProductConfiguration;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
const productResponse = yield (initialProductConfigurationV1
|
|
745
|
+
? productLoaderForGroupedLoad.postValidate(defaultCorrectedProdParams, {
|
|
746
|
+
knownFeatureCodes: [],
|
|
747
|
+
selOptions: initialProductConfigurationV1.selOptions,
|
|
748
|
+
})
|
|
749
|
+
: productLoaderForGroupedLoad.getProduct(defaultCorrectedProdParams));
|
|
750
|
+
const { productData, rootFeatureRefs, features: rawFeatures, notes, uuid, unit, } = productResponse;
|
|
751
|
+
const initiallySelected = !optional || (initialProductConfigurationV1 === null || initialProductConfigurationV1 === void 0 ? void 0 : initialProductConfigurationV1.selected) === true;
|
|
600
752
|
const product = yield new Promise((initSuccess, initFail) => {
|
|
753
|
+
var _a;
|
|
601
754
|
const p = new _CfgProductInternal(() => {
|
|
602
755
|
// We absolutely do not want anyone to assign to this._configuration. So we want that field private.
|
|
603
756
|
// But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
|
|
604
757
|
// Feel free to find a nicer more readable solution :)
|
|
605
758
|
initSuccess(p);
|
|
606
|
-
}, initFail, productLoaderRaw, prodParams, settings, optional,
|
|
759
|
+
}, 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);
|
|
607
760
|
});
|
|
608
|
-
yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
|
|
609
|
-
|
|
610
|
-
|
|
761
|
+
yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad, initialProductConfigurationV1);
|
|
762
|
+
product._initialClone = yield product.clone();
|
|
763
|
+
if (syncGroupHandler !== undefined && !initialProductConfiguration) {
|
|
764
|
+
// As syncGroupHandler is only set for root product we know that we will init with root.
|
|
765
|
+
// If we have an initialProductConfiguration we do not run init for the syncGroups.
|
|
766
|
+
// The idea with an initial configuration is that the product should look as it did when
|
|
767
|
+
// the configuration was saved. Not running init does that. Also, the DtoProductConf
|
|
768
|
+
// object can contain a sync state which is then used to populate the sync state.
|
|
769
|
+
yield syncGroupHandler.init(product, productLoaderForGroupedLoad);
|
|
770
|
+
}
|
|
611
771
|
return product;
|
|
612
772
|
}
|
|
613
773
|
catch (e) {
|
|
614
|
-
throw augmentErrorMessage(e,
|
|
774
|
+
throw augmentErrorMessage(e, `Load product request (${prodParams.partNumber}) failure`);
|
|
615
775
|
}
|
|
616
776
|
});
|
|
617
777
|
export class CfgProduct {
|
|
@@ -630,7 +790,7 @@ export class CfgProduct {
|
|
|
630
790
|
* Setting this does not cause a validation call as toggling an optional additional product is
|
|
631
791
|
* assumed to always be legal.
|
|
632
792
|
*/
|
|
633
|
-
this.setSelected = (v) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setSelected(v, CfgProductBubbleMode.ToRootAndBubbleSelected); });
|
|
793
|
+
this.setSelected = (v) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setSelected(v, CfgProductBubbleMode.ToRootAndBubbleSelected, true); });
|
|
634
794
|
/**
|
|
635
795
|
* Experimental. Additional products lacks descriptions or keys that are suitably for structure
|
|
636
796
|
* compare, so we use strict-order when trying to match the additional products. This makes
|
|
@@ -650,11 +810,40 @@ export class CfgProduct {
|
|
|
650
810
|
* Gets what selections has been made on the product, recursively including product
|
|
651
811
|
* configuration, optional products and additional products. Used when a full view of all
|
|
652
812
|
* selections on a product is needed, such as when doing Render or Export.
|
|
813
|
+
* @deprecated getDtoConf provides a newer format.
|
|
814
|
+
* @see getDtoConf
|
|
815
|
+
*/
|
|
816
|
+
this.getApiSelection = () => convertDtoProductConfToV1(this._internal.getDtoConf(CfgProdConfParts.NoExtra), true);
|
|
817
|
+
/**
|
|
818
|
+
* Applies the configuration (selections) in the passed object onto the product recursively
|
|
819
|
+
* including product configuration, optional products and additional products.
|
|
820
|
+
* @param doValidate Makes a server side validation call. These are necessary to ensure that
|
|
821
|
+
* the right models are loaded.
|
|
822
|
+
* @deprecated setDtoConf uses a newer format.
|
|
823
|
+
*/
|
|
824
|
+
this.setApiSelection = (configuration, doValidate = true) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setApiSelection(configuration, doValidate); });
|
|
825
|
+
/**
|
|
826
|
+
* A newer alternative version of getApiSelection. This returns the configuration (selections)
|
|
827
|
+
* on the product, recursively including product configuration, optional products and additional
|
|
828
|
+
* products.
|
|
829
|
+
* This version has the following advantages over getApiSelection:
|
|
830
|
+
* - The format is clearer, designed to be readable
|
|
831
|
+
* - Makes less assumptions about the structure in the Product being unchanging over time. In
|
|
832
|
+
* particular, the Feature codes are included in the data, so that changes to what Features
|
|
833
|
+
* are used in a Product is less likely to lead to unexpected results.
|
|
834
|
+
* - You can request ExtendedData, ProductParams and/or SyncGroupState to be included in the
|
|
835
|
+
* result. This extra data is ignored when passed back into the API, but it can be very useful
|
|
836
|
+
* for external applications.
|
|
837
|
+
* The other version (getApiSelection) has the advantage of using a format directly compatible with the API:s.
|
|
838
|
+
* @param include Includes extra data which is not an actual part of the configuration
|
|
653
839
|
*/
|
|
654
|
-
this.
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
840
|
+
this.getDtoConf = (include = CfgProdConfParts.NoExtra) => this._internal.getDtoConf(include);
|
|
841
|
+
/**
|
|
842
|
+
* A newer alternative version of setApiSelection.
|
|
843
|
+
* @param doValidate Makes a server side validation call. These are necessary to ensure that
|
|
844
|
+
* the right models are loaded.
|
|
845
|
+
*/
|
|
846
|
+
this.setDtoConf = (configuration, doValidate = true) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setDtoConf(configuration, doValidate); });
|
|
658
847
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
659
848
|
this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
|
|
660
849
|
this.stopAllListenForChange = () => this._internal.changeObservable.stopAllListen();
|
|
@@ -662,9 +851,9 @@ export class CfgProduct {
|
|
|
662
851
|
this.stopListenForLoading = (l) => this._internal.loadingObservable.stopListen(l);
|
|
663
852
|
this.stopAllListenForLoading = () => this._internal.loadingObservable.stopAllListen();
|
|
664
853
|
}
|
|
665
|
-
static make(productLoader, prodParams, settings) {
|
|
854
|
+
static make(productLoader, prodParams, settings, initialProductConfiguration) {
|
|
666
855
|
return __awaiter(this, void 0, void 0, function* () {
|
|
667
|
-
return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, prodParams, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined));
|
|
856
|
+
return this._makeNewRefFrom(yield _CfgProductInternal.make(productLoader, undefined, prodParams, completeSettings(settings), false, new AggregatedLoadingObservable(), undefined, undefined, undefined, initialProductConfiguration));
|
|
668
857
|
});
|
|
669
858
|
}
|
|
670
859
|
/**
|
|
@@ -690,6 +879,12 @@ export class CfgProduct {
|
|
|
690
879
|
get refKey() {
|
|
691
880
|
return this._internal.refKey;
|
|
692
881
|
}
|
|
882
|
+
get notes() {
|
|
883
|
+
return this._internal.notes;
|
|
884
|
+
}
|
|
885
|
+
get miscFiles() {
|
|
886
|
+
return this._internal.miscFiles;
|
|
887
|
+
}
|
|
693
888
|
get prodParams() {
|
|
694
889
|
return this._internal.prodParams;
|
|
695
890
|
}
|
|
@@ -727,12 +922,27 @@ export class CfgProduct {
|
|
|
727
922
|
/**
|
|
728
923
|
* Please note that this relates to the visibility in the Configuration tree.
|
|
729
924
|
* It does not affect the visibility of anything in the 3D view at all.
|
|
730
|
-
* Visibility
|
|
925
|
+
* Visibility affects the Configuration for this Product, but any Additional Products
|
|
731
926
|
* will not be affected.
|
|
732
927
|
*/
|
|
733
928
|
get visible() {
|
|
734
929
|
return this._internal.visible;
|
|
735
930
|
}
|
|
931
|
+
// A similar text to the one below exists in global-message-managers.md and should be kept in sync.
|
|
932
|
+
/**
|
|
933
|
+
* Functional selection is a Catalogues feature where selecting Options on Features result in that you
|
|
934
|
+
* "jump" to another Product as a result of the Validate call. You normally do not notice that a functional
|
|
935
|
+
* selection has occurred except for the styleNr changing. Functional selection can change which Features
|
|
936
|
+
* from the original product call are used as root Features. This can in turn affect if serialized
|
|
937
|
+
* configuration can be applied or not.
|
|
938
|
+
*
|
|
939
|
+
* The SDK can currently only apply serialized configuration if the list of root Features has not changed.
|
|
940
|
+
* For this reason, when functional selection has happened, extracting data for external systems might work
|
|
941
|
+
* well, but reapplying back into Stage will probably fail.
|
|
942
|
+
*/
|
|
943
|
+
get hasRootFeaturesChanged() {
|
|
944
|
+
return this._internal.hasRootFeaturesChanged;
|
|
945
|
+
}
|
|
736
946
|
get rawProductData() {
|
|
737
947
|
return this._internal.rawProductData;
|
|
738
948
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DtoCatalogueParamsWithCidAndLang, DtoProductParamsWithCidAndLang } from "./CatalogueAPI";
|
|
2
2
|
/**
|
|
3
3
|
* These methods aims to provide a default suggested way of building
|
|
4
4
|
* URLs to Products and Catalogues. By using consistent URL:s copy-paste
|
|
@@ -14,7 +14,7 @@ export declare class CfgReferencePathHelper {
|
|
|
14
14
|
* @param catParams What catalogue to generate URL for.
|
|
15
15
|
* @returns An URL to a catalogue
|
|
16
16
|
*/
|
|
17
|
-
static getCataloguePath: (browsingRootUrl: string, catParams:
|
|
17
|
+
static getCataloguePath: (browsingRootUrl: string, catParams: DtoCatalogueParamsWithCidAndLang) => string;
|
|
18
18
|
/**
|
|
19
19
|
* Use to generate URLs in our reference format. This is the format Configura uses in our integrations.
|
|
20
20
|
* @param browsingRootUrl The URL where Stage browsing begins
|
|
@@ -22,6 +22,6 @@ export declare class CfgReferencePathHelper {
|
|
|
22
22
|
* @param separator Optional, defaults to "product", but can be changed to indicate another function.
|
|
23
23
|
* @returns An URL to a product
|
|
24
24
|
*/
|
|
25
|
-
static getProductPath: (browsingRootUrl: string, productParams:
|
|
25
|
+
static getProductPath: (browsingRootUrl: string, productParams: DtoProductParamsWithCidAndLang, separator?: string) => string;
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=CfgReferencePathHelper.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from "./CatalogueAPI.js";
|
|
2
2
|
export * from "./CfgProduct.js";
|
|
3
3
|
export * from "./CfgReferencePathHelper.js";
|
|
4
|
-
export * from "./ConfigurationConverter.js";
|
|
5
4
|
export * from "./io/index.js";
|
|
6
5
|
export * from "./material/CfgMaterialMapping.js";
|
|
7
6
|
export * from "./material/CfgMtrlApplication.js";
|
|
@@ -20,5 +19,6 @@ export * from "./tasks/formats.js";
|
|
|
20
19
|
export * from "./tasks/TaskHandler.js";
|
|
21
20
|
export * from "./utilitiesCatalogueData.js";
|
|
22
21
|
export * from "./utilitiesCataloguePermission.js";
|
|
22
|
+
export * from "./utilitiesConfiguration.js";
|
|
23
23
|
export * from "./utilitiesNumericValues.js";
|
|
24
24
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from "./CatalogueAPI.js";
|
|
2
2
|
export * from "./CfgProduct.js";
|
|
3
3
|
export * from "./CfgReferencePathHelper.js";
|
|
4
|
-
export * from "./ConfigurationConverter.js";
|
|
5
4
|
export * from "./io/index.js";
|
|
6
5
|
export * from "./material/CfgMaterialMapping.js";
|
|
7
6
|
export * from "./material/CfgMtrlApplication.js";
|
|
@@ -20,4 +19,5 @@ export * from "./tasks/formats.js";
|
|
|
20
19
|
export * from "./tasks/TaskHandler.js";
|
|
21
20
|
export * from "./utilitiesCatalogueData.js";
|
|
22
21
|
export * from "./utilitiesCataloguePermission.js";
|
|
22
|
+
export * from "./utilitiesConfiguration.js";
|
|
23
23
|
export * from "./utilitiesNumericValues.js";
|