@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
package/dist/io/CfgIOManager.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
|
const CONFIGURA_ATTRIBUTE = "C0nf1gura";
|
|
11
2
|
const CONFIGURA_SHEBANG = "arug1fn0C";
|
|
12
3
|
// Support function. Did not manage to check both attribute and value in one step
|
|
@@ -90,7 +81,7 @@ export class CfgIOManager {
|
|
|
90
81
|
return a;
|
|
91
82
|
}, new Set());
|
|
92
83
|
const promises = [];
|
|
93
|
-
(() =>
|
|
84
|
+
(async () => {
|
|
94
85
|
for (const messageKey of allMessageKeys) {
|
|
95
86
|
if (!CfgIOManager.hasIOContainerMessageKey(data, messageKey)) {
|
|
96
87
|
continue;
|
|
@@ -104,7 +95,7 @@ export class CfgIOManager {
|
|
|
104
95
|
promises.push(item.l(message));
|
|
105
96
|
}
|
|
106
97
|
}
|
|
107
|
-
})
|
|
98
|
+
})();
|
|
108
99
|
Promise.all(promises)
|
|
109
100
|
.then(() => {
|
|
110
101
|
this._receiveInProgress = false;
|
|
@@ -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
|
var _a;
|
|
11
2
|
import { convertDtoProductConfToV1 } from "../utilitiesConfiguration.js";
|
|
12
3
|
export const isCfgProdConfMessage = (data) => typeof data === "object" && data !== null && "version" in data && "conf" in data;
|
|
@@ -31,8 +22,7 @@ export class CfgIOProdConfConnector {
|
|
|
31
22
|
this._includeInSend = _includeInSend;
|
|
32
23
|
this._stopListenToMessage = undefined;
|
|
33
24
|
this._stopListenToProdConf = undefined;
|
|
34
|
-
this.setProduct = (product) =>
|
|
35
|
-
var _b, _c;
|
|
25
|
+
this.setProduct = async (product) => {
|
|
36
26
|
const currentProduct = this._product;
|
|
37
27
|
const newProduct = product;
|
|
38
28
|
this._product = newProduct;
|
|
@@ -43,14 +33,14 @@ export class CfgIOProdConfConnector {
|
|
|
43
33
|
return;
|
|
44
34
|
}
|
|
45
35
|
if (currentProduct !== undefined) {
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
this._stopListenToMessage?.();
|
|
37
|
+
this._stopListenToProdConf?.();
|
|
48
38
|
}
|
|
49
39
|
if (newProduct === undefined) {
|
|
50
40
|
return;
|
|
51
41
|
}
|
|
52
42
|
this._send(this.makeSendData(newProduct.getDtoConf(this._includeInSend), true));
|
|
53
|
-
this._stopListenToMessage = CfgIOProdConfConnector.listenForMessage((messages) =>
|
|
43
|
+
this._stopListenToMessage = CfgIOProdConfConnector.listenForMessage(async (messages) => {
|
|
54
44
|
const subMessages = messages.subMessages;
|
|
55
45
|
if (subMessages.length === 0) {
|
|
56
46
|
console.warn(`${STAGE_PROD_CONF_MESSAGE_KEY} message without any submessages. Unexpected.`);
|
|
@@ -58,24 +48,23 @@ export class CfgIOProdConfConnector {
|
|
|
58
48
|
}
|
|
59
49
|
const highestVersionMessage = getHighestVersionProdConfMessage(subMessages);
|
|
60
50
|
if (isCfgProdConfMessageV1(highestVersionMessage)) {
|
|
61
|
-
|
|
51
|
+
await newProduct.setApiSelection(highestVersionMessage.conf);
|
|
62
52
|
return;
|
|
63
53
|
}
|
|
64
54
|
if (isCfgProdConfMessageV2(highestVersionMessage)) {
|
|
65
|
-
|
|
55
|
+
await newProduct.setDtoConf(highestVersionMessage.conf);
|
|
66
56
|
return;
|
|
67
57
|
}
|
|
68
58
|
throw new Error("Unknown message version");
|
|
69
|
-
}
|
|
70
|
-
this._stopListenToProdConf = CfgIOProdConfConnector.listenForProdConf(newProduct, (conf) =>
|
|
71
|
-
}
|
|
59
|
+
}, this._ioManager);
|
|
60
|
+
this._stopListenToProdConf = CfgIOProdConfConnector.listenForProdConf(newProduct, async (conf) => this._send(this.makeSendData(conf, false)), this._includeInSend);
|
|
61
|
+
};
|
|
72
62
|
this._send = (data) => this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, data);
|
|
73
63
|
_ioManager.addWarningSupplier(this);
|
|
74
64
|
}
|
|
75
65
|
destroy() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
(_c = this._stopListenToProdConf) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
66
|
+
this._stopListenToMessage?.();
|
|
67
|
+
this._stopListenToProdConf?.();
|
|
79
68
|
this._ioManager.removeWarningSupplier(this);
|
|
80
69
|
}
|
|
81
70
|
getWarnings() {
|
|
@@ -127,10 +116,10 @@ CfgIOProdConfConnector.makeMessage = (conf, initial, sendVersions) => {
|
|
|
127
116
|
}
|
|
128
117
|
return { subMessages: result, initial };
|
|
129
118
|
};
|
|
130
|
-
CfgIOProdConfConnector.makeMessageListener = (callback) => (message) =>
|
|
119
|
+
CfgIOProdConfConnector.makeMessageListener = (callback) => async (message) => {
|
|
131
120
|
const prodConfMessage = message;
|
|
132
|
-
|
|
133
|
-
}
|
|
121
|
+
await callback(prodConfMessage);
|
|
122
|
+
};
|
|
134
123
|
CfgIOProdConfConnector.makeProdConfListener = (callback, includeInSend) => (n) => {
|
|
135
124
|
if (!n.committed) {
|
|
136
125
|
return;
|
|
@@ -44,6 +44,7 @@ export declare class _CfgFeatureInternal {
|
|
|
44
44
|
private _options;
|
|
45
45
|
private readonly _selectedOptions;
|
|
46
46
|
private readonly _constrainedOptions;
|
|
47
|
+
private readonly _unresolvableOptions;
|
|
47
48
|
private _mtrlApplications;
|
|
48
49
|
readonly hasUpcharge: boolean;
|
|
49
50
|
readonly changeObservable: Observable<FeatureChangeNotification>;
|
|
@@ -126,6 +127,10 @@ export declare class _CfgFeatureInternal {
|
|
|
126
127
|
selectOption: (optionInternal: _CfgOptionInternal, on: boolean, bubbleMode: ProductConfigurationBubbleMode) => Promise<boolean>;
|
|
127
128
|
isSelected: (option: _CfgOptionInternal) => boolean;
|
|
128
129
|
isDisabled: (option: _CfgOptionInternal) => boolean;
|
|
130
|
+
/**
|
|
131
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
132
|
+
*/
|
|
133
|
+
isUnresolvable: (option: _CfgOptionInternal) => boolean;
|
|
129
134
|
keyMatch: (other: _CfgFeatureInternal, descriptionMatch?: boolean) => boolean;
|
|
130
135
|
/** Only in selected options */
|
|
131
136
|
_getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
|
|
@@ -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 { assertDefined, compareArrays, convertLength, count, Observable, someMatch, toLengthUnit, } from "@configura/web-utilities";
|
|
1
|
+
import { Observable, assertDefined, compareArrays, convertLength, count, someMatch, toLengthUnit, } 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";
|
|
@@ -73,8 +64,9 @@ export class _CfgFeatureInternal {
|
|
|
73
64
|
this.rootProduct = rootProduct;
|
|
74
65
|
this._selectedOptions = [];
|
|
75
66
|
this._constrainedOptions = [];
|
|
67
|
+
this._unresolvableOptions = [];
|
|
76
68
|
this.changeObservable = new Observable();
|
|
77
|
-
this.setNumericValue = (val) =>
|
|
69
|
+
this.setNumericValue = async (val) => {
|
|
78
70
|
if (this.selectionType !== SelectionType.SelectOne) {
|
|
79
71
|
throw new Error("Only SelectOne Features can have numeric values");
|
|
80
72
|
}
|
|
@@ -82,9 +74,9 @@ export class _CfgFeatureInternal {
|
|
|
82
74
|
if (option === undefined) {
|
|
83
75
|
throw new Error("No Option allows the value you tried to set");
|
|
84
76
|
}
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
this._notifyAllOfChange = (bubbleMode, committed) =>
|
|
77
|
+
return await option.setNumericValue(val, true);
|
|
78
|
+
};
|
|
79
|
+
this._notifyAllOfChange = async (bubbleMode, committed) => {
|
|
88
80
|
if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
|
|
89
81
|
return;
|
|
90
82
|
}
|
|
@@ -92,17 +84,17 @@ export class _CfgFeatureInternal {
|
|
|
92
84
|
this.changeObservable.notifyAll({ freshRef, committed });
|
|
93
85
|
const parent = this.parent;
|
|
94
86
|
if (parent !== undefined) {
|
|
95
|
-
|
|
87
|
+
await parent._childHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
|
|
96
88
|
? ProductConfigurationBubbleMode.Stop
|
|
97
89
|
: bubbleMode, committed);
|
|
98
90
|
}
|
|
99
|
-
}
|
|
91
|
+
};
|
|
100
92
|
/**
|
|
101
93
|
* Called by child to tell its parent that it has changed.
|
|
102
94
|
* @throws Will throw if options have not yet been generated. This should be impossible
|
|
103
95
|
* as nonexisting children can not call their parent.
|
|
104
96
|
*/
|
|
105
|
-
this._childHasChanged = (childOption, bubbleMode, committed) =>
|
|
97
|
+
this._childHasChanged = async (childOption, bubbleMode, committed) => {
|
|
106
98
|
const options = this._options;
|
|
107
99
|
if (options === undefined) {
|
|
108
100
|
throw Error("Child says it changed, but no children has actually been generated");
|
|
@@ -113,8 +105,8 @@ export class _CfgFeatureInternal {
|
|
|
113
105
|
if (i !== -1) {
|
|
114
106
|
selectedOptions[i] = freshRef;
|
|
115
107
|
}
|
|
116
|
-
|
|
117
|
-
}
|
|
108
|
+
await this._notifyAllOfChange(bubbleMode, committed);
|
|
109
|
+
};
|
|
118
110
|
// Keep in sync with stripExtendedDataFromDtoFeatureConf
|
|
119
111
|
this.getDtoConf = (includeExtendedData) => {
|
|
120
112
|
const result = {
|
|
@@ -136,8 +128,7 @@ export class _CfgFeatureInternal {
|
|
|
136
128
|
// way around. For that reason the get-method above uses the new format, and the set-method
|
|
137
129
|
// below the old format. As these functions are meant to only be used internally this should't
|
|
138
130
|
// cause too much confusion.
|
|
139
|
-
this.setApiSelection = (apiOptionSelectionMap, apiOptionConstraintMap) =>
|
|
140
|
-
var _a, _b;
|
|
131
|
+
this.setApiSelection = async (apiOptionSelectionMap, apiOptionConstraintMap) => {
|
|
141
132
|
const selectionType = this.selectionType;
|
|
142
133
|
const isGroup = selectionType === SelectionType.Group;
|
|
143
134
|
const isSelectOne = selectionType === SelectionType.SelectOne;
|
|
@@ -152,15 +143,21 @@ export class _CfgFeatureInternal {
|
|
|
152
143
|
options = this.options; // This will generate all children
|
|
153
144
|
}
|
|
154
145
|
let change = false;
|
|
155
|
-
const constraintMap = apiOptionConstraintMap
|
|
156
|
-
|
|
157
|
-
const
|
|
146
|
+
const constraintMap = apiOptionConstraintMap ?? {};
|
|
147
|
+
const { constrOptions = [], constrBooleans = [] } = Object.values(constraintMap).find(({ feature }) => feature === this.code) ?? {};
|
|
148
|
+
const optionalConstrainedOptions = constrBooleans.map(({ code }) => code);
|
|
149
|
+
const unresolvedConstrainedOptions = constrBooleans
|
|
150
|
+
.filter(({ value }) => value === undefined)
|
|
151
|
+
.map(({ code }) => code);
|
|
152
|
+
const featureConstrainedOptions = constrOptions.concat(optionalConstrainedOptions);
|
|
158
153
|
for (let i = 0; i < options.length; i++) {
|
|
159
154
|
const option = options[i];
|
|
160
155
|
const apiOptionSelection = apiOptionSelectionMap[option.code];
|
|
161
156
|
const isConstrained = featureConstrainedOptions.indexOf(option.code) >= 0;
|
|
157
|
+
const isUnresolvable = unresolvedConstrainedOptions.indexOf(option.code) >= 0;
|
|
162
158
|
const selectedIndex = this._selectedOptions.findIndex(getOptionFilter(option._internal));
|
|
163
159
|
const constrainedIndex = this._constrainedOptions.findIndex(getOptionFilter(option._internal));
|
|
160
|
+
const unresolvedIndex = this._unresolvableOptions.findIndex(getOptionFilter(option._internal));
|
|
164
161
|
const isOn = isGroup || apiOptionSelection;
|
|
165
162
|
if (isConstrained) {
|
|
166
163
|
if (constrainedIndex === -1) {
|
|
@@ -175,6 +172,19 @@ export class _CfgFeatureInternal {
|
|
|
175
172
|
change = true;
|
|
176
173
|
}
|
|
177
174
|
}
|
|
175
|
+
if (isUnresolvable) {
|
|
176
|
+
if (unresolvedIndex === -1) {
|
|
177
|
+
doFreshRefOptionAtIndex(options, i, committed, (freshRef) => this._unresolvableOptions.push(freshRef));
|
|
178
|
+
change = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (unresolvedIndex !== -1) {
|
|
183
|
+
this._unresolvableOptions.splice(unresolvedIndex, 1);
|
|
184
|
+
doFreshRefOptionAtIndex(options, i, committed);
|
|
185
|
+
change = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
178
188
|
if (isOn) {
|
|
179
189
|
if (isSelectOne) {
|
|
180
190
|
if (this.isUseNumericValue) {
|
|
@@ -183,7 +193,7 @@ export class _CfgFeatureInternal {
|
|
|
183
193
|
throw new Error("No numeric value for numeric feature");
|
|
184
194
|
}
|
|
185
195
|
const { value, unit } = numericValue;
|
|
186
|
-
if (
|
|
196
|
+
if (await option.setNumericValue(unit === undefined
|
|
187
197
|
? value
|
|
188
198
|
: convertLength(value, toLengthUnit(unit), this.unit), false)) {
|
|
189
199
|
change = true;
|
|
@@ -209,14 +219,14 @@ export class _CfgFeatureInternal {
|
|
|
209
219
|
change = true;
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
|
-
if (
|
|
222
|
+
if (await option._internal.setApiSelection(apiOptionSelection, constraintMap[option.code])) {
|
|
213
223
|
change = true;
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
if (this.ancestorsSelected) {
|
|
217
227
|
const selectionCount = this._selectedOptions.length;
|
|
218
228
|
if (isSelectOne && selectionCount !== 1) {
|
|
219
|
-
const wrongCountWarning = `A select-one Feature (i.e. neither optional nor multiple) should have exactly one Option selected. Feature
|
|
229
|
+
const wrongCountWarning = `A select-one Feature (i.e. neither optional nor multiple) should have exactly one Option selected. Feature code: "${this.code}". Actual: ${selectionCount}`;
|
|
220
230
|
if (this.rootProduct.settings.strictSelectOneSelectionCount) {
|
|
221
231
|
throw new Error(wrongCountWarning);
|
|
222
232
|
}
|
|
@@ -230,7 +240,7 @@ export class _CfgFeatureInternal {
|
|
|
230
240
|
this._freshRefAllOptions(committed);
|
|
231
241
|
}
|
|
232
242
|
if (selectionType === SelectionType.SelectOne) {
|
|
233
|
-
|
|
243
|
+
await this.pushStretch();
|
|
234
244
|
}
|
|
235
245
|
// setApiSelection works its way top down and handles notifications on
|
|
236
246
|
// each level by looking at change returned from its children. That way
|
|
@@ -238,10 +248,10 @@ export class _CfgFeatureInternal {
|
|
|
238
248
|
// if multiple descendants are affected by the setApiSelection. Therefore
|
|
239
249
|
// we use OneLevel to make this feature notify and the parent update its
|
|
240
250
|
// reference.
|
|
241
|
-
|
|
251
|
+
await this._notifyAllOfChange(ProductConfigurationBubbleMode.OneLevel, committed);
|
|
242
252
|
}
|
|
243
253
|
return change;
|
|
244
|
-
}
|
|
254
|
+
};
|
|
245
255
|
this.addForApiConstrained = (next) => {
|
|
246
256
|
const constrOptions = this._constrainedOptions;
|
|
247
257
|
for (const so of this._selectedOptions) {
|
|
@@ -249,16 +259,16 @@ export class _CfgFeatureInternal {
|
|
|
249
259
|
}
|
|
250
260
|
};
|
|
251
261
|
/** Pushes to refresh stretch. Does not cause validation. */
|
|
252
|
-
this.pushStretch = () =>
|
|
262
|
+
this.pushStretch = async () => {
|
|
253
263
|
if (this.selectionType !== SelectionType.SelectOne) {
|
|
254
264
|
throw new Error("Can only push stretch for SelectOne");
|
|
255
265
|
}
|
|
256
266
|
const value = this.numericValue;
|
|
257
|
-
return (
|
|
258
|
-
}
|
|
267
|
+
return (await Promise.all((this.measureParamCodes || []).map((measureParamCode) => this.parentConfiguration.setStretchReferenceLength(measureParamCode, value, this.unit)))).some((change) => change);
|
|
268
|
+
};
|
|
259
269
|
this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => this.keyMatch(other, descriptionMatch) &&
|
|
260
270
|
compareArrays(this.options, other.options, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
261
|
-
this.tryMatchSelection = (other, descriptionMatch = false) =>
|
|
271
|
+
this.tryMatchSelection = async (other, descriptionMatch = false) => {
|
|
262
272
|
const { selectionType, isUseNumericValue } = this;
|
|
263
273
|
if (selectionType !== other.selectionType) {
|
|
264
274
|
// Will not try if the selection type is different
|
|
@@ -276,7 +286,7 @@ export class _CfgFeatureInternal {
|
|
|
276
286
|
throw new Error("Numeric feature without numeric value, this should never happen");
|
|
277
287
|
}
|
|
278
288
|
else {
|
|
279
|
-
if (
|
|
289
|
+
if (await this.setNumericValue(otherNumericValue)) {
|
|
280
290
|
change = true;
|
|
281
291
|
}
|
|
282
292
|
}
|
|
@@ -284,7 +294,7 @@ export class _CfgFeatureInternal {
|
|
|
284
294
|
else {
|
|
285
295
|
const thisOptions = this.options;
|
|
286
296
|
const otherOptions = other.options;
|
|
287
|
-
change = (
|
|
297
|
+
change = (await Promise.all(otherOptions.map((otherO) => (async () => {
|
|
288
298
|
const otherOSelected = otherO.selected;
|
|
289
299
|
if (selectionType === SelectionType.SelectOne && !otherOSelected) {
|
|
290
300
|
return false;
|
|
@@ -310,14 +320,14 @@ export class _CfgFeatureInternal {
|
|
|
310
320
|
// so we do not need to bubble the notification.
|
|
311
321
|
// Instead we use the change variable to know
|
|
312
322
|
// when to notify for this feature.
|
|
313
|
-
change =
|
|
323
|
+
change = await toTryChangeOption._internal.parent.selectOption(toTryChangeOption._internal, otherOSelected, ProductConfigurationBubbleMode.Stop);
|
|
314
324
|
}
|
|
315
325
|
if (otherOSelected &&
|
|
316
|
-
(
|
|
326
|
+
(await toTryChangeOption._internal.tryMatchSelection(otherO, descriptionMatch))) {
|
|
317
327
|
change = true;
|
|
318
328
|
}
|
|
319
329
|
return change;
|
|
320
|
-
})
|
|
330
|
+
})()))).some((b) => b);
|
|
321
331
|
}
|
|
322
332
|
if (change) {
|
|
323
333
|
// tryMatchSelection works its way top down and handles notifications on
|
|
@@ -326,23 +336,23 @@ export class _CfgFeatureInternal {
|
|
|
326
336
|
// if multiple descendants are affected by the tryMatchSelection. Therefore
|
|
327
337
|
// we use OneLevel to make this feature notify and the parent update its
|
|
328
338
|
// reference.
|
|
329
|
-
|
|
339
|
+
await this._notifyAllOfChange(ProductConfigurationBubbleMode.OneLevel, true);
|
|
330
340
|
}
|
|
331
341
|
return change;
|
|
332
|
-
}
|
|
342
|
+
};
|
|
333
343
|
/**
|
|
334
344
|
* Normally this is used through methods on CfgFeature and CfgOption. Use this internal version
|
|
335
345
|
* if you need to control the bubbleMode.
|
|
336
346
|
*
|
|
337
347
|
* Using a validate bubbleMode will cause validation calls to the server.
|
|
338
348
|
*/
|
|
339
|
-
this.selectOption = (optionInternal, on, bubbleMode) =>
|
|
349
|
+
this.selectOption = async (optionInternal, on, bubbleMode) => {
|
|
340
350
|
if (bubbleMode ===
|
|
341
351
|
ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups) {
|
|
342
352
|
const product = this.rootProduct;
|
|
343
353
|
const syncGroupHandler = product.syncGroupHandler;
|
|
344
354
|
assertDefined(syncGroupHandler, `Sync group handler is required for bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
|
|
345
|
-
return
|
|
355
|
+
return await syncGroupHandler.selectOption(product, optionInternal, on, wrapWithCache(product._productLoaderRaw));
|
|
346
356
|
}
|
|
347
357
|
if (!on) {
|
|
348
358
|
if (this.selectionType === SelectionType.Group) {
|
|
@@ -378,7 +388,7 @@ export class _CfgFeatureInternal {
|
|
|
378
388
|
doFreshRefOption(options, optionInternal, committed, (freshRef) => selectedOptions.push(freshRef));
|
|
379
389
|
}
|
|
380
390
|
if (this.selectionType === SelectionType.SelectOne) {
|
|
381
|
-
|
|
391
|
+
await this.pushStretch();
|
|
382
392
|
}
|
|
383
393
|
}
|
|
384
394
|
else {
|
|
@@ -409,12 +419,16 @@ export class _CfgFeatureInternal {
|
|
|
409
419
|
nextLevelBubbleMode = ProductConfigurationBubbleMode.ToRoot;
|
|
410
420
|
}
|
|
411
421
|
}
|
|
412
|
-
|
|
422
|
+
await this._notifyAllOfChange(nextLevelBubbleMode, committed);
|
|
413
423
|
return isActualChange;
|
|
414
|
-
}
|
|
424
|
+
};
|
|
415
425
|
this.isSelected = (option) => this.selectionType === SelectionType.Group ||
|
|
416
426
|
this._selectedOptions.some(getOptionFilter(option));
|
|
417
427
|
this.isDisabled = (option) => this._constrainedOptions.some(getOptionFilter(option));
|
|
428
|
+
/**
|
|
429
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
430
|
+
*/
|
|
431
|
+
this.isUnresolvable = (option) => this._unresolvableOptions.some(getOptionFilter(option));
|
|
418
432
|
this.keyMatch = (other, descriptionMatch = false) => descriptionMatch
|
|
419
433
|
? this.description.toLowerCase() === other.description.toLowerCase()
|
|
420
434
|
: this.code === other.code;
|
|
@@ -448,8 +462,7 @@ export class _CfgFeatureInternal {
|
|
|
448
462
|
this._key = k;
|
|
449
463
|
}
|
|
450
464
|
get notes() {
|
|
451
|
-
|
|
452
|
-
return this.parentProduct.getNotes((_a = this.rawFeature.noteRefs) !== null && _a !== void 0 ? _a : []);
|
|
465
|
+
return this.parentProduct.getNotes(this.rawFeature.noteRefs ?? []);
|
|
453
466
|
}
|
|
454
467
|
get isUseNumericValue() {
|
|
455
468
|
return this.rawFeature.numericOrder;
|
|
@@ -502,8 +515,7 @@ export class _CfgFeatureInternal {
|
|
|
502
515
|
* of this Feature. Hence only the code property is used.
|
|
503
516
|
*/
|
|
504
517
|
get measureParamCodes() {
|
|
505
|
-
|
|
506
|
-
return (_a = this.rawFeature.measureParams) === null || _a === void 0 ? void 0 : _a.map((measureParam) => measureParam.code);
|
|
518
|
+
return this.rawFeature.measureParams?.map((measureParam) => measureParam.code);
|
|
507
519
|
}
|
|
508
520
|
get unit() {
|
|
509
521
|
const unit = this.rawFeature.unit;
|
|
@@ -597,15 +609,13 @@ export class CfgFeature {
|
|
|
597
609
|
* This will find the first option allowing the value, set the value on it and select it.
|
|
598
610
|
* This is an implicit option-select.
|
|
599
611
|
*/
|
|
600
|
-
this.setNumericValue = (val) =>
|
|
612
|
+
this.setNumericValue = async (val) => await this._internal.setNumericValue(val);
|
|
601
613
|
/**
|
|
602
614
|
* Selects the passed Option.
|
|
603
615
|
* Only Options belonging to Features that are "select many" can be deselected.
|
|
604
616
|
* Calling this will cause a validation call to the server.
|
|
605
617
|
*/
|
|
606
|
-
this.selectOption = (option, on) =>
|
|
607
|
-
return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
608
|
-
});
|
|
618
|
+
this.selectOption = async (option, on) => await this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
609
619
|
this.isSelected = (option) => this._internal.isSelected(option._internal);
|
|
610
620
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
611
621
|
this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
|
|
@@ -84,6 +84,10 @@ export declare class _CfgOptionInternal {
|
|
|
84
84
|
get description(): string;
|
|
85
85
|
get selected(): boolean;
|
|
86
86
|
get disabled(): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
89
|
+
*/
|
|
90
|
+
get unresolvable(): boolean;
|
|
87
91
|
get selectedChangeInProgress(): boolean;
|
|
88
92
|
get ancestorsSelected(): boolean;
|
|
89
93
|
get mtrlApplications(): CfgMtrlApplication[];
|
|
@@ -91,6 +95,24 @@ export declare class _CfgOptionInternal {
|
|
|
91
95
|
private _calculateUpcharge;
|
|
92
96
|
get upcharge(): number;
|
|
93
97
|
get priceChangeAtSelectChange(): number;
|
|
98
|
+
/**
|
|
99
|
+
* Get the child features that are contained within this option.
|
|
100
|
+
*
|
|
101
|
+
* Safe to call outside of the sync process, but may not contain any
|
|
102
|
+
* children until the sync process is complete.
|
|
103
|
+
*/
|
|
104
|
+
getFeaturesOutsideSync(): CfgFeature[];
|
|
105
|
+
/**
|
|
106
|
+
* Get the child features that are contained within this option.
|
|
107
|
+
*
|
|
108
|
+
* ONLY ACCESS THIS PROPERTY UNDER THESE CONDITIONS:
|
|
109
|
+
* 1. The product is undergoing the sync group sync process.
|
|
110
|
+
* 2. AND you are operating on the new "target" product.
|
|
111
|
+
*
|
|
112
|
+
* Explanation: This method will generate all children if they have not been
|
|
113
|
+
* generated yet, which breaks sync group syncing, due to the presence of
|
|
114
|
+
* these children being used to determine if the sync should happen at all.
|
|
115
|
+
*/
|
|
94
116
|
get features(): CfgFeature[];
|
|
95
117
|
/** Called by child to tell its parent that it has changed. */
|
|
96
118
|
_childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
|
|
@@ -135,6 +157,10 @@ export declare class CfgOption {
|
|
|
135
157
|
get description(): string;
|
|
136
158
|
get selected(): boolean;
|
|
137
159
|
get disabled(): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
162
|
+
*/
|
|
163
|
+
get unresolvable(): boolean;
|
|
138
164
|
/**
|
|
139
165
|
* Selection state is in progress to be changed. This can be used in GUI
|
|
140
166
|
* to display the state as transitioning, or as already changed.
|
|
@@ -154,6 +180,24 @@ export declare class CfgOption {
|
|
|
154
180
|
get thumbnail(): string | undefined;
|
|
155
181
|
get upcharge(): number;
|
|
156
182
|
get priceChangeAtSelectChange(): number;
|
|
183
|
+
/**
|
|
184
|
+
* Get the child features that are contained within this option.
|
|
185
|
+
*
|
|
186
|
+
* Safe to call outside of the sync process, but may not contain any
|
|
187
|
+
* children until the sync process is complete.
|
|
188
|
+
*/
|
|
189
|
+
getFeaturesOutsideSync(): CfgFeature[];
|
|
190
|
+
/**
|
|
191
|
+
* Get the child features that are contained within this option.
|
|
192
|
+
*
|
|
193
|
+
* ONLY ACCESS THIS PROPERTY UNDER THESE CONDITIONS:
|
|
194
|
+
* 1. The product is undergoing the sync group sync process.
|
|
195
|
+
* 2. AND you are operating on the new "target" product.
|
|
196
|
+
*
|
|
197
|
+
* Explanation: This method will generate all children if they have not been
|
|
198
|
+
* generated yet, which breaks sync group syncing, due to the presence of
|
|
199
|
+
* these children being used to determine if the sync should happen at all.
|
|
200
|
+
*/
|
|
157
201
|
get features(): CfgFeature[];
|
|
158
202
|
listenForChange: (l: SingleArgCallback<OptionChangeNotification>) => void;
|
|
159
203
|
stopListenForChange: (l: SingleArgCallback<OptionChangeNotification>) => void;
|