@configura/web-api 1.6.1-alpha.7 → 1.6.1
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 +18 -0
- package/dist/CatalogueAPI.d.ts +4 -9
- package/dist/CatalogueAPI.js +6 -3
- package/dist/CfgProduct.d.ts +31 -12
- package/dist/CfgProduct.js +124 -45
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/productConfiguration/CfgFeature.d.ts +13 -3
- package/dist/productConfiguration/CfgFeature.js +77 -52
- package/dist/productConfiguration/CfgOption.d.ts +30 -8
- package/dist/productConfiguration/CfgOption.js +49 -17
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +1 -1
- package/dist/productConfiguration/CfgProductConfiguration.js +4 -2
- package/dist/productConfiguration/filters.js +7 -7
- package/dist/syncGroups/SyncGroupsApplyMode.d.ts +21 -0
- package/dist/syncGroups/SyncGroupsApplyMode.js +21 -0
- package/dist/syncGroups/SyncGroupsHandler.d.ts +41 -0
- package/dist/syncGroups/SyncGroupsHandler.js +358 -0
- package/dist/syncGroups/SyncGroupsPathHelper.d.ts +27 -0
- package/dist/syncGroups/SyncGroupsPathHelper.js +90 -0
- package/dist/syncGroups/SyncGroupsState.d.ts +36 -0
- package/dist/syncGroups/SyncGroupsState.js +125 -0
- package/dist/syncGroups/SyncGroupsTransaction.d.ts +155 -0
- package/dist/syncGroups/SyncGroupsTransaction.js +576 -0
- package/dist/tasks/TaskHandler.d.ts +1 -1
- package/dist/tasks/TaskHandler.js +20 -9
- package/dist/tests/testData/collectorForTest.d.ts +1 -1
- package/dist/tests/testData/collectorForTest.js +1 -2
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.d.ts +3 -24
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +30 -101
- package/dist/tests/testData/testDataCachedGetProduct.d.ts +1 -1
- package/dist/tests/testData/testDataCachedGetProduct.js +16 -27
- package/dist/tests/testData/testDataCachedPostValidate.js +5 -5
- package/dist/tests/testData/testDataOptions.d.ts +13 -0
- package/dist/tests/testData/testDataOptions.js +60 -0
- package/dist/tests/testData/testDataProductAggregatedPrice.js +19 -30
- package/dist/tests/testData/testDataUpcharge.d.ts +3 -24
- package/dist/tests/testData/testDataUpcharge.js +17 -49
- package/dist/utilitiesCatalogueData.d.ts +8 -2
- package/dist/utilitiesCatalogueData.js +105 -9
- package/dist/utilitiesCataloguePermission.d.ts +1 -3
- package/dist/utilitiesCataloguePermission.js +10 -14
- package/package.json +3 -3
|
@@ -7,10 +7,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { compareArrays, convertLength, count, Observable, someMatch, toLengthUnit, } from "@configura/web-utilities";
|
|
10
|
+
import { assertDefined, compareArrays, convertLength, count, Observable, someMatch, toLengthUnit, } from "@configura/web-utilities";
|
|
11
11
|
import { CfgProduct } from "../CfgProduct.js";
|
|
12
12
|
import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
|
|
13
13
|
import { CfgMtrlApplicationSource } from "../material/CfgMtrlApplicationSource.js";
|
|
14
|
+
import { wrapWithCache } from "../productLoader.js";
|
|
14
15
|
import { CfgOption, ProductConfigurationBubbleMode } from "./CfgOption.js";
|
|
15
16
|
import { _CfgProductConfigurationInternal } from "./CfgProductConfiguration.js";
|
|
16
17
|
import { getMtrlPreview } from "./utilitiesProductConfiguration.js";
|
|
@@ -188,25 +189,13 @@ export class _CfgFeatureInternal {
|
|
|
188
189
|
console.warn(wrongCountWarning);
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
|
-
if (!isGroup) {
|
|
192
|
-
const apiSelectionCount = Object.keys(apiOptionSelectionMap).length;
|
|
193
|
-
if (selectionCount !== apiSelectionCount) {
|
|
194
|
-
const wrongCountWarning = `All provided Options are expected to be selected. Feature key: "${this.key}". Expected: ${apiSelectionCount} Actual: ${selectionCount}`;
|
|
195
|
-
if (this.rootProduct.settings.strictSetApiSelectionMatch) {
|
|
196
|
-
throw new Error(wrongCountWarning);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
console.warn(wrongCountWarning);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
192
|
}
|
|
204
193
|
if (change) {
|
|
205
194
|
if (isAllOptionsAffectedByAnySelection) {
|
|
206
195
|
this._freshRefAllOptions();
|
|
207
196
|
}
|
|
208
197
|
if (selectionType === SelectionType.SelectOne) {
|
|
209
|
-
this.pushStretch();
|
|
198
|
+
yield this.pushStretch();
|
|
210
199
|
}
|
|
211
200
|
// setApiSelection works its way top down and handles notifications on
|
|
212
201
|
// each level by looking at change returned from its children. That way
|
|
@@ -301,11 +290,19 @@ export class _CfgFeatureInternal {
|
|
|
301
290
|
return change;
|
|
302
291
|
});
|
|
303
292
|
/**
|
|
304
|
-
* Normally this is used through methods on CfgFeature and CfgOption. Use this
|
|
305
|
-
*
|
|
293
|
+
* Normally this is used through methods on CfgFeature and CfgOption. Use this internal version
|
|
294
|
+
* if you need to control the bubbleMode.
|
|
295
|
+
*
|
|
306
296
|
* Using a validate bubbleMode will cause validation calls to the server.
|
|
307
297
|
*/
|
|
308
298
|
this.selectOption = (optionInternal, on, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
|
|
299
|
+
if (bubbleMode ===
|
|
300
|
+
ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups) {
|
|
301
|
+
const product = this.rootProduct;
|
|
302
|
+
const syncGroupHandler = product.syncGroupHandler;
|
|
303
|
+
assertDefined(syncGroupHandler, `Sync group handler is required for bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
|
|
304
|
+
return yield syncGroupHandler.selectOption(product, optionInternal, on, wrapWithCache(product._productLoaderRaw));
|
|
305
|
+
}
|
|
309
306
|
if (!on) {
|
|
310
307
|
if (this.selectionType === SelectionType.Group) {
|
|
311
308
|
throw new Error(`Multiple features are always selected and are not user selectable. Feature key: "${this.key}".`);
|
|
@@ -318,50 +315,59 @@ export class _CfgFeatureInternal {
|
|
|
318
315
|
const isAllOptionsAffectedByAnySelection = this.isAllOptionsAffectedByAnySelection;
|
|
319
316
|
const index = selectedOptions.findIndex(getOptionFilter(optionInternal));
|
|
320
317
|
const isActualChange = (index === -1) === on;
|
|
321
|
-
if (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
318
|
+
if (this.selectionType !== SelectionType.Group) {
|
|
319
|
+
if (on) {
|
|
320
|
+
// Calling this.options will populate (generate) all Options if they have not yet
|
|
321
|
+
// been generated. As we are selecting an option we need all Options to be generated.
|
|
322
|
+
const options = this.options;
|
|
323
|
+
if (this.selectionType === SelectionType.SelectOne) {
|
|
324
|
+
let removeOption = selectedOptions.shift();
|
|
325
|
+
while (removeOption !== undefined) {
|
|
326
|
+
if (!isAllOptionsAffectedByAnySelection) {
|
|
327
|
+
doFreshRefOption(options, removeOption._internal);
|
|
328
|
+
}
|
|
329
|
+
removeOption = selectedOptions.shift();
|
|
330
330
|
}
|
|
331
|
-
removeOption = selectedOptions.shift();
|
|
332
331
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
332
|
+
if (isAllOptionsAffectedByAnySelection) {
|
|
333
|
+
selectedOptions.push(CfgOption._makeNewRefFrom(optionInternal));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
doFreshRefOption(options, optionInternal, (freshRef) => selectedOptions.push(freshRef));
|
|
337
|
+
}
|
|
338
|
+
if (this.selectionType === SelectionType.SelectOne) {
|
|
339
|
+
yield this.pushStretch();
|
|
340
|
+
}
|
|
336
341
|
}
|
|
337
342
|
else {
|
|
338
|
-
|
|
343
|
+
selectedOptions.splice(index, 1);
|
|
344
|
+
if (!isAllOptionsAffectedByAnySelection) {
|
|
345
|
+
// Accessing this._options gives us the Options that have been generated
|
|
346
|
+
// or undefined if the Options have not yet been generated. As this action
|
|
347
|
+
// is deselect and deselected is the default uninitialized state we can
|
|
348
|
+
// safely ignore if undefined.
|
|
349
|
+
const options = this._options;
|
|
350
|
+
if (options !== undefined) {
|
|
351
|
+
doFreshRefOption(options, optionInternal);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
339
354
|
}
|
|
340
|
-
if (
|
|
341
|
-
|
|
355
|
+
if (isAllOptionsAffectedByAnySelection) {
|
|
356
|
+
this._freshRefAllOptions();
|
|
342
357
|
}
|
|
343
358
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
doFreshRefOption(options, optionInternal);
|
|
354
|
-
}
|
|
359
|
+
let nextLevelBubbleMode = bubbleMode;
|
|
360
|
+
if (!on) {
|
|
361
|
+
// If this was a deselect action we shall not bubble selected, that is, we shall not
|
|
362
|
+
// select the ancestors if this action was deselect.
|
|
363
|
+
if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected) {
|
|
364
|
+
nextLevelBubbleMode = ProductConfigurationBubbleMode.Validate;
|
|
365
|
+
}
|
|
366
|
+
else if (bubbleMode === ProductConfigurationBubbleMode.BubbleSelected) {
|
|
367
|
+
nextLevelBubbleMode = ProductConfigurationBubbleMode.ToRoot;
|
|
355
368
|
}
|
|
356
369
|
}
|
|
357
|
-
|
|
358
|
-
this._freshRefAllOptions();
|
|
359
|
-
}
|
|
360
|
-
// If this was a deselect action we shall not bubble selected, that is, we shall not
|
|
361
|
-
// select the ancestors if this action was deselect.
|
|
362
|
-
yield this._notifyAllOfChange(!on && bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected
|
|
363
|
-
? ProductConfigurationBubbleMode.Validate
|
|
364
|
-
: bubbleMode);
|
|
370
|
+
yield this._notifyAllOfChange(nextLevelBubbleMode);
|
|
365
371
|
return isActualChange;
|
|
366
372
|
});
|
|
367
373
|
this.isSelected = (option) => this.selectionType === SelectionType.Group ||
|
|
@@ -415,6 +421,25 @@ export class _CfgFeatureInternal {
|
|
|
415
421
|
get description() {
|
|
416
422
|
return this.rawFeature.description;
|
|
417
423
|
}
|
|
424
|
+
get syncGroup() {
|
|
425
|
+
return this.rawFeature.syncGroup;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* @return one of the following, in order:
|
|
429
|
+
* - undefined if the Feature lacks a syncGroup.
|
|
430
|
+
* - false if the syncGroup doesn't fulfill the optional mustSupport requirement.
|
|
431
|
+
* - syncCode from the syncGroup.
|
|
432
|
+
*/
|
|
433
|
+
getSyncCode(mustSupport) {
|
|
434
|
+
if (this.syncGroup === undefined) {
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
const { syncGroupCode, syncMethod } = this.syncGroup;
|
|
438
|
+
if (mustSupport === undefined || syncMethod === "twoWay" || syncMethod === mustSupport) {
|
|
439
|
+
return syncGroupCode;
|
|
440
|
+
}
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
418
443
|
/**
|
|
419
444
|
* The MeasureParam class is re-used for different purposes. In Features it is used
|
|
420
445
|
* to indicate which stretch measures inside Models shall be affected by this state
|
|
@@ -531,7 +556,7 @@ export class CfgFeature {
|
|
|
531
556
|
* Calling this will cause a validation call to the server.
|
|
532
557
|
*/
|
|
533
558
|
this.selectOption = (option, on) => __awaiter(this, void 0, void 0, function* () {
|
|
534
|
-
return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.
|
|
559
|
+
return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
535
560
|
});
|
|
536
561
|
this.isSelected = (option) => this._internal.isSelected(option._internal);
|
|
537
562
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
@@ -10,16 +10,25 @@ export declare type OptionChangeNotification = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare enum ProductConfigurationBubbleMode {
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
|
|
13
|
+
* If this is select it will turns on all ancestors all the way up.
|
|
14
|
+
*/
|
|
15
|
+
BubbleSelected = "BubbleSelected",
|
|
16
|
+
/**
|
|
17
|
+
* Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
|
|
18
|
+
* after validate.
|
|
15
19
|
*/
|
|
16
20
|
Validate = "Validate",
|
|
17
21
|
/**
|
|
18
|
-
* Bubble to the closest CfgProduct, let it revalidate, then that will continue
|
|
19
|
-
*
|
|
22
|
+
* Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
|
|
23
|
+
* after validate. If this is select it will turn on all ancestors all the way up.
|
|
20
24
|
* So with this mode it is possible to select an option where its parents are not selected.
|
|
21
25
|
*/
|
|
22
26
|
ValidateAndBubbleSelected = "ValidateAndBubbleSelected",
|
|
27
|
+
/**
|
|
28
|
+
* Like ValidateAndBubbleSelected, but SyncGroups are applied after ValidateAndBubbleSelected
|
|
29
|
+
* has been done
|
|
30
|
+
*/
|
|
31
|
+
ValidateAndBubbleSelectedAndApplySyncGroups = "ValidateAndBubbleSelectedAndApplySyncGroups",
|
|
23
32
|
/**
|
|
24
33
|
* Stop bubbling
|
|
25
34
|
* This mode supports internal functionality and is not expected to be used by integrators.
|
|
@@ -44,10 +53,9 @@ export declare enum ProductConfigurationBubbleMode {
|
|
|
44
53
|
ToRoot = "ToRoot"
|
|
45
54
|
}
|
|
46
55
|
/**
|
|
47
|
-
* This class is meant to
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* should be used and interacted with.
|
|
56
|
+
* This class is only meant to be used through CfgOption. It should never be instantiated on its
|
|
57
|
+
* own. Normally the internal state of this class should never be directly modified. CfgOption is
|
|
58
|
+
* the class that should be used and interacted with.
|
|
51
59
|
*/
|
|
52
60
|
export declare class _CfgOptionInternal {
|
|
53
61
|
readonly rawOption: Option;
|
|
@@ -71,6 +79,7 @@ export declare class _CfgOptionInternal {
|
|
|
71
79
|
get unit(): LengthUnit;
|
|
72
80
|
get description(): string;
|
|
73
81
|
get selected(): boolean;
|
|
82
|
+
get selectedChangeInProgress(): boolean;
|
|
74
83
|
get ancestorsSelected(): boolean;
|
|
75
84
|
get mtrlApplications(): CfgMtrlApplication[];
|
|
76
85
|
get thumbnail(): string | undefined;
|
|
@@ -116,8 +125,21 @@ export declare class CfgOption {
|
|
|
116
125
|
get unit(): LengthUnit;
|
|
117
126
|
get description(): string;
|
|
118
127
|
get selected(): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Selection state is in progress to be changed. This can be used in GUI
|
|
130
|
+
* to display the state as transitioning, or as already changed.
|
|
131
|
+
* If selectedChangeInProgress and:
|
|
132
|
+
* selected is true, it means that this is about to get unselected
|
|
133
|
+
* selected is false, it means that this is about to get selected
|
|
134
|
+
*/
|
|
135
|
+
get selectedChangeInProgress(): boolean;
|
|
119
136
|
/** Are all ancestors up to the CfgProductConfiguration selected? Includes self. */
|
|
120
137
|
get ancestorsSelected(): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Selects this Option.
|
|
140
|
+
* Only Options belonging to Features that are "select many" can be deselected.
|
|
141
|
+
* Calling this will cause a validation call to the server.
|
|
142
|
+
*/
|
|
121
143
|
setSelected: (on: boolean) => Promise<boolean>;
|
|
122
144
|
get thumbnail(): string | undefined;
|
|
123
145
|
get upcharge(): number | undefined;
|
|
@@ -18,16 +18,25 @@ import { getMtrlPreview, syncCfgFeatures } from "./utilitiesProductConfiguration
|
|
|
18
18
|
export var ProductConfigurationBubbleMode;
|
|
19
19
|
(function (ProductConfigurationBubbleMode) {
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
|
|
21
|
+
* If this is select it will turns on all ancestors all the way up.
|
|
22
|
+
*/
|
|
23
|
+
ProductConfigurationBubbleMode["BubbleSelected"] = "BubbleSelected";
|
|
24
|
+
/**
|
|
25
|
+
* Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
|
|
26
|
+
* after validate.
|
|
23
27
|
*/
|
|
24
28
|
ProductConfigurationBubbleMode["Validate"] = "Validate";
|
|
25
29
|
/**
|
|
26
|
-
* Bubble to the closest CfgProduct, let it revalidate, then that will continue
|
|
27
|
-
*
|
|
30
|
+
* Bubble to the closest CfgProduct, let it revalidate, then that will continue the bubble
|
|
31
|
+
* after validate. If this is select it will turn on all ancestors all the way up.
|
|
28
32
|
* So with this mode it is possible to select an option where its parents are not selected.
|
|
29
33
|
*/
|
|
30
34
|
ProductConfigurationBubbleMode["ValidateAndBubbleSelected"] = "ValidateAndBubbleSelected";
|
|
35
|
+
/**
|
|
36
|
+
* Like ValidateAndBubbleSelected, but SyncGroups are applied after ValidateAndBubbleSelected
|
|
37
|
+
* has been done
|
|
38
|
+
*/
|
|
39
|
+
ProductConfigurationBubbleMode["ValidateAndBubbleSelectedAndApplySyncGroups"] = "ValidateAndBubbleSelectedAndApplySyncGroups";
|
|
31
40
|
/**
|
|
32
41
|
* Stop bubbling
|
|
33
42
|
* This mode supports internal functionality and is not expected to be used by integrators.
|
|
@@ -66,10 +75,9 @@ function doesChildrenShareOptionsCode(features) {
|
|
|
66
75
|
return false;
|
|
67
76
|
}
|
|
68
77
|
/**
|
|
69
|
-
* This class is meant to
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* should be used and interacted with.
|
|
78
|
+
* This class is only meant to be used through CfgOption. It should never be instantiated on its
|
|
79
|
+
* own. Normally the internal state of this class should never be directly modified. CfgOption is
|
|
80
|
+
* the class that should be used and interacted with.
|
|
73
81
|
*/
|
|
74
82
|
export class _CfgOptionInternal {
|
|
75
83
|
constructor(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
|
|
@@ -93,7 +101,8 @@ export class _CfgOptionInternal {
|
|
|
93
101
|
features[i] = freshRef;
|
|
94
102
|
// In CfgOption we let stop bubble slip through. This is because CfgOption is sort of
|
|
95
103
|
// a semi level. Like Feature + Option together constitutes one level.
|
|
96
|
-
if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected
|
|
104
|
+
if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected ||
|
|
105
|
+
bubbleMode === ProductConfigurationBubbleMode.BubbleSelected) {
|
|
97
106
|
// selectOption takes care of the bubble
|
|
98
107
|
yield this.parent.selectOption(this, true, bubbleMode);
|
|
99
108
|
}
|
|
@@ -170,9 +179,8 @@ export class _CfgOptionInternal {
|
|
|
170
179
|
agg.push(...feature._internal._getFeaturesWithCode(code));
|
|
171
180
|
return agg;
|
|
172
181
|
}, []);
|
|
173
|
-
// Description based key helps when switching between
|
|
174
|
-
//
|
|
175
|
-
// to retain made selection
|
|
182
|
+
// Description based key helps when switching between products with similar feature-options
|
|
183
|
+
// tree and trying to retain made selection.
|
|
176
184
|
this.key =
|
|
177
185
|
this.description +
|
|
178
186
|
(this.description === "" || siblingHasDuplicateDescription ? this.code : "");
|
|
@@ -219,9 +227,9 @@ export class _CfgOptionInternal {
|
|
|
219
227
|
this._numericValue = val;
|
|
220
228
|
change = true;
|
|
221
229
|
}
|
|
222
|
-
// It could be that even though our value did not change some sibling value did, and
|
|
223
|
-
// could make it needed to bubble later. Maybe. A bit uncertain about why I did
|
|
224
|
-
// this in the if-statement above //Linus
|
|
230
|
+
// It could be that even though our value did not change some sibling value did, and
|
|
231
|
+
// this could make it needed to bubble later. Maybe. A bit uncertain about why I did
|
|
232
|
+
// not put this in the if-statement above //Linus
|
|
225
233
|
if (yield this.parent.pushStretch()) {
|
|
226
234
|
change = true;
|
|
227
235
|
}
|
|
@@ -248,6 +256,20 @@ export class _CfgOptionInternal {
|
|
|
248
256
|
get selected() {
|
|
249
257
|
return this.parent.isSelected(this);
|
|
250
258
|
}
|
|
259
|
+
get selectedChangeInProgress() {
|
|
260
|
+
const syncGroupHandler = this.rootProduct.syncGroupHandler;
|
|
261
|
+
if (syncGroupHandler === undefined) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
const inProgressOption = syncGroupHandler.pending;
|
|
265
|
+
if (inProgressOption === this) {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
if (!(this.selected && this.parent.selectionType === SelectionType.SelectOne)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
return this.parent.options.some((o) => o._internal === inProgressOption);
|
|
272
|
+
}
|
|
251
273
|
get ancestorsSelected() {
|
|
252
274
|
return this.selected && this.parent.ancestorsSelected;
|
|
253
275
|
}
|
|
@@ -320,13 +342,13 @@ export class CfgOption {
|
|
|
320
342
|
this.isBackedBySame = (other) => this._internal === other._internal;
|
|
321
343
|
this.setNumericValue = (val, doSelectOption) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setNumericValue(val, doSelectOption); });
|
|
322
344
|
this.isAllowedNumericValue = (val) => this._internal.isAllowedNumericValue(val);
|
|
323
|
-
|
|
345
|
+
/**
|
|
324
346
|
* Selects this Option.
|
|
325
347
|
* Only Options belonging to Features that are "select many" can be deselected.
|
|
326
348
|
* Calling this will cause a validation call to the server.
|
|
327
349
|
*/
|
|
328
350
|
this.setSelected = (on) => __awaiter(this, void 0, void 0, function* () {
|
|
329
|
-
return yield this._internal.parent.selectOption(this._internal, on, ProductConfigurationBubbleMode.
|
|
351
|
+
return yield this._internal.parent.selectOption(this._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
330
352
|
});
|
|
331
353
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
332
354
|
this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
|
|
@@ -375,6 +397,16 @@ export class CfgOption {
|
|
|
375
397
|
get selected() {
|
|
376
398
|
return this._internal.selected;
|
|
377
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Selection state is in progress to be changed. This can be used in GUI
|
|
402
|
+
* to display the state as transitioning, or as already changed.
|
|
403
|
+
* If selectedChangeInProgress and:
|
|
404
|
+
* selected is true, it means that this is about to get unselected
|
|
405
|
+
* selected is false, it means that this is about to get selected
|
|
406
|
+
*/
|
|
407
|
+
get selectedChangeInProgress() {
|
|
408
|
+
return this._internal.selectedChangeInProgress;
|
|
409
|
+
}
|
|
378
410
|
/** Are all ancestors up to the CfgProductConfiguration selected? Includes self. */
|
|
379
411
|
get ancestorsSelected() {
|
|
380
412
|
return this._internal.ancestorsSelected;
|
|
@@ -43,7 +43,7 @@ export declare class _CfgProductConfigurationInternal {
|
|
|
43
43
|
* outside we want notifications to bubble all the way to the root.
|
|
44
44
|
*/
|
|
45
45
|
setApiSelection: (selectedOptions: SelectedOption[], bubbleToRoot: boolean) => Promise<boolean>;
|
|
46
|
-
structureCompare: (other: _CfgProductConfigurationInternal, strictOrder
|
|
46
|
+
structureCompare: (other: _CfgProductConfigurationInternal, strictOrder: boolean, descriptionMatch: boolean) => boolean;
|
|
47
47
|
/**
|
|
48
48
|
* When used internally the notifications are taken care off by the caller, but if set from
|
|
49
49
|
* outside we want notifications to bubble all the way to the root.
|
|
@@ -74,7 +74,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
74
74
|
}
|
|
75
75
|
return change;
|
|
76
76
|
});
|
|
77
|
-
this.structureCompare = (other, strictOrder
|
|
77
|
+
this.structureCompare = (other, strictOrder, descriptionMatch) => compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
78
78
|
/**
|
|
79
79
|
* When used internally the notifications are taken care off by the caller, but if set from
|
|
80
80
|
* outside we want notifications to bubble all the way to the root.
|
|
@@ -129,7 +129,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
129
129
|
return false;
|
|
130
130
|
}
|
|
131
131
|
const stretchReferenceLengthsByMeasureParamCode = this.stretchReferenceLengthsByMeasureParamCode;
|
|
132
|
-
|
|
132
|
+
const stretchReferenceLength = stretchReferenceLengthsByMeasureParamCode.get(measureParamCode);
|
|
133
133
|
const referenceLengthWithUnit = {
|
|
134
134
|
length: referenceLength,
|
|
135
135
|
unit,
|
|
@@ -151,6 +151,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
151
151
|
}
|
|
152
152
|
return true;
|
|
153
153
|
});
|
|
154
|
+
/* eslint-disable */
|
|
154
155
|
// Useful debug tool:
|
|
155
156
|
if (false) {
|
|
156
157
|
const dbgName = `conf${parentProduct.refKey || parentProduct.key}`;
|
|
@@ -158,6 +159,7 @@ export class _CfgProductConfigurationInternal {
|
|
|
158
159
|
window.conf = this;
|
|
159
160
|
console.log(`Use "window['${dbgName}']" or window.conf to access conf.`);
|
|
160
161
|
}
|
|
162
|
+
/* eslint-enable */
|
|
161
163
|
/**
|
|
162
164
|
* Although the measurement-datas are also passed in validate-calls they are only used at
|
|
163
165
|
* initial product creation. The data is assumed to always be the same for a product, so
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { match, pick } from "@configura/web-utilities";
|
|
2
2
|
export function applyCatalogueFilters(filters, catalogues) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
const enterprise = match("enterprise", filters.enterprise, catalogues);
|
|
4
|
+
const prdCat = match("prdCat", filters.prdCat, enterprise.matching);
|
|
5
|
+
const prdCatVersion = match("prdCatVersion", filters.prdCatVersion, prdCat.matching);
|
|
6
|
+
const vendor = match("vendor", filters.vendor, prdCatVersion.matching);
|
|
7
|
+
const priceList = match("priceList", filters.priceList, vendor.matching);
|
|
8
8
|
let picked = pick(filters.enterprise, priceList.matching);
|
|
9
9
|
picked = pick(filters.prdCat, picked);
|
|
10
10
|
picked = pick(filters.prdCatVersion, picked);
|
|
@@ -48,9 +48,9 @@ export function cloneFilterSortLevels(levels, prdRefsFilter, showEmpty, doSort =
|
|
|
48
48
|
newPrdRefs = level.prdRefs.filter((prod) => prdRefsFilter.some((p) => p.partNr === prod.prdRef));
|
|
49
49
|
}
|
|
50
50
|
// add copy of level if not empty
|
|
51
|
-
|
|
51
|
+
const addPrdRefs = showEmpty || (newPrdRefs !== undefined && newPrdRefs.length > 0);
|
|
52
52
|
if (nextLevels !== undefined || addPrdRefs) {
|
|
53
|
-
|
|
53
|
+
const newLevel = {
|
|
54
54
|
code: level.code,
|
|
55
55
|
description: level.description,
|
|
56
56
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SyncGroupsApplyMode controls how many SyncGroups can be updated in the SyncState for one
|
|
3
|
+
* run of rootProductOntoSyncState.
|
|
4
|
+
*
|
|
5
|
+
* "Fast" will update any SyncGroup that should be updated before running syncStateOntoRootProduct
|
|
6
|
+
* This way several SyncGroups can be applied in one go before sending the validation calls to the * server, making the whole process faster.
|
|
7
|
+
*
|
|
8
|
+
* The downside of this is that is not exactly how CET (the desktop software) works. CET will
|
|
9
|
+
* instead apply Features to the SyncState as soon as it gets the chance.
|
|
10
|
+
*
|
|
11
|
+
* "Strict" tries to behave exactly as CET. This will potentially generate a lot more validate
|
|
12
|
+
* calls, increasing delay and cost.
|
|
13
|
+
*
|
|
14
|
+
* Strict is the safer option of the two, but we still recommend trying out Fast since it should
|
|
15
|
+
* work fine in most cases.
|
|
16
|
+
*/
|
|
17
|
+
export declare enum SyncGroupsApplyMode {
|
|
18
|
+
Strict = "Strict",
|
|
19
|
+
Fast = "Fast"
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=SyncGroupsApplyMode.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SyncGroupsApplyMode controls how many SyncGroups can be updated in the SyncState for one
|
|
3
|
+
* run of rootProductOntoSyncState.
|
|
4
|
+
*
|
|
5
|
+
* "Fast" will update any SyncGroup that should be updated before running syncStateOntoRootProduct
|
|
6
|
+
* This way several SyncGroups can be applied in one go before sending the validation calls to the * server, making the whole process faster.
|
|
7
|
+
*
|
|
8
|
+
* The downside of this is that is not exactly how CET (the desktop software) works. CET will
|
|
9
|
+
* instead apply Features to the SyncState as soon as it gets the chance.
|
|
10
|
+
*
|
|
11
|
+
* "Strict" tries to behave exactly as CET. This will potentially generate a lot more validate
|
|
12
|
+
* calls, increasing delay and cost.
|
|
13
|
+
*
|
|
14
|
+
* Strict is the safer option of the two, but we still recommend trying out Fast since it should
|
|
15
|
+
* work fine in most cases.
|
|
16
|
+
*/
|
|
17
|
+
export var SyncGroupsApplyMode;
|
|
18
|
+
(function (SyncGroupsApplyMode) {
|
|
19
|
+
SyncGroupsApplyMode["Strict"] = "Strict";
|
|
20
|
+
SyncGroupsApplyMode["Fast"] = "Fast";
|
|
21
|
+
})(SyncGroupsApplyMode || (SyncGroupsApplyMode = {}));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AggregatedLoadingObservable } from "@configura/web-utilities";
|
|
2
|
+
import { _CfgProductInternal } from "../CfgProduct.js";
|
|
3
|
+
import { _CfgOptionInternal } from "../productConfiguration/CfgOption.js";
|
|
4
|
+
import { ProductLoader } from "../productLoader.js";
|
|
5
|
+
import { SyncGroupsApplyMode } from "./SyncGroupsApplyMode.js";
|
|
6
|
+
import { SyncGroupsTransaction } from "./SyncGroupsTransaction.js";
|
|
7
|
+
export declare type SyncCode = string;
|
|
8
|
+
export declare type OptionCode = string;
|
|
9
|
+
/**
|
|
10
|
+
* Is used to apply the SyncGroups functionality on the Configuration and the other way around.
|
|
11
|
+
* It also keeps the SyncState.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SyncGroupsHandler {
|
|
14
|
+
private _syncState;
|
|
15
|
+
readonly updateMode: SyncGroupsApplyMode;
|
|
16
|
+
private readonly _loadingObservable;
|
|
17
|
+
private _currentTransaction;
|
|
18
|
+
/**
|
|
19
|
+
* @param verboseLogging Set to true to get verbose sync state changes logged to the console.
|
|
20
|
+
*/
|
|
21
|
+
static make(updateMode?: SyncGroupsApplyMode, loadingObservable?: AggregatedLoadingObservable, verboseLogging?: boolean): SyncGroupsHandler;
|
|
22
|
+
private constructor();
|
|
23
|
+
/** Please note that clones will use the same loadingObservable as their source. */
|
|
24
|
+
clone(): SyncGroupsHandler;
|
|
25
|
+
get verboseLogging(): boolean;
|
|
26
|
+
set verboseLogging(v: boolean);
|
|
27
|
+
/** Used to initially apply the sync state onto a new product so that it is "in sync". */
|
|
28
|
+
init(product: _CfgProductInternal, productLoader: ProductLoader): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Used when an Option is selected or deselected to apply all consequences of the sync groups.
|
|
31
|
+
* Can cause multiple extra validation calls to the server.
|
|
32
|
+
*/
|
|
33
|
+
selectOption(product: _CfgProductInternal, option: _CfgOptionInternal, on: boolean, productLoader: ProductLoader): Promise<boolean>;
|
|
34
|
+
private _pending;
|
|
35
|
+
private setPending;
|
|
36
|
+
get pending(): _CfgOptionInternal | undefined;
|
|
37
|
+
private newTransaction;
|
|
38
|
+
private closeTransaction;
|
|
39
|
+
commitTransaction(transaction: SyncGroupsTransaction): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=SyncGroupsHandler.d.ts.map
|