@configura/web-api 2.0.0-alpha.9 → 2.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -14
- package/dist/CatalogueAPI.d.ts +103 -32
- package/dist/CatalogueAPI.js +62 -6
- package/dist/CfgProduct.d.ts +90 -14
- package/dist/CfgProduct.js +266 -56
- package/dist/CfgReferencePathHelper.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/io/CfgHistoryManager.d.ts +33 -1
- package/dist/io/CfgHistoryManager.js +68 -6
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +11 -10
- package/dist/io/CfgHistoryToProdConfConnector.js +32 -38
- package/dist/io/CfgIOManager.d.ts +5 -0
- package/dist/io/CfgIOManager.js +20 -1
- package/dist/io/CfgIOProdConfConnector.d.ts +17 -18
- package/dist/io/CfgIOProdConfConnector.js +52 -58
- package/dist/io/CfgIOWarningSupplier.d.ts +4 -0
- package/dist/io/CfgIOWarningSupplier.js +1 -0
- package/dist/io/CfgObservableStateToProdConfConnector.d.ts +4 -4
- package/dist/io/CfgObservableStateToProdConfConnector.js +3 -3
- package/dist/io/CfgWindowMessageManager.js +4 -0
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +4 -4
- package/dist/io/CfgWindowMessageToProdConfConnector.js +3 -3
- package/dist/productConfiguration/CfgFeature.d.ts +12 -7
- package/dist/productConfiguration/CfgFeature.js +33 -14
- package/dist/productConfiguration/CfgOption.d.ts +16 -10
- package/dist/productConfiguration/CfgOption.js +46 -18
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +27 -16
- package/dist/productConfiguration/CfgProductConfiguration.js +53 -29
- package/dist/productConfiguration/filters.d.ts +6 -4
- package/dist/productConfiguration/filters.js +94 -23
- package/dist/productConfiguration/productParamsGenerator.d.ts +3 -3
- package/dist/productConfiguration/utilitiesProductConfiguration.d.ts +1 -1
- package/dist/productConfiguration/utilitiesProductConfiguration.js +11 -4
- package/dist/productLoader.d.ts +3 -3
- package/dist/productLoader.js +1 -1
- package/dist/syncGroups/SyncGroupsHandler.d.ts +9 -2
- package/dist/syncGroups/SyncGroupsHandler.js +15 -4
- package/dist/syncGroups/SyncGroupsState.d.ts +5 -1
- package/dist/syncGroups/SyncGroupsState.js +44 -2
- package/dist/syncGroups/SyncGroupsTransaction.js +34 -21
- package/dist/tasks/TaskHandler.d.ts +2 -2
- package/dist/tasks/TaskHandler.js +2 -1
- package/dist/tests/testData/dummyProductForTest.d.ts +2 -2
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +14 -9
- package/dist/tests/testData/testDataCachedGetProduct.js +2 -0
- package/dist/tests/testData/testDataCachedPostValidate.js +2 -0
- package/dist/tests/testData/testDataProductAggregatedPrice.js +3 -1
- package/dist/tests/testData/testDataUpcharge.js +2 -0
- package/dist/utilitiesCatalogueData.d.ts +14 -9
- package/dist/utilitiesCatalogueData.js +7 -0
- package/dist/utilitiesCataloguePermission.d.ts +4 -4
- package/dist/utilitiesConfiguration.d.ts +29 -0
- package/dist/utilitiesConfiguration.js +200 -0
- package/dist/utilitiesNumericValues.js +13 -8
- package/package.json +3 -3
- package/dist/ConfigurationConverter.d.ts +0 -5
- package/dist/ConfigurationConverter.js +0 -72
|
@@ -9,8 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { compareArrays, count, isEqualLength, isLengthUnit, Observable, toError, toLengthUnit, } from "@configura/web-utilities";
|
|
11
11
|
import { CfgProduct } from "../CfgProduct.js";
|
|
12
|
-
import {
|
|
13
|
-
import { CfgFeature } from "./CfgFeature.js";
|
|
12
|
+
import { convertDtoFeatureConfsToSelOptions } from "../utilitiesConfiguration.js";
|
|
14
13
|
import { ProductConfigurationBubbleMode } from "./CfgOption.js";
|
|
15
14
|
import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
|
|
16
15
|
/**
|
|
@@ -19,13 +18,13 @@ import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
|
|
|
19
18
|
* modified. CfgProductConfiguration is the class that should be used and interacted with.
|
|
20
19
|
*/
|
|
21
20
|
export class _CfgProductConfigurationInternal {
|
|
22
|
-
constructor(
|
|
23
|
-
parentProduct, rootProduct) {
|
|
24
|
-
this.allRawFeatures = allRawFeatures;
|
|
21
|
+
constructor(rawFeatures, parentProduct, rootProduct, _initialRootFeatureRefs) {
|
|
25
22
|
this.parentProduct = parentProduct;
|
|
26
23
|
this.rootProduct = rootProduct;
|
|
24
|
+
this._initialRootFeatureRefs = _initialRootFeatureRefs;
|
|
27
25
|
this.key = "~";
|
|
28
26
|
this._rootFeatureRefs = [];
|
|
27
|
+
this.accumulatedRawFeatures = []; // Flat packed. May be extended in validate calls.
|
|
29
28
|
this._features = [];
|
|
30
29
|
this.changeObservable = new Observable();
|
|
31
30
|
this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -56,9 +55,11 @@ export class _CfgProductConfigurationInternal {
|
|
|
56
55
|
yield this._notifyAllOfChange(bubbleMode, committed);
|
|
57
56
|
});
|
|
58
57
|
this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
|
|
58
|
+
this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
|
|
59
59
|
/**
|
|
60
60
|
* When used internally the notifications are taken care off by the caller, but if set from
|
|
61
61
|
* outside we want notifications to bubble all the way to the root.
|
|
62
|
+
* This method will not cause validation calls. Data is assumed to already be validated.
|
|
62
63
|
*/
|
|
63
64
|
this.setApiSelection = (selectedOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
|
|
64
65
|
const featuresLength = this._features.length;
|
|
@@ -111,9 +112,39 @@ export class _CfgProductConfigurationInternal {
|
|
|
111
112
|
agg.push(...feature._internal._getFeaturesWithCode(code));
|
|
112
113
|
return agg;
|
|
113
114
|
}, []);
|
|
115
|
+
/**
|
|
116
|
+
* Extends the list of loaded potentially used features. Will warn for but ignore duplicates.
|
|
117
|
+
* Returns true if a change happened.
|
|
118
|
+
*/
|
|
119
|
+
this.addRawFeatures = (rawFeatures, warnForDuplicates) => {
|
|
120
|
+
let change = false;
|
|
121
|
+
const accumulatedRawFeatures = this.accumulatedRawFeatures;
|
|
122
|
+
for (const rawFeature of rawFeatures) {
|
|
123
|
+
const code = rawFeature.code;
|
|
124
|
+
if (accumulatedRawFeatures.find((f) => code === f.code)) {
|
|
125
|
+
if (warnForDuplicates) {
|
|
126
|
+
console.warn(`Feature ${code} was already loaded. Will ignore it.`);
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
accumulatedRawFeatures.push(rawFeature);
|
|
131
|
+
change = true;
|
|
132
|
+
}
|
|
133
|
+
return change;
|
|
134
|
+
};
|
|
135
|
+
this._hasRootFeaturesChanged = false;
|
|
136
|
+
/**
|
|
137
|
+
* Populates _features based on the passed @param rootFeatureRefs .
|
|
138
|
+
* @return true if a change happened.
|
|
139
|
+
*/
|
|
114
140
|
this.populateFeatures = (rootFeatureRefs) => {
|
|
141
|
+
if (compareArrays(this._rootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code, true)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
115
144
|
this._rootFeatureRefs = rootFeatureRefs;
|
|
116
|
-
this.
|
|
145
|
+
this._hasRootFeaturesChanged = !compareArrays(this._initialRootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code);
|
|
146
|
+
this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.accumulatedRawFeatures, this, this, this.parentProduct, this.rootProduct);
|
|
147
|
+
return true;
|
|
117
148
|
};
|
|
118
149
|
this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
|
|
119
150
|
if (measureParamCode === "") {
|
|
@@ -158,6 +189,8 @@ export class _CfgProductConfigurationInternal {
|
|
|
158
189
|
console.log(`Use "window['${dbgName}']" or window.conf to access conf.`);
|
|
159
190
|
}
|
|
160
191
|
/* eslint-enable */
|
|
192
|
+
this.addRawFeatures(rawFeatures, true);
|
|
193
|
+
this.populateFeatures(_initialRootFeatureRefs);
|
|
161
194
|
/**
|
|
162
195
|
* Although the measurement-datas are also passed in validate-calls they are only used at
|
|
163
196
|
* initial product creation. The data is assumed to always be the same for a product, so
|
|
@@ -194,11 +227,9 @@ export class _CfgProductConfigurationInternal {
|
|
|
194
227
|
}
|
|
195
228
|
this.stretchReferenceLengthsByMeasureParamCode = stretchReferenceLengthsByMeasureParamCode;
|
|
196
229
|
}
|
|
197
|
-
static _makeUninitialized(rootFeatureRefs,
|
|
230
|
+
static _makeUninitialized(rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
|
|
198
231
|
parentProduct, rootProduct) {
|
|
199
|
-
|
|
200
|
-
configuration.populateFeatures(rootFeatureRefs);
|
|
201
|
-
return configuration;
|
|
232
|
+
return new this(rawFeatures, parentProduct, rootProduct, rootFeatureRefs);
|
|
202
233
|
}
|
|
203
234
|
get rootFeatureRefs() {
|
|
204
235
|
return this._rootFeatureRefs;
|
|
@@ -207,13 +238,12 @@ export class _CfgProductConfigurationInternal {
|
|
|
207
238
|
get features() {
|
|
208
239
|
return this._features;
|
|
209
240
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
241
|
+
/**
|
|
242
|
+
* True if what root Features are used is not the same as at initial load.
|
|
243
|
+
* This means that functional selection has happened.
|
|
244
|
+
*/
|
|
245
|
+
get hasRootFeaturesChanged() {
|
|
246
|
+
return this._hasRootFeaturesChanged;
|
|
217
247
|
}
|
|
218
248
|
}
|
|
219
249
|
export class CfgProductConfiguration {
|
|
@@ -233,12 +263,6 @@ export class CfgProductConfiguration {
|
|
|
233
263
|
*/
|
|
234
264
|
this.tryMatchSelection = (other, descriptionMatch = false // Match on case insensitive description, not code
|
|
235
265
|
) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.tryMatchSelection(other._internal, descriptionMatch, true); });
|
|
236
|
-
this.getApiSelection = () => convertDtoConfFeaturesToSelOptions(this._internal.getDtoConf(false), true);
|
|
237
|
-
/**
|
|
238
|
-
* This method does not propagate its selections.
|
|
239
|
-
* This method will not cause validation calls. Data is assumed to already be validated.
|
|
240
|
-
*/
|
|
241
|
-
this.setApiSelection = (selectedOptions) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setApiSelection(selectedOptions, true); });
|
|
242
266
|
/**
|
|
243
267
|
* Set how stretched a certain measure should be measureParamCode is the measure to be
|
|
244
268
|
* stretched referenceLength is a value relative to the initial length of the measure. If the
|
|
@@ -259,9 +283,9 @@ export class CfgProductConfiguration {
|
|
|
259
283
|
* CfgProductConfiguration, but is not properly initialized until the initDone-callback
|
|
260
284
|
* has been called.
|
|
261
285
|
*/
|
|
262
|
-
static make(initSuccess, initFail, rootFeatureRefs,
|
|
286
|
+
static make(initSuccess, initFail, rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
|
|
263
287
|
apiSelection, parentProduct, rootProduct) {
|
|
264
|
-
const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs,
|
|
288
|
+
const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs, rawFeatures, parentProduct, rootProduct);
|
|
265
289
|
const external = new this(internal);
|
|
266
290
|
// Note the async-callback at the end of the following line. The call is async.
|
|
267
291
|
internal
|
|
@@ -289,12 +313,12 @@ export class CfgProductConfiguration {
|
|
|
289
313
|
return this._internal.key;
|
|
290
314
|
}
|
|
291
315
|
/**
|
|
292
|
-
* Every (unprocessed) feature
|
|
293
|
-
*
|
|
316
|
+
* Every (unprocessed) feature that is currently loaded for this product. This can be extended
|
|
317
|
+
* by validation calls. What features are actually used is controlled by rootFeatureRefs and what
|
|
294
318
|
* options are selected.
|
|
295
319
|
*/
|
|
296
|
-
get
|
|
297
|
-
return this._internal.
|
|
320
|
+
get rawFeatures() {
|
|
321
|
+
return this._internal.accumulatedRawFeatures;
|
|
298
322
|
}
|
|
299
323
|
/** What features are used in the root of this. This can change with new validate calls. */
|
|
300
324
|
get rootFeatureRefs() {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { Filters
|
|
2
|
-
import {
|
|
3
|
-
export declare function applyCatalogueFilters<T extends
|
|
1
|
+
import { Filters } from "@configura/web-utilities";
|
|
2
|
+
import { DtoCatalogueParams, DtoLevel, DtoProductRef } from "../CatalogueAPI.js";
|
|
3
|
+
export declare function applyCatalogueFilters<T extends DtoCatalogueParams>(filters: Filters<DtoCatalogueParams>, catalogues: T[]): [{
|
|
4
|
+
[K in keyof DtoCatalogueParams]: string[];
|
|
5
|
+
}, T[]];
|
|
4
6
|
export interface ProductRefParams {
|
|
5
7
|
partNr: string;
|
|
6
8
|
}
|
|
7
|
-
export declare function applyProductRefFilters(filters: Filters<ProductRefParams>, productRefs: DtoProductRef[]): [
|
|
9
|
+
export declare function applyProductRefFilters(filters: Filters<ProductRefParams>, productRefs: DtoProductRef[]): [string[], DtoProductRef[]];
|
|
8
10
|
/**
|
|
9
11
|
* Clones the table of content levels tree.
|
|
10
12
|
* Filters to only include passed products.
|
|
@@ -1,31 +1,102 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { shuffle } from "@configura/web-utilities";
|
|
2
|
+
function filterAndSort(propertyValuesToT, property, filtersByProperty, availablePropertyValuesByProperty) {
|
|
3
|
+
const availablePropertyValues = availablePropertyValuesByProperty[property];
|
|
4
|
+
for (const key of propertyValuesToT.keys()) {
|
|
5
|
+
availablePropertyValues.add(key);
|
|
6
|
+
}
|
|
7
|
+
let items;
|
|
8
|
+
const filter = filtersByProperty[property];
|
|
9
|
+
if (filter.mode === "exact") {
|
|
10
|
+
const { value: key } = filter;
|
|
11
|
+
if (key !== "-") {
|
|
12
|
+
const item = propertyValuesToT.get(key);
|
|
13
|
+
if (item === undefined) {
|
|
14
|
+
items = [];
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
items = [item];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (items === undefined) {
|
|
22
|
+
if (filter.mode === "random") {
|
|
23
|
+
items = shuffle(Array.from(propertyValuesToT.values()));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
items = Array.from(propertyValuesToT.entries())
|
|
27
|
+
.sort((l, r) => l[0].localeCompare(r[0], undefined, { sensitivity: "base" }))
|
|
28
|
+
.map((item) => item[1]);
|
|
29
|
+
}
|
|
30
|
+
if (filter.value > 0 && (filter.mode === "first" || filter.mode === "random")) {
|
|
31
|
+
items = items.slice(0, filter.value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return items;
|
|
35
|
+
}
|
|
36
|
+
function stringSetToSortedArray(s) {
|
|
37
|
+
return Array.from(s).sort((l, r) => l.localeCompare(r, undefined, { sensitivity: "base" }));
|
|
38
|
+
}
|
|
2
39
|
export function applyCatalogueFilters(filters, catalogues) {
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
prdCatVersion
|
|
17
|
-
|
|
18
|
-
|
|
40
|
+
const cataloguesAsTree = new Map();
|
|
41
|
+
for (const catalogueParams of catalogues) {
|
|
42
|
+
const { enterprise, prdCat, prdCatVersion, vendor, priceList } = catalogueParams;
|
|
43
|
+
let byEnterprise = cataloguesAsTree.get(enterprise);
|
|
44
|
+
if (byEnterprise === undefined) {
|
|
45
|
+
byEnterprise = new Map();
|
|
46
|
+
cataloguesAsTree.set(enterprise, byEnterprise);
|
|
47
|
+
}
|
|
48
|
+
let byPrdCat = byEnterprise.get(prdCat);
|
|
49
|
+
if (byPrdCat === undefined) {
|
|
50
|
+
byPrdCat = new Map();
|
|
51
|
+
byEnterprise.set(prdCat, byPrdCat);
|
|
52
|
+
}
|
|
53
|
+
let byPrdCatVersion = byPrdCat.get(prdCatVersion);
|
|
54
|
+
if (byPrdCatVersion === undefined) {
|
|
55
|
+
byPrdCatVersion = new Map();
|
|
56
|
+
byPrdCat.set(prdCatVersion, byPrdCatVersion);
|
|
57
|
+
}
|
|
58
|
+
let byVendor = byPrdCatVersion.get(vendor);
|
|
59
|
+
if (byVendor === undefined) {
|
|
60
|
+
byVendor = new Map();
|
|
61
|
+
byPrdCatVersion.set(vendor, byVendor);
|
|
62
|
+
}
|
|
63
|
+
if (byVendor.has(priceList)) {
|
|
64
|
+
console.warn(`Duplicate catalogue ${enterprise} ${prdCat} ${prdCatVersion} ${vendor} ${priceList}`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
byVendor.set(priceList, catalogueParams);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const filteredCatalogues = [];
|
|
71
|
+
const availablePropertyValues = {
|
|
72
|
+
enterprise: new Set(),
|
|
73
|
+
prdCat: new Set(),
|
|
74
|
+
prdCatVersion: new Set(),
|
|
75
|
+
vendor: new Set(),
|
|
76
|
+
priceList: new Set(),
|
|
19
77
|
};
|
|
20
|
-
|
|
78
|
+
filterAndSort(cataloguesAsTree, "enterprise", filters, availablePropertyValues).map((item) => filterAndSort(item, "prdCat", filters, availablePropertyValues).map((item) => filterAndSort(item, "prdCatVersion", filters, availablePropertyValues).map((item) => filterAndSort(item, "vendor", filters, availablePropertyValues).map((item) => filterAndSort(item, "priceList", filters, availablePropertyValues).forEach((item) => {
|
|
79
|
+
filteredCatalogues.push(item);
|
|
80
|
+
})))));
|
|
81
|
+
const availablePropertyValuesAsSortedArrays = {
|
|
82
|
+
enterprise: stringSetToSortedArray(availablePropertyValues.enterprise),
|
|
83
|
+
prdCat: stringSetToSortedArray(availablePropertyValues.prdCat),
|
|
84
|
+
prdCatVersion: stringSetToSortedArray(availablePropertyValues.prdCatVersion),
|
|
85
|
+
vendor: stringSetToSortedArray(availablePropertyValues.vendor),
|
|
86
|
+
priceList: stringSetToSortedArray(availablePropertyValues.priceList),
|
|
87
|
+
};
|
|
88
|
+
return [availablePropertyValuesAsSortedArrays, filteredCatalogues];
|
|
21
89
|
}
|
|
22
90
|
export function applyProductRefFilters(filters, productRefs) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
91
|
+
const map = new Map();
|
|
92
|
+
for (const productRef of productRefs) {
|
|
93
|
+
map.set(productRef.partNr, productRef);
|
|
94
|
+
}
|
|
95
|
+
const availablePropertyValues = {
|
|
96
|
+
partNr: new Set(),
|
|
27
97
|
};
|
|
28
|
-
|
|
98
|
+
const filtered = filterAndSort(map, "partNr", filters, availablePropertyValues);
|
|
99
|
+
return [stringSetToSortedArray(availablePropertyValues.partNr), filtered];
|
|
29
100
|
}
|
|
30
101
|
/**
|
|
31
102
|
* Clones the table of content levels tree.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Filters } from "@configura/web-utilities";
|
|
2
|
-
import { CatalogueAPI, DtoApplicationAreasResponse,
|
|
2
|
+
import { CatalogueAPI, DtoApplicationAreasResponse, DtoCatalogueParamsWithCid, DtoCatalogueParamsWithCidAndLang } from "../CatalogueAPI.js";
|
|
3
3
|
import { CfgProduct, CfgProductSettings } from "../CfgProduct.js";
|
|
4
4
|
import { ProductRefParams } from "./filters.js";
|
|
5
5
|
export interface GeneratedProductConfiguration {
|
|
6
6
|
applicationAreasResponse: DtoApplicationAreasResponse;
|
|
7
7
|
catalogueCount: number;
|
|
8
8
|
catalogueIndex: number;
|
|
9
|
-
catalogueParams:
|
|
9
|
+
catalogueParams: DtoCatalogueParamsWithCidAndLang;
|
|
10
10
|
getProductDuration: number;
|
|
11
11
|
product: CfgProduct;
|
|
12
12
|
productCount: number;
|
|
13
13
|
productIndex: number;
|
|
14
14
|
}
|
|
15
|
-
export declare function generateProductConfigurations(api: CatalogueAPI, lang: string, catalogues:
|
|
15
|
+
export declare function generateProductConfigurations(api: CatalogueAPI, lang: string, catalogues: DtoCatalogueParamsWithCid[], filters: Filters<ProductRefParams>, settings?: Partial<CfgProductSettings>): AsyncIterableIterator<GeneratedProductConfiguration | Error>;
|
|
16
16
|
//# sourceMappingURL=productParamsGenerator.d.ts.map
|
|
@@ -8,7 +8,7 @@ import { CfgProductConfiguration, _CfgProductConfigurationInternal } from "./Cfg
|
|
|
8
8
|
* Returns a new array of CfgFeatures that maps to the newFeatureRefs array. Uses CfgFeatures from
|
|
9
9
|
* currentFeatures if they can be found, otherwise makes new.
|
|
10
10
|
*/
|
|
11
|
-
export declare function syncCfgFeatures(newFeatureRefs: DtoFeatureRef[], currentFeatures: CfgFeature[],
|
|
11
|
+
export declare function syncCfgFeatures(newFeatureRefs: DtoFeatureRef[], currentFeatures: CfgFeature[], rawFeatures: DtoFeature[], parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgFeature[];
|
|
12
12
|
export declare function getMtrlPreview(mtrlApplications: CfgMtrlApplication[] | undefined): string | undefined;
|
|
13
13
|
/**
|
|
14
14
|
* Recursively find all additional product references given a product configuration.
|
|
@@ -6,11 +6,11 @@ import { CfgProductConfiguration, } from "./CfgProductConfiguration.js";
|
|
|
6
6
|
* Returns a new array of CfgFeatures that maps to the newFeatureRefs array. Uses CfgFeatures from
|
|
7
7
|
* currentFeatures if they can be found, otherwise makes new.
|
|
8
8
|
*/
|
|
9
|
-
export function syncCfgFeatures(newFeatureRefs, currentFeatures,
|
|
9
|
+
export function syncCfgFeatures(newFeatureRefs, currentFeatures, rawFeatures, parent, parentConfiguration, parentProduct, rootProduct) {
|
|
10
10
|
const usedRawFeatures = newFeatureRefs
|
|
11
11
|
.map((r) => r.code)
|
|
12
12
|
.map((c) => {
|
|
13
|
-
const rawFeature =
|
|
13
|
+
const rawFeature = rawFeatures.find((f) => c === f.code);
|
|
14
14
|
if (rawFeature === undefined) {
|
|
15
15
|
throw new Error(`Feature not found. Requested feature code: "${c}".`);
|
|
16
16
|
}
|
|
@@ -38,12 +38,19 @@ export function syncCfgFeatures(newFeatureRefs, currentFeatures, allRawFeatures,
|
|
|
38
38
|
// products with similar feature-options tree and trying
|
|
39
39
|
// to retain made selections
|
|
40
40
|
const key = fDescription + (fDescription === "" || hasDuplicateDescription ? fCode : "");
|
|
41
|
-
const existingFeature = currentFeatures.find((cfgF) => cfgF.code === fCode
|
|
41
|
+
const existingFeature = currentFeatures.find((cfgF) => cfgF.code === fCode);
|
|
42
42
|
if (existingFeature !== undefined) {
|
|
43
|
+
if (hasDuplicateDescription) {
|
|
44
|
+
// HasDuplicateDescription could mean the key need to be more specific compared
|
|
45
|
+
// to the one we already have, so then we set it. An old duplicate description
|
|
46
|
+
// key will cause no harm as it is guaranteed to be at least as specific as this.
|
|
47
|
+
// Not changing the key will make React not rerender, so we don't change.
|
|
48
|
+
existingFeature._internal.key = key;
|
|
49
|
+
}
|
|
43
50
|
newFeatures.push(existingFeature);
|
|
44
51
|
continue;
|
|
45
52
|
}
|
|
46
|
-
newFeatures.push(CfgFeature.make(f,
|
|
53
|
+
newFeatures.push(CfgFeature.make(f, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
|
|
47
54
|
}
|
|
48
55
|
return newFeatures;
|
|
49
56
|
}
|
package/dist/productLoader.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DtoProductParamsWithCidAndLang, DtoValidateRequest } from "./CatalogueAPI.js";
|
|
2
2
|
import { CfgProductResponse, CfgValidateResponse } from "./utilitiesCatalogueData.js";
|
|
3
|
-
export declare type GetProduct = (params:
|
|
4
|
-
export declare type PostValidate = (params:
|
|
3
|
+
export declare type GetProduct = (params: DtoProductParamsWithCidAndLang) => Promise<CfgProductResponse>;
|
|
4
|
+
export declare type PostValidate = (params: DtoProductParamsWithCidAndLang, body: DtoValidateRequest) => Promise<CfgValidateResponse>;
|
|
5
5
|
export declare type ProductLoader = {
|
|
6
6
|
getProduct: GetProduct;
|
|
7
7
|
postValidate: PostValidate;
|
package/dist/productLoader.js
CHANGED
|
@@ -37,7 +37,7 @@ export function wrapWithGetProductCache(getProduct) {
|
|
|
37
37
|
export function wrapWithPostValidateCache(postValidate) {
|
|
38
38
|
const cache = new PromiseCache();
|
|
39
39
|
return (params, body) => __awaiter(this, void 0, void 0, function* () {
|
|
40
|
-
return cache.get(`${makeProductKey(params)}-${makeSelOptionsKey(body.selOptions)}`, () => postValidate(params, body));
|
|
40
|
+
return cache.get(`${makeProductKey(params)}-${makeSelOptionsKey(body.selOptions)}-${body.knownFeatureCodes.join(",")}`, () => postValidate(params, body));
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
/** Does both wrapWithGetProductCache and wrapWithPostValidateCache. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AggregatedLoadingObservable } from "@configura/web-utilities";
|
|
2
|
+
import { DtoSyncGroupState } from "../CatalogueAPI.js";
|
|
2
3
|
import { _CfgProductInternal } from "../CfgProduct.js";
|
|
3
4
|
import { _CfgOptionInternal } from "../productConfiguration/CfgOption.js";
|
|
4
5
|
import { ProductLoader } from "../productLoader.js";
|
|
@@ -18,13 +19,19 @@ export declare class SyncGroupsHandler {
|
|
|
18
19
|
/**
|
|
19
20
|
* @param verboseLogging Set to true to get verbose sync state changes logged to the console.
|
|
20
21
|
*/
|
|
21
|
-
static make(updateMode?: SyncGroupsApplyMode, loadingObservable?: AggregatedLoadingObservable, verboseLogging?: boolean): SyncGroupsHandler;
|
|
22
|
+
static make(updateMode?: SyncGroupsApplyMode, loadingObservable?: AggregatedLoadingObservable, initial?: DtoSyncGroupState, verboseLogging?: boolean): SyncGroupsHandler;
|
|
22
23
|
private constructor();
|
|
23
24
|
/** Please note that clones will use the same loadingObservable as their source. */
|
|
24
25
|
clone(): SyncGroupsHandler;
|
|
26
|
+
getCompactSyncGroupState(): DtoSyncGroupState;
|
|
27
|
+
/** Overwrites the sync state */
|
|
28
|
+
setCompactSyncGroupState(s: DtoSyncGroupState): void;
|
|
25
29
|
get verboseLogging(): boolean;
|
|
26
30
|
set verboseLogging(v: boolean);
|
|
27
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Used to initially apply the sync state onto a new product so that it is "in sync"
|
|
33
|
+
* and to reapply the sync state when an optional additional product is selected.
|
|
34
|
+
*/
|
|
28
35
|
init(product: _CfgProductInternal, productLoader: ProductLoader): Promise<void>;
|
|
29
36
|
/**
|
|
30
37
|
* Used when an Option is selected or deselected to apply all consequences of the sync groups.
|
|
@@ -123,7 +123,8 @@ import { SyncGroupsTransaction } from "./SyncGroupsTransaction.js";
|
|
|
123
123
|
* C) The SyncState has an option code for this SyncGroup.
|
|
124
124
|
* D) The option code in the SyncState for the SyncGroup is not the Option selected.
|
|
125
125
|
* E) The Feature has an Option with the right option code.
|
|
126
|
-
* F) The Feature has not previously been affected in this transaction
|
|
126
|
+
* F) The Feature has not previously been affected in this transaction, unless it was affected
|
|
127
|
+
* at Feature initialization.
|
|
127
128
|
*
|
|
128
129
|
* ...for SelectMany (done for every Option):
|
|
129
130
|
* C) The SyncState has a value (on or off) for this SyncGroup and option code.
|
|
@@ -262,20 +263,30 @@ export class SyncGroupsHandler {
|
|
|
262
263
|
/**
|
|
263
264
|
* @param verboseLogging Set to true to get verbose sync state changes logged to the console.
|
|
264
265
|
*/
|
|
265
|
-
static make(updateMode = SyncGroupsApplyMode.Strict, loadingObservable, verboseLogging = false) {
|
|
266
|
-
return new SyncGroupsHandler(new SyncGroupsState(verboseLogging), updateMode, loadingObservable);
|
|
266
|
+
static make(updateMode = SyncGroupsApplyMode.Strict, loadingObservable, initial, verboseLogging = false) {
|
|
267
|
+
return new SyncGroupsHandler(new SyncGroupsState(verboseLogging, initial), updateMode, loadingObservable);
|
|
267
268
|
}
|
|
268
269
|
/** Please note that clones will use the same loadingObservable as their source. */
|
|
269
270
|
clone() {
|
|
270
271
|
return new SyncGroupsHandler(this._syncState.clone(), this.updateMode, this._loadingObservable);
|
|
271
272
|
}
|
|
273
|
+
getCompactSyncGroupState() {
|
|
274
|
+
return this._syncState.getCompact();
|
|
275
|
+
}
|
|
276
|
+
/** Overwrites the sync state */
|
|
277
|
+
setCompactSyncGroupState(s) {
|
|
278
|
+
this._syncState.setCompact(s);
|
|
279
|
+
}
|
|
272
280
|
get verboseLogging() {
|
|
273
281
|
return this._syncState.verboseLogging;
|
|
274
282
|
}
|
|
275
283
|
set verboseLogging(v) {
|
|
276
284
|
this._syncState.verboseLogging = v;
|
|
277
285
|
}
|
|
278
|
-
/**
|
|
286
|
+
/**
|
|
287
|
+
* Used to initially apply the sync state onto a new product so that it is "in sync"
|
|
288
|
+
* and to reapply the sync state when an optional additional product is selected.
|
|
289
|
+
*/
|
|
279
290
|
init(product, productLoader) {
|
|
280
291
|
return __awaiter(this, void 0, void 0, function* () {
|
|
281
292
|
const transaction = yield this.newTransaction(product, productLoader, true);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DtoSyncGroupState } from "../CatalogueAPI.js";
|
|
1
2
|
import { OptionCode, SyncCode } from "./SyncGroupsHandler.js";
|
|
2
3
|
/**
|
|
3
4
|
* The SyncState is used to keep track of the current value of the SyncGroups.
|
|
@@ -12,7 +13,7 @@ export declare class SyncGroupsState {
|
|
|
12
13
|
/**
|
|
13
14
|
* @param verboseLogging Set to true to get verbose sync state changes logged to the console.
|
|
14
15
|
*/
|
|
15
|
-
constructor(_verboseLogging: boolean);
|
|
16
|
+
constructor(_verboseLogging: boolean, initial: DtoSyncGroupState | undefined);
|
|
16
17
|
get verboseLogging(): boolean;
|
|
17
18
|
/**
|
|
18
19
|
* Set to true to get verbose sync state changes logged to the console.
|
|
@@ -31,6 +32,9 @@ export declare class SyncGroupsState {
|
|
|
31
32
|
setForSelectMany(syncCode: SyncCode, optionCode: OptionCode, selected: boolean): void;
|
|
32
33
|
getForSelectOne(syncCode: SyncCode): OptionCode | undefined;
|
|
33
34
|
getForSelectMany(syncCode: SyncCode, optionCode: OptionCode): boolean | undefined;
|
|
35
|
+
/** Overrides the current sync state */
|
|
36
|
+
setCompact(s: DtoSyncGroupState): void;
|
|
37
|
+
getCompact(): DtoSyncGroupState;
|
|
34
38
|
log(syncCode?: SyncCode, optionCode?: OptionCode, selected?: boolean): void;
|
|
35
39
|
}
|
|
36
40
|
//# sourceMappingURL=SyncGroupsState.d.ts.map
|
|
@@ -8,10 +8,11 @@ export class SyncGroupsState {
|
|
|
8
8
|
/**
|
|
9
9
|
* @param verboseLogging Set to true to get verbose sync state changes logged to the console.
|
|
10
10
|
*/
|
|
11
|
-
constructor(_verboseLogging) {
|
|
11
|
+
constructor(_verboseLogging, initial) {
|
|
12
12
|
this._verboseLogging = _verboseLogging;
|
|
13
13
|
this._selectOne = new Map();
|
|
14
14
|
this._selectMany = new Map();
|
|
15
|
+
this.setCompact(initial !== null && initial !== void 0 ? initial : {});
|
|
15
16
|
}
|
|
16
17
|
get verboseLogging() {
|
|
17
18
|
return this._verboseLogging;
|
|
@@ -26,7 +27,7 @@ export class SyncGroupsState {
|
|
|
26
27
|
* @returns a deep copy of the SyncGroupState.
|
|
27
28
|
*/
|
|
28
29
|
clone() {
|
|
29
|
-
return new SyncGroupsState(this._verboseLogging
|
|
30
|
+
return new SyncGroupsState(this._verboseLogging, this.getCompact());
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
33
|
* Replaces the internal state of this SyncGroupState with a deep copy of the one in source.
|
|
@@ -67,6 +68,47 @@ export class SyncGroupsState {
|
|
|
67
68
|
var _a;
|
|
68
69
|
return (_a = this._selectMany.get(syncCode)) === null || _a === void 0 ? void 0 : _a.get(optionCode);
|
|
69
70
|
}
|
|
71
|
+
/** Overrides the current sync state */
|
|
72
|
+
setCompact(s) {
|
|
73
|
+
this._selectOne.clear();
|
|
74
|
+
this._selectMany.clear();
|
|
75
|
+
const { selectOne, selectMany } = s;
|
|
76
|
+
if (selectOne !== undefined) {
|
|
77
|
+
for (const { syncCode, optionCode } of selectOne) {
|
|
78
|
+
this._selectOne.set(syncCode, optionCode);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (selectMany !== undefined) {
|
|
82
|
+
for (const { syncCode, optionCode, selected } of selectMany) {
|
|
83
|
+
let entry = this._selectMany.get(syncCode);
|
|
84
|
+
if (entry === undefined) {
|
|
85
|
+
entry = new Map();
|
|
86
|
+
this._selectMany.set(syncCode, entry);
|
|
87
|
+
}
|
|
88
|
+
entry.set(optionCode, selected);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
getCompact() {
|
|
93
|
+
const result = {};
|
|
94
|
+
if (this._selectOne.size !== 0) {
|
|
95
|
+
const resultSelectOne = [];
|
|
96
|
+
for (const [syncCode, optionCode] of this._selectOne) {
|
|
97
|
+
resultSelectOne.push({ syncCode, optionCode });
|
|
98
|
+
}
|
|
99
|
+
result.selectOne = resultSelectOne;
|
|
100
|
+
}
|
|
101
|
+
if (this._selectMany.size !== 0) {
|
|
102
|
+
const resultSelectMany = [];
|
|
103
|
+
for (const [syncCode, optionCodeToSelected] of this._selectMany) {
|
|
104
|
+
for (const [optionCode, selected] of optionCodeToSelected) {
|
|
105
|
+
resultSelectMany.push({ syncCode, optionCode, selected });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
result.selectMany = resultSelectMany;
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
70
112
|
log(syncCode, optionCode, selected) {
|
|
71
113
|
if (!this._verboseLogging) {
|
|
72
114
|
return;
|