@configura/web-api 3.0.0-alpha.1 → 3.0.0-alpha.3
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.d.ts +22 -3
- package/dist/CfgProduct.js +172 -162
- 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 +68 -53
- package/dist/productConfiguration/CfgOption.d.ts +8 -0
- package/dist/productConfiguration/CfgOption.js +68 -73
- 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.d.ts +19 -1
- package/dist/syncGroups/SyncGroupsTransaction.js +352 -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 { Observable, assertDefined, compareArrays, convertLength, count, someMatch, toLengthUnit, } from "@configura/web-utilities";
|
|
1
|
+
import { assertDefined, compareArrays, convertLength, count, Observable, 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,12 +193,17 @@ 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;
|
|
190
200
|
}
|
|
191
201
|
}
|
|
202
|
+
// Triggers `pushStretch` when it is a stretch feature
|
|
203
|
+
// Fixes https://configura.atlassian.net/browse/WEB-16599
|
|
204
|
+
if (this.measureParamCodes?.length) {
|
|
205
|
+
change = true;
|
|
206
|
+
}
|
|
192
207
|
}
|
|
193
208
|
if (selectedIndex === -1) {
|
|
194
209
|
if (isAllOptionsAffectedByAnySelection) {
|
|
@@ -209,7 +224,7 @@ export class _CfgFeatureInternal {
|
|
|
209
224
|
change = true;
|
|
210
225
|
}
|
|
211
226
|
}
|
|
212
|
-
if (
|
|
227
|
+
if (await option._internal.setApiSelection(apiOptionSelection, constraintMap[option.code])) {
|
|
213
228
|
change = true;
|
|
214
229
|
}
|
|
215
230
|
}
|
|
@@ -230,7 +245,7 @@ export class _CfgFeatureInternal {
|
|
|
230
245
|
this._freshRefAllOptions(committed);
|
|
231
246
|
}
|
|
232
247
|
if (selectionType === SelectionType.SelectOne) {
|
|
233
|
-
|
|
248
|
+
await this.pushStretch();
|
|
234
249
|
}
|
|
235
250
|
// setApiSelection works its way top down and handles notifications on
|
|
236
251
|
// each level by looking at change returned from its children. That way
|
|
@@ -238,10 +253,10 @@ export class _CfgFeatureInternal {
|
|
|
238
253
|
// if multiple descendants are affected by the setApiSelection. Therefore
|
|
239
254
|
// we use OneLevel to make this feature notify and the parent update its
|
|
240
255
|
// reference.
|
|
241
|
-
|
|
256
|
+
await this._notifyAllOfChange(ProductConfigurationBubbleMode.OneLevel, committed);
|
|
242
257
|
}
|
|
243
258
|
return change;
|
|
244
|
-
}
|
|
259
|
+
};
|
|
245
260
|
this.addForApiConstrained = (next) => {
|
|
246
261
|
const constrOptions = this._constrainedOptions;
|
|
247
262
|
for (const so of this._selectedOptions) {
|
|
@@ -249,16 +264,16 @@ export class _CfgFeatureInternal {
|
|
|
249
264
|
}
|
|
250
265
|
};
|
|
251
266
|
/** Pushes to refresh stretch. Does not cause validation. */
|
|
252
|
-
this.pushStretch = () =>
|
|
267
|
+
this.pushStretch = async () => {
|
|
253
268
|
if (this.selectionType !== SelectionType.SelectOne) {
|
|
254
269
|
throw new Error("Can only push stretch for SelectOne");
|
|
255
270
|
}
|
|
256
271
|
const value = this.numericValue;
|
|
257
|
-
return (
|
|
258
|
-
}
|
|
272
|
+
return (await Promise.all((this.measureParamCodes || []).map((measureParamCode) => this.parentConfiguration.setStretchReferenceLength(measureParamCode, value, this.unit)))).some((change) => change);
|
|
273
|
+
};
|
|
259
274
|
this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => this.keyMatch(other, descriptionMatch) &&
|
|
260
275
|
compareArrays(this.options, other.options, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
261
|
-
this.tryMatchSelection = (other, descriptionMatch = false) =>
|
|
276
|
+
this.tryMatchSelection = async (other, descriptionMatch = false) => {
|
|
262
277
|
const { selectionType, isUseNumericValue } = this;
|
|
263
278
|
if (selectionType !== other.selectionType) {
|
|
264
279
|
// Will not try if the selection type is different
|
|
@@ -276,7 +291,7 @@ export class _CfgFeatureInternal {
|
|
|
276
291
|
throw new Error("Numeric feature without numeric value, this should never happen");
|
|
277
292
|
}
|
|
278
293
|
else {
|
|
279
|
-
if (
|
|
294
|
+
if (await this.setNumericValue(otherNumericValue)) {
|
|
280
295
|
change = true;
|
|
281
296
|
}
|
|
282
297
|
}
|
|
@@ -284,7 +299,7 @@ export class _CfgFeatureInternal {
|
|
|
284
299
|
else {
|
|
285
300
|
const thisOptions = this.options;
|
|
286
301
|
const otherOptions = other.options;
|
|
287
|
-
change = (
|
|
302
|
+
change = (await Promise.all(otherOptions.map((otherO) => (async () => {
|
|
288
303
|
const otherOSelected = otherO.selected;
|
|
289
304
|
if (selectionType === SelectionType.SelectOne && !otherOSelected) {
|
|
290
305
|
return false;
|
|
@@ -310,14 +325,14 @@ export class _CfgFeatureInternal {
|
|
|
310
325
|
// so we do not need to bubble the notification.
|
|
311
326
|
// Instead we use the change variable to know
|
|
312
327
|
// when to notify for this feature.
|
|
313
|
-
change =
|
|
328
|
+
change = await toTryChangeOption._internal.parent.selectOption(toTryChangeOption._internal, otherOSelected, ProductConfigurationBubbleMode.Stop);
|
|
314
329
|
}
|
|
315
330
|
if (otherOSelected &&
|
|
316
|
-
(
|
|
331
|
+
(await toTryChangeOption._internal.tryMatchSelection(otherO, descriptionMatch))) {
|
|
317
332
|
change = true;
|
|
318
333
|
}
|
|
319
334
|
return change;
|
|
320
|
-
})
|
|
335
|
+
})()))).some((b) => b);
|
|
321
336
|
}
|
|
322
337
|
if (change) {
|
|
323
338
|
// tryMatchSelection works its way top down and handles notifications on
|
|
@@ -326,23 +341,23 @@ export class _CfgFeatureInternal {
|
|
|
326
341
|
// if multiple descendants are affected by the tryMatchSelection. Therefore
|
|
327
342
|
// we use OneLevel to make this feature notify and the parent update its
|
|
328
343
|
// reference.
|
|
329
|
-
|
|
344
|
+
await this._notifyAllOfChange(ProductConfigurationBubbleMode.OneLevel, true);
|
|
330
345
|
}
|
|
331
346
|
return change;
|
|
332
|
-
}
|
|
347
|
+
};
|
|
333
348
|
/**
|
|
334
349
|
* Normally this is used through methods on CfgFeature and CfgOption. Use this internal version
|
|
335
350
|
* if you need to control the bubbleMode.
|
|
336
351
|
*
|
|
337
352
|
* Using a validate bubbleMode will cause validation calls to the server.
|
|
338
353
|
*/
|
|
339
|
-
this.selectOption = (optionInternal, on, bubbleMode) =>
|
|
354
|
+
this.selectOption = async (optionInternal, on, bubbleMode) => {
|
|
340
355
|
if (bubbleMode ===
|
|
341
356
|
ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups) {
|
|
342
357
|
const product = this.rootProduct;
|
|
343
358
|
const syncGroupHandler = product.syncGroupHandler;
|
|
344
359
|
assertDefined(syncGroupHandler, `Sync group handler is required for bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
|
|
345
|
-
return
|
|
360
|
+
return await syncGroupHandler.selectOption(product, optionInternal, on, wrapWithCache(product._productLoaderRaw));
|
|
346
361
|
}
|
|
347
362
|
if (!on) {
|
|
348
363
|
if (this.selectionType === SelectionType.Group) {
|
|
@@ -378,7 +393,7 @@ export class _CfgFeatureInternal {
|
|
|
378
393
|
doFreshRefOption(options, optionInternal, committed, (freshRef) => selectedOptions.push(freshRef));
|
|
379
394
|
}
|
|
380
395
|
if (this.selectionType === SelectionType.SelectOne) {
|
|
381
|
-
|
|
396
|
+
await this.pushStretch();
|
|
382
397
|
}
|
|
383
398
|
}
|
|
384
399
|
else {
|
|
@@ -409,12 +424,16 @@ export class _CfgFeatureInternal {
|
|
|
409
424
|
nextLevelBubbleMode = ProductConfigurationBubbleMode.ToRoot;
|
|
410
425
|
}
|
|
411
426
|
}
|
|
412
|
-
|
|
427
|
+
await this._notifyAllOfChange(nextLevelBubbleMode, committed);
|
|
413
428
|
return isActualChange;
|
|
414
|
-
}
|
|
429
|
+
};
|
|
415
430
|
this.isSelected = (option) => this.selectionType === SelectionType.Group ||
|
|
416
431
|
this._selectedOptions.some(getOptionFilter(option));
|
|
417
432
|
this.isDisabled = (option) => this._constrainedOptions.some(getOptionFilter(option));
|
|
433
|
+
/**
|
|
434
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
435
|
+
*/
|
|
436
|
+
this.isUnresolvable = (option) => this._unresolvableOptions.some(getOptionFilter(option));
|
|
418
437
|
this.keyMatch = (other, descriptionMatch = false) => descriptionMatch
|
|
419
438
|
? this.description.toLowerCase() === other.description.toLowerCase()
|
|
420
439
|
: this.code === other.code;
|
|
@@ -448,8 +467,7 @@ export class _CfgFeatureInternal {
|
|
|
448
467
|
this._key = k;
|
|
449
468
|
}
|
|
450
469
|
get notes() {
|
|
451
|
-
|
|
452
|
-
return this.parentProduct.getNotes((_a = this.rawFeature.noteRefs) !== null && _a !== void 0 ? _a : []);
|
|
470
|
+
return this.parentProduct.getNotes(this.rawFeature.noteRefs ?? []);
|
|
453
471
|
}
|
|
454
472
|
get isUseNumericValue() {
|
|
455
473
|
return this.rawFeature.numericOrder;
|
|
@@ -502,8 +520,7 @@ export class _CfgFeatureInternal {
|
|
|
502
520
|
* of this Feature. Hence only the code property is used.
|
|
503
521
|
*/
|
|
504
522
|
get measureParamCodes() {
|
|
505
|
-
|
|
506
|
-
return (_a = this.rawFeature.measureParams) === null || _a === void 0 ? void 0 : _a.map((measureParam) => measureParam.code);
|
|
523
|
+
return this.rawFeature.measureParams?.map((measureParam) => measureParam.code);
|
|
507
524
|
}
|
|
508
525
|
get unit() {
|
|
509
526
|
const unit = this.rawFeature.unit;
|
|
@@ -597,15 +614,13 @@ export class CfgFeature {
|
|
|
597
614
|
* This will find the first option allowing the value, set the value on it and select it.
|
|
598
615
|
* This is an implicit option-select.
|
|
599
616
|
*/
|
|
600
|
-
this.setNumericValue = (val) =>
|
|
617
|
+
this.setNumericValue = async (val) => await this._internal.setNumericValue(val);
|
|
601
618
|
/**
|
|
602
619
|
* Selects the passed Option.
|
|
603
620
|
* Only Options belonging to Features that are "select many" can be deselected.
|
|
604
621
|
* Calling this will cause a validation call to the server.
|
|
605
622
|
*/
|
|
606
|
-
this.selectOption = (option, on) =>
|
|
607
|
-
return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
608
|
-
});
|
|
623
|
+
this.selectOption = async (option, on) => await this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
|
|
609
624
|
this.isSelected = (option) => this._internal.isSelected(option._internal);
|
|
610
625
|
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
611
626
|
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[];
|
|
@@ -153,6 +157,10 @@ export declare class CfgOption {
|
|
|
153
157
|
get description(): string;
|
|
154
158
|
get selected(): boolean;
|
|
155
159
|
get disabled(): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* An option is unresolvable when it is constrained from any possible value.
|
|
162
|
+
*/
|
|
163
|
+
get unresolvable(): boolean;
|
|
156
164
|
/**
|
|
157
165
|
* Selection state is in progress to be changed. This can be used in GUI
|
|
158
166
|
* to display the state as transitioning, or as already changed.
|