@configura/web-api 3.0.0-alpha.0 → 3.0.0-alpha.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.
- package/dist/CatalogueAPI.d.ts +68 -1
- package/dist/CatalogueAPI.js +184 -219
- package/dist/CfgMeasure.js +1 -2
- package/dist/CfgProduct.js +131 -159
- package/dist/io/CfgIOManager.js +2 -11
- package/dist/io/CfgIOProdConfConnector.js +14 -25
- package/dist/io/CfgObservableStateManager.js +1 -1
- package/dist/productConfiguration/CfgFeature.d.ts +5 -0
- package/dist/productConfiguration/CfgFeature.js +64 -54
- package/dist/productConfiguration/CfgOption.d.ts +44 -0
- package/dist/productConfiguration/CfgOption.js +107 -71
- package/dist/productConfiguration/CfgProductConfiguration.js +22 -34
- package/dist/productConfiguration/productParamsGenerator.js +43 -57
- package/dist/productLoader.js +2 -13
- package/dist/syncGroups/SyncGroupsHandler.js +60 -83
- package/dist/syncGroups/SyncGroupsPathHelper.js +5 -5
- package/dist/syncGroups/SyncGroupsState.js +4 -5
- package/dist/syncGroups/SyncGroupsTransaction.js +259 -303
- package/dist/tasks/TaskHandler.js +53 -64
- package/dist/tests/testData/dummyProductForTest.js +4 -1
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +18 -21
- package/dist/tests/testData/testDataCachedGetProduct.js +20 -20
- package/dist/tests/testData/testDataCachedPostValidate.js +6 -15
- package/dist/tests/testData/testDataProductAggregatedPrice.js +21 -21
- package/dist/tests/testData/testDataUpcharge.js +31 -22
- package/dist/utilitiesCatalogueData.js +21 -9
- package/dist/utilitiesCataloguePermission.js +5 -2
- package/dist/utilitiesConfiguration.js +21 -23
- package/package.json +3 -3
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { compareArrays, count, Observable, } from "@configura/web-utilities";
|
|
1
|
+
import { Observable, compareArrays, count, } from "@configura/web-utilities";
|
|
11
2
|
import { CfgProduct } from "../CfgProduct.js";
|
|
12
3
|
import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
|
|
13
4
|
import { CfgMtrlApplicationSource } from "../material/CfgMtrlApplicationSource.js";
|
|
@@ -89,7 +80,7 @@ export class _CfgOptionInternal {
|
|
|
89
80
|
this.rootProduct = rootProduct;
|
|
90
81
|
this.changeObservable = new Observable();
|
|
91
82
|
/** Called by child to tell its parent that it has changed. */
|
|
92
|
-
this._childHasChanged = (freshRef, bubbleMode, committed) =>
|
|
83
|
+
this._childHasChanged = async (freshRef, bubbleMode, committed) => {
|
|
93
84
|
const features = this._features;
|
|
94
85
|
if (features === undefined) {
|
|
95
86
|
throw Error("Child says it changed, but no children has actually been generated");
|
|
@@ -104,12 +95,12 @@ export class _CfgOptionInternal {
|
|
|
104
95
|
if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected ||
|
|
105
96
|
bubbleMode === ProductConfigurationBubbleMode.BubbleSelected) {
|
|
106
97
|
// selectOption takes care of the bubble
|
|
107
|
-
|
|
98
|
+
await this.parent.selectOption(this, true, bubbleMode);
|
|
108
99
|
}
|
|
109
100
|
else {
|
|
110
|
-
|
|
101
|
+
await this.parent._childHasChanged(this, bubbleMode, committed);
|
|
111
102
|
}
|
|
112
|
-
}
|
|
103
|
+
};
|
|
113
104
|
this.getDtoConf = (includeExtendedData) => {
|
|
114
105
|
const { features, isUseNumericValue, code, selected, numericValue } = this;
|
|
115
106
|
if (!selected) {
|
|
@@ -138,7 +129,7 @@ export class _CfgOptionInternal {
|
|
|
138
129
|
// way around. For that reason the get-method above uses the new format, and the set-method
|
|
139
130
|
// below the old format. As these functions are meant to only be used internally this should't
|
|
140
131
|
// cause too much confusion.
|
|
141
|
-
this.setApiSelection = (apiOptionSelection, apiOptionConstraint) =>
|
|
132
|
+
this.setApiSelection = async (apiOptionSelection, apiOptionConstraint) => {
|
|
142
133
|
let change = false;
|
|
143
134
|
const upcharge = this._calculateUpcharge();
|
|
144
135
|
if (this._upcharge !== upcharge) {
|
|
@@ -152,16 +143,15 @@ export class _CfgOptionInternal {
|
|
|
152
143
|
else {
|
|
153
144
|
features = this.features; // This will generate all children
|
|
154
145
|
}
|
|
155
|
-
if ((
|
|
146
|
+
if ((await Promise.all(features.map((f) => f._internal.setApiSelection(apiOptionSelection ? apiOptionSelection.next : undefined, apiOptionConstraint?.next)))).some((b) => b)) {
|
|
156
147
|
change = true;
|
|
157
148
|
}
|
|
158
149
|
return change;
|
|
159
|
-
}
|
|
150
|
+
};
|
|
160
151
|
this.getApiConstrained = (constrOptions) => {
|
|
161
|
-
var _a;
|
|
162
152
|
const next = {};
|
|
163
153
|
// use _features to avoid populating when the option is not selected
|
|
164
|
-
for (const feature of
|
|
154
|
+
for (const feature of this._features ?? []) {
|
|
165
155
|
feature._internal.addForApiConstrained(next);
|
|
166
156
|
}
|
|
167
157
|
return {
|
|
@@ -173,24 +163,22 @@ export class _CfgOptionInternal {
|
|
|
173
163
|
};
|
|
174
164
|
this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => this.keyMatch(other, descriptionMatch) &&
|
|
175
165
|
compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
176
|
-
this.tryMatchSelection = (other, descriptionMatch = false) =>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}))()))).some((b) => b);
|
|
193
|
-
});
|
|
166
|
+
this.tryMatchSelection = async (other, descriptionMatch = false) => (await Promise.all(other.features.map((otherF) => (async () => {
|
|
167
|
+
if (1 <
|
|
168
|
+
count(other.features, (item) => item._internal.keyMatch(otherF._internal, descriptionMatch))) {
|
|
169
|
+
console.warn("tryMatchSelection will ignore items with same key");
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const toSetFeatures = this.features.filter((f) => f._internal.keyMatch(otherF._internal, descriptionMatch));
|
|
173
|
+
if (1 < toSetFeatures.length) {
|
|
174
|
+
console.warn("tryMatchSelection will ignore items with same key");
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
if (toSetFeatures.length === 0) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return await toSetFeatures[0]._internal.tryMatchSelection(otherF._internal, descriptionMatch);
|
|
181
|
+
})()))).some((b) => b);
|
|
194
182
|
this.keyMatch = (other, descriptionMatch = false) => descriptionMatch
|
|
195
183
|
? this.description.toLowerCase() === other.description.toLowerCase()
|
|
196
184
|
: this.code === other.code;
|
|
@@ -231,12 +219,10 @@ export class _CfgOptionInternal {
|
|
|
231
219
|
return this.rawOption.code;
|
|
232
220
|
}
|
|
233
221
|
get notes() {
|
|
234
|
-
|
|
235
|
-
return this.parentProduct.getNotes((_a = this.rawOption.noteRefs) !== null && _a !== void 0 ? _a : []);
|
|
222
|
+
return this.parentProduct.getNotes(this.rawOption.noteRefs ?? []);
|
|
236
223
|
}
|
|
237
224
|
get miscFiles() {
|
|
238
|
-
|
|
239
|
-
return (_a = this.rawOption.miscFiles) !== null && _a !== void 0 ? _a : [];
|
|
225
|
+
return this.rawOption.miscFiles ?? [];
|
|
240
226
|
}
|
|
241
227
|
get isUseNumericValue() {
|
|
242
228
|
return this.parent.isUseNumericValue;
|
|
@@ -244,36 +230,34 @@ export class _CfgOptionInternal {
|
|
|
244
230
|
get numericValue() {
|
|
245
231
|
return this._numericValue;
|
|
246
232
|
}
|
|
247
|
-
setNumericValue(val, doSelectOption) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
233
|
+
async setNumericValue(val, doSelectOption) {
|
|
234
|
+
if (!this.isAllowedNumericValue(val)) {
|
|
235
|
+
throw new Error(`The value ${val} is not allowed. This could be because: 1. There are no allowed ranges defined 2. The Feature is numeric selection and the value does not fit in the allowed values 3. The Feature is not numeric selection and the value is not the first in the allowed ranges.`);
|
|
236
|
+
}
|
|
237
|
+
let change = false;
|
|
238
|
+
if (this.isUseNumericValue) {
|
|
239
|
+
if (this._numericValue !== val) {
|
|
240
|
+
this._numericValue = val;
|
|
241
|
+
change = true;
|
|
251
242
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
// It could be that even though our value did not change some sibling value did, and
|
|
259
|
-
// this could make it needed to bubble later. Maybe. A bit uncertain about why I did
|
|
260
|
-
// not put this in the if-statement above //Linus
|
|
261
|
-
if (yield this.parent.pushStretch()) {
|
|
262
|
-
change = true;
|
|
263
|
-
}
|
|
243
|
+
// It could be that even though our value did not change some sibling value did, and
|
|
244
|
+
// this could make it needed to bubble later. Maybe. A bit uncertain about why I did
|
|
245
|
+
// not put this in the if-statement above //Linus
|
|
246
|
+
if (await this.parent.pushStretch()) {
|
|
247
|
+
change = true;
|
|
264
248
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
249
|
+
}
|
|
250
|
+
if (doSelectOption) {
|
|
251
|
+
if (await this.parent.selectOption(this, true, ProductConfigurationBubbleMode.Validate)) {
|
|
252
|
+
change = true;
|
|
269
253
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
if (change) {
|
|
257
|
+
await this.parent._childHasChanged(this, ProductConfigurationBubbleMode.Stop, false);
|
|
274
258
|
}
|
|
275
|
-
|
|
276
|
-
|
|
259
|
+
}
|
|
260
|
+
return change;
|
|
277
261
|
}
|
|
278
262
|
get unit() {
|
|
279
263
|
return this.parent.unit;
|
|
@@ -287,6 +271,12 @@ export class _CfgOptionInternal {
|
|
|
287
271
|
get disabled() {
|
|
288
272
|
return this.parent.isDisabled(this);
|
|
289
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
276
|
+
*/
|
|
277
|
+
get unresolvable() {
|
|
278
|
+
return this.parent.isUnresolvable(this);
|
|
279
|
+
}
|
|
290
280
|
get selectedChangeInProgress() {
|
|
291
281
|
const syncGroupHandler = this.rootProduct.syncGroupHandler;
|
|
292
282
|
if (syncGroupHandler === undefined) {
|
|
@@ -345,6 +335,26 @@ export class _CfgOptionInternal {
|
|
|
345
335
|
}
|
|
346
336
|
return 0;
|
|
347
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Get the child features that are contained within this option.
|
|
340
|
+
*
|
|
341
|
+
* Safe to call outside of the sync process, but may not contain any
|
|
342
|
+
* children until the sync process is complete.
|
|
343
|
+
*/
|
|
344
|
+
getFeaturesOutsideSync() {
|
|
345
|
+
return this._features ?? [];
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Get the child features that are contained within this option.
|
|
349
|
+
*
|
|
350
|
+
* ONLY ACCESS THIS PROPERTY UNDER THESE CONDITIONS:
|
|
351
|
+
* 1. The product is undergoing the sync group sync process.
|
|
352
|
+
* 2. AND you are operating on the new "target" product.
|
|
353
|
+
*
|
|
354
|
+
* Explanation: This method will generate all children if they have not been
|
|
355
|
+
* generated yet, which breaks sync group syncing, due to the presence of
|
|
356
|
+
* these children being used to determine if the sync should happen at all.
|
|
357
|
+
*/
|
|
348
358
|
get features() {
|
|
349
359
|
if (this._features === undefined) {
|
|
350
360
|
const allRefs = this.rawOption.featureRefs || [];
|
|
@@ -366,16 +376,16 @@ export class CfgOption {
|
|
|
366
376
|
constructor(_internal) {
|
|
367
377
|
this._internal = _internal;
|
|
368
378
|
this.isBackedBySame = (other) => this._internal === other._internal;
|
|
369
|
-
this.setNumericValue = (val, doSelectOption) =>
|
|
379
|
+
this.setNumericValue = async (val, doSelectOption) => await this._internal.setNumericValue(val, doSelectOption);
|
|
370
380
|
this.isAllowedNumericValue = (val) => this._internal.isAllowedNumericValue(val);
|
|
371
381
|
/**
|
|
372
382
|
* Selects this Option.
|
|
373
383
|
* Only Options belonging to Features that are "select many" can be deselected.
|
|
374
384
|
* Calling this will cause a validation call to the server.
|
|
375
385
|
*/
|
|
376
|
-
this.setSelected = (on) =>
|
|
377
|
-
return
|
|
378
|
-
}
|
|
386
|
+
this.setSelected = async (on) => {
|
|
387
|
+
return await this._internal.parent.selectOption(this._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
388
|
+
};
|
|
379
389
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
380
390
|
this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
|
|
381
391
|
}
|
|
@@ -435,6 +445,12 @@ export class CfgOption {
|
|
|
435
445
|
get disabled() {
|
|
436
446
|
return this._internal.disabled;
|
|
437
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
450
|
+
*/
|
|
451
|
+
get unresolvable() {
|
|
452
|
+
return this._internal.unresolvable;
|
|
453
|
+
}
|
|
438
454
|
/**
|
|
439
455
|
* Selection state is in progress to be changed. This can be used in GUI
|
|
440
456
|
* to display the state as transitioning, or as already changed.
|
|
@@ -458,6 +474,26 @@ export class CfgOption {
|
|
|
458
474
|
get priceChangeAtSelectChange() {
|
|
459
475
|
return this._internal.priceChangeAtSelectChange;
|
|
460
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Get the child features that are contained within this option.
|
|
479
|
+
*
|
|
480
|
+
* Safe to call outside of the sync process, but may not contain any
|
|
481
|
+
* children until the sync process is complete.
|
|
482
|
+
*/
|
|
483
|
+
getFeaturesOutsideSync() {
|
|
484
|
+
return this._internal.getFeaturesOutsideSync();
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get the child features that are contained within this option.
|
|
488
|
+
*
|
|
489
|
+
* ONLY ACCESS THIS PROPERTY UNDER THESE CONDITIONS:
|
|
490
|
+
* 1. The product is undergoing the sync group sync process.
|
|
491
|
+
* 2. AND you are operating on the new "target" product.
|
|
492
|
+
*
|
|
493
|
+
* Explanation: This method will generate all children if they have not been
|
|
494
|
+
* generated yet, which breaks sync group syncing, due to the presence of
|
|
495
|
+
* these children being used to determine if the sync should happen at all.
|
|
496
|
+
*/
|
|
461
497
|
get features() {
|
|
462
498
|
return this._internal.features;
|
|
463
499
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { compareArrays, count, isEqualLength, isLengthUnit, Observable, toError, toLengthUnit, } from "@configura/web-utilities";
|
|
11
2
|
import { CfgProduct } from "../CfgProduct.js";
|
|
12
3
|
import { convertDtoFeatureConfsToSelOptions } from "../utilitiesConfiguration.js";
|
|
@@ -27,7 +18,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
27
18
|
this.accumulatedRawFeatures = []; // Flat packed. May be extended in validate calls.
|
|
28
19
|
this._features = [];
|
|
29
20
|
this.changeObservable = new Observable();
|
|
30
|
-
this._notifyAllOfChange = (bubbleMode, committed) =>
|
|
21
|
+
this._notifyAllOfChange = async (bubbleMode, committed) => {
|
|
31
22
|
if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
|
|
32
23
|
return;
|
|
33
24
|
}
|
|
@@ -40,20 +31,20 @@ export class _CfgProductConfigurationInternal {
|
|
|
40
31
|
if (parent === undefined) {
|
|
41
32
|
return;
|
|
42
33
|
}
|
|
43
|
-
|
|
34
|
+
await parent._configurationHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
|
|
44
35
|
? ProductConfigurationBubbleMode.Stop
|
|
45
36
|
: bubbleMode, committed);
|
|
46
|
-
}
|
|
37
|
+
};
|
|
47
38
|
/** Called by child to tell its parent that it has changed. */
|
|
48
|
-
this._childHasChanged = (freshRef, bubbleMode, committed) =>
|
|
39
|
+
this._childHasChanged = async (freshRef, bubbleMode, committed) => {
|
|
49
40
|
const features = this._features;
|
|
50
41
|
const i = features.findIndex((a) => a.isBackedBySame(freshRef));
|
|
51
42
|
if (i === -1) {
|
|
52
43
|
throw Error("Child feature not found");
|
|
53
44
|
}
|
|
54
45
|
features[i] = freshRef;
|
|
55
|
-
|
|
56
|
-
}
|
|
46
|
+
await this._notifyAllOfChange(bubbleMode, committed);
|
|
47
|
+
};
|
|
57
48
|
this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
|
|
58
49
|
this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
|
|
59
50
|
this.getApiConstrained = () => this._features.map((f) => {
|
|
@@ -70,7 +61,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
70
61
|
* outside we want notifications to bubble all the way to the root.
|
|
71
62
|
* This method will not cause validation calls. Data is assumed to already be validated.
|
|
72
63
|
*/
|
|
73
|
-
this.setApiSelection = (selectedOptions, constrOptions, bubbleToRoot) =>
|
|
64
|
+
this.setApiSelection = async (selectedOptions, constrOptions, bubbleToRoot) => {
|
|
74
65
|
const featuresLength = this._features.length;
|
|
75
66
|
const selectedOptionsLength = selectedOptions.length;
|
|
76
67
|
if (featuresLength !== selectedOptionsLength) {
|
|
@@ -79,27 +70,24 @@ export class _CfgProductConfigurationInternal {
|
|
|
79
70
|
if (constrOptions && featuresLength !== constrOptions.length) {
|
|
80
71
|
throw new Error(`Wrong constraint feature count. Features on this configuration: ${featuresLength}. Passed constraint feature count: ${constrOptions.length}.`);
|
|
81
72
|
}
|
|
82
|
-
const change = (
|
|
83
|
-
var _a;
|
|
84
|
-
return f._internal.setApiSelection(selectedOptions[i].next, (_a = (constrOptions !== null && constrOptions !== void 0 ? constrOptions : [])[i]) === null || _a === void 0 ? void 0 : _a.next);
|
|
85
|
-
}))).some((b) => b);
|
|
73
|
+
const change = (await Promise.all(this._features.map((f, i) => f._internal.setApiSelection(selectedOptions[i].next, (constrOptions ?? [])[i]?.next)))).some((b) => b);
|
|
86
74
|
if (change) {
|
|
87
|
-
|
|
75
|
+
await this._notifyAllOfChange(bubbleToRoot
|
|
88
76
|
? ProductConfigurationBubbleMode.ToRoot
|
|
89
77
|
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
90
78
|
}
|
|
91
79
|
return change;
|
|
92
|
-
}
|
|
80
|
+
};
|
|
93
81
|
this.structureCompare = (other, strictOrder, descriptionMatch) => compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
94
82
|
/**
|
|
95
83
|
* When used internally the notifications are taken care off by the caller, but if set from
|
|
96
84
|
* outside we want notifications to bubble all the way to the root.
|
|
97
85
|
*/
|
|
98
|
-
this.tryMatchSelection = (other, descriptionMatch = false, // Match on case insensitive description, not code
|
|
99
|
-
validate) =>
|
|
86
|
+
this.tryMatchSelection = async (other, descriptionMatch = false, // Match on case insensitive description, not code
|
|
87
|
+
validate) => {
|
|
100
88
|
const thisFeatures = this.features;
|
|
101
89
|
const otherFeatures = other.features;
|
|
102
|
-
const change = (
|
|
90
|
+
const change = (await Promise.all(otherFeatures.map((otherF) => (async () => {
|
|
103
91
|
if (1 <
|
|
104
92
|
count(otherFeatures, (item) => item._internal.keyMatch(otherF._internal, descriptionMatch))) {
|
|
105
93
|
console.warn("tryMatchSelection will ignore items with same key");
|
|
@@ -113,15 +101,15 @@ export class _CfgProductConfigurationInternal {
|
|
|
113
101
|
if (toSetFeatures.length === 0) {
|
|
114
102
|
return false;
|
|
115
103
|
}
|
|
116
|
-
return
|
|
117
|
-
})
|
|
104
|
+
return await toSetFeatures[0]._internal.tryMatchSelection(otherF._internal, descriptionMatch);
|
|
105
|
+
})()))).some((b) => b);
|
|
118
106
|
if (change) {
|
|
119
|
-
|
|
107
|
+
await this._notifyAllOfChange(validate
|
|
120
108
|
? ProductConfigurationBubbleMode.Validate
|
|
121
109
|
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
122
110
|
}
|
|
123
111
|
return change;
|
|
124
|
-
}
|
|
112
|
+
};
|
|
125
113
|
/** Only selected features. */
|
|
126
114
|
this._getFeaturesWithCode = (code) => this._features.reduce((agg, feature) => {
|
|
127
115
|
agg.push(...feature._internal._getFeaturesWithCode(code));
|
|
@@ -161,7 +149,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
161
149
|
this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.accumulatedRawFeatures, this, this, this.parentProduct, this.rootProduct);
|
|
162
150
|
return true;
|
|
163
151
|
};
|
|
164
|
-
this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) =>
|
|
152
|
+
this.setStretchReferenceLength = async (measureParamCode, referenceLength, unit) => {
|
|
165
153
|
if (measureParamCode === "") {
|
|
166
154
|
return false;
|
|
167
155
|
}
|
|
@@ -192,9 +180,9 @@ export class _CfgProductConfigurationInternal {
|
|
|
192
180
|
}
|
|
193
181
|
stretchReferenceLength.current = referenceLengthWithUnit;
|
|
194
182
|
}
|
|
195
|
-
|
|
183
|
+
await this._notifyAllOfChange(ProductConfigurationBubbleMode.ToRoot, false);
|
|
196
184
|
return true;
|
|
197
|
-
}
|
|
185
|
+
};
|
|
198
186
|
/* eslint-disable */
|
|
199
187
|
// Useful debug tool:
|
|
200
188
|
if (false) {
|
|
@@ -278,8 +266,8 @@ export class CfgProductConfiguration {
|
|
|
278
266
|
* This method does not propagate its selections.
|
|
279
267
|
* This method will cause validation calls.
|
|
280
268
|
*/
|
|
281
|
-
this.tryMatchSelection = (other, descriptionMatch = false // Match on case insensitive description, not code
|
|
282
|
-
) =>
|
|
269
|
+
this.tryMatchSelection = async (other, descriptionMatch = false // Match on case insensitive description, not code
|
|
270
|
+
) => await this._internal.tryMatchSelection(other._internal, descriptionMatch, true);
|
|
283
271
|
/**
|
|
284
272
|
* Set how stretched a certain measure should be measureParamCode is the measure to be
|
|
285
273
|
* stretched referenceLength is a value relative to the initial length of the measure. If the
|
|
@@ -1,65 +1,51 @@
|
|
|
1
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
2
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
3
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
5
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
6
|
-
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
7
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
8
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
9
|
-
function fulfill(value) { resume("next", value); }
|
|
10
|
-
function reject(value) { resume("throw", value); }
|
|
11
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
12
|
-
};
|
|
13
1
|
import { toError } from "@configura/web-utilities";
|
|
14
2
|
import { CfgProduct } from "../CfgProduct.js";
|
|
15
3
|
import { applyProductRefFilters } from "./filters.js";
|
|
16
|
-
export function generateProductConfigurations(api, lang, catalogues, filters, settings) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
err.message = err.message.slice(0, split);
|
|
55
|
-
}
|
|
56
|
-
yield yield __await(toError(e));
|
|
4
|
+
export async function* generateProductConfigurations(api, lang, catalogues, filters, settings) {
|
|
5
|
+
const catalogueCount = catalogues.length;
|
|
6
|
+
const catalogueEntries = catalogues.entries();
|
|
7
|
+
for (const [catalogueIndex, catalogueParamsWithoutLang] of catalogueEntries) {
|
|
8
|
+
const catalogueParams = { ...catalogueParamsWithoutLang, lang };
|
|
9
|
+
try {
|
|
10
|
+
const [applicationAreasResponse, toc] = await Promise.all([
|
|
11
|
+
api.getApplicationAreas(catalogueParams),
|
|
12
|
+
api.getTocFlat(catalogueParams),
|
|
13
|
+
]);
|
|
14
|
+
const [, productRefs] = applyProductRefFilters(filters, toc?.prdRefs || []);
|
|
15
|
+
const productCount = productRefs.length;
|
|
16
|
+
const productEntries = productRefs.entries();
|
|
17
|
+
for (const [productIndex, prdRef] of productEntries) {
|
|
18
|
+
const startTime = performance.now();
|
|
19
|
+
try {
|
|
20
|
+
const product = await CfgProduct.make(api, { ...catalogueParams, partNumber: prdRef.partNr }, settings);
|
|
21
|
+
const getProductDuration = performance.now() - startTime;
|
|
22
|
+
yield {
|
|
23
|
+
applicationAreasResponse,
|
|
24
|
+
catalogueCount,
|
|
25
|
+
catalogueIndex,
|
|
26
|
+
catalogueParams,
|
|
27
|
+
getProductDuration,
|
|
28
|
+
product,
|
|
29
|
+
productCount,
|
|
30
|
+
productIndex,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
const err = e;
|
|
35
|
+
// Product load error, for example missing CmSym files.
|
|
36
|
+
// Safe to continue loading the next product.
|
|
37
|
+
const split = err.message.indexOf(", request ID: ");
|
|
38
|
+
if (split > -1) {
|
|
39
|
+
// The request ID part of the error from the server is mostly just spam and
|
|
40
|
+
// makes it harder to read list of errors, so remove it.
|
|
41
|
+
err.message = err.message.slice(0, split);
|
|
57
42
|
}
|
|
43
|
+
yield toError(e);
|
|
58
44
|
}
|
|
59
45
|
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
yield yield __await(toError(e));
|
|
62
|
-
}
|
|
63
46
|
}
|
|
64
|
-
|
|
47
|
+
catch (e) {
|
|
48
|
+
yield toError(e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
65
51
|
}
|
package/dist/productLoader.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { PromiseCache } from "@configura/web-utilities";
|
|
11
2
|
import { makeProductKey, makeSelOptionsKey, } from "./utilitiesCatalogueData.js";
|
|
12
3
|
/**
|
|
@@ -21,7 +12,7 @@ import { makeProductKey, makeSelOptionsKey, } from "./utilitiesCatalogueData.js"
|
|
|
21
12
|
*/
|
|
22
13
|
export function wrapWithGetProductCache(getProduct) {
|
|
23
14
|
const cache = new PromiseCache();
|
|
24
|
-
return (params) =>
|
|
15
|
+
return async (params) => cache.get(makeProductKey(params), () => getProduct(params));
|
|
25
16
|
}
|
|
26
17
|
/**
|
|
27
18
|
* Wraps a postValidate function so that it caches for the time it lives.
|
|
@@ -36,9 +27,7 @@ export function wrapWithGetProductCache(getProduct) {
|
|
|
36
27
|
*/
|
|
37
28
|
export function wrapWithPostValidateCache(postValidate) {
|
|
38
29
|
const cache = new PromiseCache();
|
|
39
|
-
return (params, body) =>
|
|
40
|
-
return cache.get(`${makeProductKey(params)}-${makeSelOptionsKey(body.selOptions)}-${body.knownFeatureCodes.join(",")}`, () => postValidate(params, body));
|
|
41
|
-
});
|
|
30
|
+
return async (params, body) => cache.get(`${makeProductKey(params)}-${makeSelOptionsKey(body.selOptions)}-${body.knownFeatureCodes.join(",")}`, () => postValidate(params, body));
|
|
42
31
|
}
|
|
43
32
|
/** Does both wrapWithGetProductCache and wrapWithPostValidateCache. */
|
|
44
33
|
export function wrapWithCache(loader) {
|