@configura/web-api 2.0.0 → 2.1.0-alpha.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.
@@ -300,9 +300,19 @@ export interface DtoPartsData {
300
300
  listPrice: number;
301
301
  pkgCount: number;
302
302
  selOptions: Array<DtoPartsSelectedOption>;
303
+ constrOptions?: Array<DtoPartsConstrainedOption>;
303
304
  styleNr: string;
304
305
  prices?: DtoPrices;
305
306
  }
307
+ /** PartsConstrainedOption */
308
+ export interface DtoPartsConstrainedOption {
309
+ code: string;
310
+ feature: string;
311
+ constrOptions?: Array<string>;
312
+ next?: {
313
+ [index: string]: DtoPartsConstrainedOption;
314
+ };
315
+ }
306
316
  /** PartsSelectedOption */
307
317
  export interface DtoPartsSelectedOption {
308
318
  code: string;
@@ -1,7 +1,6 @@
1
1
  import { AggregatedLoadingObservable, LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
2
  import { DtoAdditionalProductConfiguration, DtoAdditionalProductRef, DtoCatalogueParamsWithCid, DtoMeasureParam, DtoMiscFile, DtoMtrlApplication, DtoNote, DtoPrices, DtoProductConf, DtoProductParamsWithCidAndLang, DtoTransform } from "./CatalogueAPI.js";
3
3
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
4
- import { CfgProdConfParts } from "./index.js";
5
4
  import { _CfgFeatureInternal } from "./productConfiguration/CfgFeature.js";
6
5
  import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
7
6
  import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfiguration.js";
@@ -9,6 +8,7 @@ import { ProductLoader } from "./productLoader.js";
9
8
  import { SyncGroupsApplyMode } from "./syncGroups/SyncGroupsApplyMode.js";
10
9
  import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
11
10
  import { CfgProductData, RootNodeSource } from "./utilitiesCatalogueData.js";
11
+ import { CfgProdConfParts } from "./utilitiesConfiguration.js";
12
12
  /**
13
13
  * @freshRef a new pointer to the same product, backed by the same original object
14
14
  * @committed false is an indication that this is a potentially transient state. It could
@@ -9,14 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { AggregatedLoadingObservable, assert, assertDefined, augmentErrorMessage, compareArrays, count, Observable, toLengthUnit, } from "@configura/web-utilities";
11
11
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
12
- import { convertDtoProductConfToV1, isAdditionalProductConfiguration, isProductConf, } from "./ConfigurationConverter.js";
13
- import { CfgProdConfParts } from "./index.js";
14
12
  import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
15
13
  import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfiguration.js";
16
14
  import { collectAdditionalProductRefs } from "./productConfiguration/utilitiesProductConfiguration.js";
17
15
  import { wrapWithCache } from "./productLoader.js";
18
16
  import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
19
17
  import { compareCfgProductData, correctDefaultsOnCatalogueParams, isSameCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
18
+ import { CfgProdConfParts, convertDtoProductConfToV1, isAdditionalProductConfiguration, isProductConf, } from "./utilitiesConfiguration.js";
20
19
  function completeSettings(incompleteSettings) {
21
20
  var _a;
22
21
  return {
@@ -53,7 +52,7 @@ function isDescriptionMatch(l, r) {
53
52
  * the class that should be used and interacted with.
54
53
  */
55
54
  export class _CfgProductInternal {
56
- constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, notes, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
55
+ constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, notes, uuid, _rawUnit, _rawProductData, apiSelection, apiConstraints, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
57
56
  var _a;
58
57
  this._productLoaderRaw = _productLoaderRaw;
59
58
  this.prodParams = prodParams;
@@ -236,7 +235,7 @@ export class _CfgProductInternal {
236
235
  }
237
236
  }
238
237
  }
239
- const configurationChange = yield this.configuration._internal.setApiSelection(productConfiguration.selOptions, false);
238
+ const configurationChange = yield this.configuration._internal.setApiSelection(productConfiguration.selOptions, sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct._rawProductData.partsData.constrOptions, false);
240
239
  if (configurationChange) {
241
240
  change = true;
242
241
  }
@@ -394,7 +393,7 @@ export class _CfgProductInternal {
394
393
  if (rootFeatureRefs !== undefined) {
395
394
  configuration._internal.populateFeatures(rootFeatureRefs);
396
395
  }
397
- yield configuration._internal.setApiSelection(productData.partsData.selOptions || [], false);
396
+ yield configuration._internal.setApiSelection(productData.partsData.selOptions || [], productData.partsData.constrOptions, false);
398
397
  yield this._syncAndLoadAdditionalProducts(productLoader, undefined);
399
398
  if (this._destroyed) {
400
399
  return false;
@@ -487,7 +486,7 @@ export class _CfgProductInternal {
487
486
  if (notes !== undefined) {
488
487
  this.addNotes(notes);
489
488
  }
490
- this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, rawFeatures, apiSelection, this, this.root);
489
+ this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, rawFeatures, apiSelection, apiConstraints, this, this.root);
491
490
  }
492
491
  get selected() {
493
492
  return this._selected !== false;
@@ -504,7 +503,7 @@ export class _CfgProductInternal {
504
503
  var _a;
505
504
  const p = new _CfgProductInternal(() => {
506
505
  initSuccess(p);
507
- }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.rawFeatures, this._notes.values(), this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
506
+ }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.rawFeatures, this._notes.values(), this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), this.configuration._internal.getApiConstrained(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
508
507
  });
509
508
  for (const additionalProduct of this.additionalProducts) {
510
509
  product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
@@ -757,7 +756,7 @@ prodParams, settings, optional, loadingObservable, parent, root, additionalProdu
757
756
  // But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
758
757
  // Feel free to find a nicer more readable solution :)
759
758
  initSuccess(p);
760
- }, initFail, productLoaderRaw, prodParams, settings, optional, initiallySelected, rootFeatureRefs !== null && rootFeatureRefs !== void 0 ? rootFeatureRefs : [], rawFeatures, notes === null || notes === void 0 ? void 0 : notes.values(), uuid, unit, productData, (_a = productData.partsData.selOptions) !== null && _a !== void 0 ? _a : [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
759
+ }, initFail, productLoaderRaw, prodParams, settings, optional, initiallySelected, rootFeatureRefs !== null && rootFeatureRefs !== void 0 ? rootFeatureRefs : [], rawFeatures, notes === null || notes === void 0 ? void 0 : notes.values(), uuid, unit, productData, (_a = productData.partsData.selOptions) !== null && _a !== void 0 ? _a : [], productData.partsData.constrOptions, loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
761
760
  });
762
761
  yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad, initialProductConfigurationV1);
763
762
  product._initialClone = yield product.clone();
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
3
  export * from "./CfgReferencePathHelper.js";
4
- export * from "./ConfigurationConverter.js";
5
4
  export * from "./io/index.js";
6
5
  export * from "./material/CfgMaterialMapping.js";
7
6
  export * from "./material/CfgMtrlApplication.js";
@@ -16,9 +15,11 @@ export * from "./productConfiguration/productParamsGenerator.js";
16
15
  export * from "./productLoader.js";
17
16
  export * from "./syncGroups/SyncGroupsApplyMode.js";
18
17
  export * from "./syncGroups/SyncGroupsHandler.js";
18
+ export * from "./syncGroups/SyncGroupsPathHelper.js";
19
19
  export * from "./tasks/formats.js";
20
20
  export * from "./tasks/TaskHandler.js";
21
21
  export * from "./utilitiesCatalogueData.js";
22
22
  export * from "./utilitiesCataloguePermission.js";
23
+ export * from "./utilitiesConfiguration.js";
23
24
  export * from "./utilitiesNumericValues.js";
24
25
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
3
  export * from "./CfgReferencePathHelper.js";
4
- export * from "./ConfigurationConverter.js";
5
4
  export * from "./io/index.js";
6
5
  export * from "./material/CfgMaterialMapping.js";
7
6
  export * from "./material/CfgMtrlApplication.js";
@@ -16,8 +15,10 @@ export * from "./productConfiguration/productParamsGenerator.js";
16
15
  export * from "./productLoader.js";
17
16
  export * from "./syncGroups/SyncGroupsApplyMode.js";
18
17
  export * from "./syncGroups/SyncGroupsHandler.js";
18
+ export * from "./syncGroups/SyncGroupsPathHelper.js";
19
19
  export * from "./tasks/formats.js";
20
20
  export * from "./tasks/TaskHandler.js";
21
21
  export * from "./utilitiesCatalogueData.js";
22
22
  export * from "./utilitiesCataloguePermission.js";
23
+ export * from "./utilitiesConfiguration.js";
23
24
  export * from "./utilitiesNumericValues.js";
@@ -1,7 +1,7 @@
1
1
  import { augmentErrorMessage } from "@configura/web-utilities";
2
- import { compactStringToDtoProductConf, dtoProductConfigurationToCompactString, } from "../ConfigurationConverter.js";
2
+ import { CfgProdConfParts, compactStringToDtoProductConf, dtoProductConfigurationToCompactString, } from "../utilitiesConfiguration.js";
3
3
  import { CfgHistoryManager } from "./CfgHistoryManager.js";
4
- import { CfgIOProdConfConnector, CfgProdConfMessageVersions, CfgProdConfParts, getHighestVersionProdConfMessage, isCfgProdConfMessageV2, STAGE_PROD_CONF_MESSAGE_KEY, } from "./CfgIOProdConfConnector.js";
4
+ import { CfgIOProdConfConnector, CfgProdConfMessageVersions, getHighestVersionProdConfMessage, isCfgProdConfMessageV2, STAGE_PROD_CONF_MESSAGE_KEY, } from "./CfgIOProdConfConnector.js";
5
5
  /**
6
6
  * Instantiating this will make the browser history (and URL) update with the product configuration.
7
7
  */
@@ -1,5 +1,6 @@
1
1
  import { DtoAdditionalProductConfiguration, DtoProductConf } from "../CatalogueAPI.js";
2
2
  import { CfgProduct, CfgProductChangeNotification } from "../CfgProduct.js";
3
+ import { CfgProdConfParts } from "../utilitiesConfiguration.js";
3
4
  import { CfgIOManager } from "./CfgIOManager.js";
4
5
  import { CfgIOWarningSupplier } from "./CfgIOWarningSupplier.js";
5
6
  export declare const isCfgProdConfMessage: (data: unknown) => data is CfgProdConfMessageV1 | CfgProdConfMessageV2;
@@ -22,17 +23,6 @@ export declare enum CfgProdConfMessageVersions {
22
23
  V1dot0 = 1,
23
24
  V2dot0 = 2
24
25
  }
25
- /**
26
- * @param ExtendedData Includes extra data, i.e. units and groupCodes
27
- * @param ProductParams Includes what Product this was generated for, and the same for any Additional Products.
28
- * @param SyncGroupState Includes the current sync group state
29
- */
30
- export declare enum CfgProdConfParts {
31
- NoExtra = 0,
32
- ExtendedData = 1,
33
- ProdParams = 2,
34
- SyncGroupState = 4
35
- }
36
26
  export declare const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
37
27
  declare type ProdConfMessageCallback = (message: CfgProdConfMessage) => Promise<void>;
38
28
  declare type ProdConfCallback = (conf: DtoProductConf) => Promise<void>;
@@ -7,7 +7,7 @@ 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 { convertDtoProductConfToV1 } from "../ConfigurationConverter.js";
10
+ import { convertDtoProductConfToV1 } from "../utilitiesConfiguration.js";
11
11
  export const isCfgProdConfMessage = (data) => typeof data === "object" && data !== null && "version" in data && "conf" in data;
12
12
  export const isCfgProdConfMessageV1 = (data) => isCfgProdConfMessage(data) && data.version === "1.0";
13
13
  export const isCfgProdConfMessageV2 = (data) => isCfgProdConfMessage(data) && data.version === "2.0";
@@ -19,18 +19,6 @@ export var CfgProdConfMessageVersions;
19
19
  CfgProdConfMessageVersions[CfgProdConfMessageVersions["V1dot0"] = 1] = "V1dot0";
20
20
  CfgProdConfMessageVersions[CfgProdConfMessageVersions["V2dot0"] = 2] = "V2dot0";
21
21
  })(CfgProdConfMessageVersions || (CfgProdConfMessageVersions = {}));
22
- /**
23
- * @param ExtendedData Includes extra data, i.e. units and groupCodes
24
- * @param ProductParams Includes what Product this was generated for, and the same for any Additional Products.
25
- * @param SyncGroupState Includes the current sync group state
26
- */
27
- export var CfgProdConfParts;
28
- (function (CfgProdConfParts) {
29
- CfgProdConfParts[CfgProdConfParts["NoExtra"] = 0] = "NoExtra";
30
- CfgProdConfParts[CfgProdConfParts["ExtendedData"] = 1] = "ExtendedData";
31
- CfgProdConfParts[CfgProdConfParts["ProdParams"] = 2] = "ProdParams";
32
- CfgProdConfParts[CfgProdConfParts["SyncGroupState"] = 4] = "SyncGroupState";
33
- })(CfgProdConfParts || (CfgProdConfParts = {}));
34
22
  export const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
35
23
  /**
36
24
  * Base class for connecting the product configuration to an IO channel
@@ -1,5 +1,6 @@
1
1
  import { DtoProductConf } from "../CatalogueAPI.js";
2
- import { CfgIOProdConfConnector, CfgProdConfMessage, CfgProdConfMessageVersions, CfgProdConfParts } from "./CfgIOProdConfConnector.js";
2
+ import { CfgProdConfParts } from "../utilitiesConfiguration.js";
3
+ import { CfgIOProdConfConnector, CfgProdConfMessage, CfgProdConfMessageVersions } from "./CfgIOProdConfConnector.js";
3
4
  import { CfgObservableStateManager } from "./CfgObservableStateManager.js";
4
5
  /**
5
6
  * Instantiating this will make the observable state update with the product configuration.
@@ -1,4 +1,5 @@
1
- import { CfgIOProdConfConnector, CfgProdConfMessageVersions, CfgProdConfParts, } from "./CfgIOProdConfConnector.js";
1
+ import { CfgProdConfParts } from "../utilitiesConfiguration.js";
2
+ import { CfgIOProdConfConnector, CfgProdConfMessageVersions, } from "./CfgIOProdConfConnector.js";
2
3
  /**
3
4
  * Instantiating this will make the observable state update with the product configuration.
4
5
  * @param sendVersions What versions of the productConfiguration shall be sent? Multiple can be selected
@@ -1,5 +1,6 @@
1
1
  import { DtoProductConf } from "../CatalogueAPI.js";
2
- import { CfgIOProdConfConnector, CfgProdConfMessage, CfgProdConfMessageVersions, CfgProdConfParts } from "./CfgIOProdConfConnector.js";
2
+ import { CfgProdConfParts } from "../utilitiesConfiguration.js";
3
+ import { CfgIOProdConfConnector, CfgProdConfMessage, CfgProdConfMessageVersions } from "./CfgIOProdConfConnector.js";
3
4
  import { CfgWindowMessageManager } from "./CfgWindowMessageManager.js";
4
5
  /**
5
6
  * Instantiating this will make Stage send product configuration changes using the post message-API.
@@ -1,4 +1,5 @@
1
- import { CfgIOProdConfConnector, CfgProdConfMessageVersions, CfgProdConfParts, } from "./CfgIOProdConfConnector.js";
1
+ import { CfgProdConfParts } from "../utilitiesConfiguration.js";
2
+ import { CfgIOProdConfConnector, CfgProdConfMessageVersions, } from "./CfgIOProdConfConnector.js";
2
3
  /**
3
4
  * Instantiating this will make Stage send product configuration changes using the post message-API.
4
5
  * It will also make Stage listen for incoming product configuration update messages.
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoFeature, DtoFeatureConf, DtoNote, DtoSelectedOption, DtoSyncGroup, DtoSyncGroupMethods } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoFeatureConf, DtoNote, DtoPartsConstrainedOption, DtoSelectedOption, DtoSyncGroup, DtoSyncGroupMethods } from "../CatalogueAPI.js";
3
3
  import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { SyncCode } from "../syncGroups/SyncGroupsHandler.js";
@@ -43,6 +43,7 @@ export declare class _CfgFeatureInternal {
43
43
  readonly selectionType: SelectionType;
44
44
  private _options;
45
45
  private readonly _selectedOptions;
46
+ private readonly _constrainedOptions;
46
47
  private _mtrlApplications;
47
48
  readonly hasUpcharge: boolean;
48
49
  readonly changeObservable: Observable<FeatureChangeNotification>;
@@ -106,7 +107,12 @@ export declare class _CfgFeatureInternal {
106
107
  getDtoConf: (includeExtendedData: boolean) => DtoFeatureConf;
107
108
  setApiSelection: (apiOptionSelectionMap: {
108
109
  [index: string]: DtoSelectedOption;
110
+ } | undefined, apiOptionConstraintMap: {
111
+ [index: string]: DtoPartsConstrainedOption;
109
112
  } | undefined) => Promise<boolean>;
113
+ addForApiConstrained: (next: {
114
+ [key: string]: DtoPartsConstrainedOption;
115
+ }) => void;
110
116
  /** Pushes to refresh stretch. Does not cause validation. */
111
117
  pushStretch: () => Promise<boolean>;
112
118
  structureCompare: (other: _CfgFeatureInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
@@ -119,6 +125,7 @@ export declare class _CfgFeatureInternal {
119
125
  */
120
126
  selectOption: (optionInternal: _CfgOptionInternal, on: boolean, bubbleMode: ProductConfigurationBubbleMode) => Promise<boolean>;
121
127
  isSelected: (option: _CfgOptionInternal) => boolean;
128
+ isDisabled: (option: _CfgOptionInternal) => boolean;
122
129
  keyMatch: (other: _CfgFeatureInternal, descriptionMatch?: boolean) => boolean;
123
130
  /** Only in selected options */
124
131
  _getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
@@ -72,6 +72,7 @@ export class _CfgFeatureInternal {
72
72
  this.parentProduct = parentProduct;
73
73
  this.rootProduct = rootProduct;
74
74
  this._selectedOptions = [];
75
+ this._constrainedOptions = [];
75
76
  this.changeObservable = new Observable();
76
77
  this.setNumericValue = (val) => __awaiter(this, void 0, void 0, function* () {
77
78
  if (this.selectionType !== SelectionType.SelectOne) {
@@ -114,6 +115,7 @@ export class _CfgFeatureInternal {
114
115
  }
115
116
  yield this._notifyAllOfChange(bubbleMode, committed);
116
117
  });
118
+ // Keep in sync with stripExtendedDataFromDtoFeatureConf
117
119
  this.getDtoConf = (includeExtendedData) => {
118
120
  const result = {
119
121
  code: this.code,
@@ -134,7 +136,8 @@ export class _CfgFeatureInternal {
134
136
  // way around. For that reason the get-method above uses the new format, and the set-method
135
137
  // below the old format. As these functions are meant to only be used internally this should't
136
138
  // cause too much confusion.
137
- this.setApiSelection = (apiOptionSelectionMap) => __awaiter(this, void 0, void 0, function* () {
139
+ this.setApiSelection = (apiOptionSelectionMap, apiOptionConstraintMap) => __awaiter(this, void 0, void 0, function* () {
140
+ var _a, _b;
138
141
  const selectionType = this.selectionType;
139
142
  const isGroup = selectionType === SelectionType.Group;
140
143
  const isSelectOne = selectionType === SelectionType.SelectOne;
@@ -149,11 +152,29 @@ export class _CfgFeatureInternal {
149
152
  options = this.options; // This will generate all children
150
153
  }
151
154
  let change = false;
155
+ const constraintMap = apiOptionConstraintMap !== null && apiOptionConstraintMap !== void 0 ? apiOptionConstraintMap : {};
156
+ // The first value that belongs to this features options is used as the key to look up constrained options
157
+ const featureConstrainedOptions = (_b = (_a = options.map((o) => constraintMap[o.code]).find((o) => !!o)) === null || _a === void 0 ? void 0 : _a.constrOptions) !== null && _b !== void 0 ? _b : [];
152
158
  for (let i = 0; i < options.length; i++) {
153
159
  const option = options[i];
154
160
  const apiOptionSelection = apiOptionSelectionMap[option.code];
161
+ const isConstrained = featureConstrainedOptions.indexOf(option.code) >= 0;
155
162
  const selectedIndex = this._selectedOptions.findIndex(getOptionFilter(option._internal));
163
+ const constrainedIndex = this._constrainedOptions.findIndex(getOptionFilter(option._internal));
156
164
  const isOn = isGroup || apiOptionSelection;
165
+ if (isConstrained) {
166
+ if (constrainedIndex === -1) {
167
+ doFreshRefOptionAtIndex(options, i, committed, (freshRef) => this._constrainedOptions.push(freshRef));
168
+ change = true;
169
+ }
170
+ }
171
+ else {
172
+ if (constrainedIndex !== -1) {
173
+ this._constrainedOptions.splice(constrainedIndex, 1);
174
+ doFreshRefOptionAtIndex(options, i, committed);
175
+ change = true;
176
+ }
177
+ }
157
178
  if (isOn) {
158
179
  if (isSelectOne) {
159
180
  if (this.isUseNumericValue) {
@@ -188,7 +209,7 @@ export class _CfgFeatureInternal {
188
209
  change = true;
189
210
  }
190
211
  }
191
- if (yield option._internal.setApiSelection(apiOptionSelection)) {
212
+ if (yield option._internal.setApiSelection(apiOptionSelection, constraintMap[option.code])) {
192
213
  change = true;
193
214
  }
194
215
  }
@@ -221,6 +242,12 @@ export class _CfgFeatureInternal {
221
242
  }
222
243
  return change;
223
244
  });
245
+ this.addForApiConstrained = (next) => {
246
+ const constrOptions = this._constrainedOptions;
247
+ for (const so of this._selectedOptions) {
248
+ next[so.code] = so._internal.getApiConstrained(constrOptions);
249
+ }
250
+ };
224
251
  /** Pushes to refresh stretch. Does not cause validation. */
225
252
  this.pushStretch = () => __awaiter(this, void 0, void 0, function* () {
226
253
  if (this.selectionType !== SelectionType.SelectOne) {
@@ -387,6 +414,7 @@ export class _CfgFeatureInternal {
387
414
  });
388
415
  this.isSelected = (option) => this.selectionType === SelectionType.Group ||
389
416
  this._selectedOptions.some(getOptionFilter(option));
417
+ this.isDisabled = (option) => this._constrainedOptions.some(getOptionFilter(option));
390
418
  this.keyMatch = (other, descriptionMatch = false) => descriptionMatch
391
419
  ? this.description.toLowerCase() === other.description.toLowerCase()
392
420
  : this.code === other.code;
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoFeature, DtoMiscFile, DtoNote, DtoOption, DtoOptionConf, DtoSelectedOption } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoMiscFile, DtoNote, DtoOption, DtoOptionConf, DtoPartsConstrainedOption, DtoSelectedOption } from "../CatalogueAPI.js";
3
3
  import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { NumericValuesSelection } from "../utilitiesNumericValues.js";
@@ -83,6 +83,7 @@ export declare class _CfgOptionInternal {
83
83
  get unit(): LengthUnit;
84
84
  get description(): string;
85
85
  get selected(): boolean;
86
+ get disabled(): boolean;
86
87
  get selectedChangeInProgress(): boolean;
87
88
  get ancestorsSelected(): boolean;
88
89
  get mtrlApplications(): CfgMtrlApplication[];
@@ -94,7 +95,8 @@ export declare class _CfgOptionInternal {
94
95
  /** Called by child to tell its parent that it has changed. */
95
96
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
96
97
  getDtoConf: (includeExtendedData: boolean) => DtoOptionConf;
97
- setApiSelection: (apiOptionSelection: DtoSelectedOption | undefined) => Promise<boolean>;
98
+ setApiSelection: (apiOptionSelection: DtoSelectedOption | undefined, apiOptionConstraint: DtoPartsConstrainedOption | undefined) => Promise<boolean>;
99
+ getApiConstrained: (constrOptions: CfgOption[]) => DtoPartsConstrainedOption;
98
100
  structureCompare: (other: _CfgOptionInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
99
101
  tryMatchSelection: (other: CfgOption, descriptionMatch?: boolean) => Promise<boolean>;
100
102
  keyMatch: (other: _CfgOptionInternal, descriptionMatch?: boolean) => boolean;
@@ -132,6 +134,7 @@ export declare class CfgOption {
132
134
  get unit(): LengthUnit;
133
135
  get description(): string;
134
136
  get selected(): boolean;
137
+ get disabled(): boolean;
135
138
  /**
136
139
  * Selection state is in progress to be changed. This can be used in GUI
137
140
  * to display the state as transitioning, or as already changed.
@@ -138,7 +138,7 @@ export class _CfgOptionInternal {
138
138
  // way around. For that reason the get-method above uses the new format, and the set-method
139
139
  // below the old format. As these functions are meant to only be used internally this should't
140
140
  // cause too much confusion.
141
- this.setApiSelection = (apiOptionSelection) => __awaiter(this, void 0, void 0, function* () {
141
+ this.setApiSelection = (apiOptionSelection, apiOptionConstraint) => __awaiter(this, void 0, void 0, function* () {
142
142
  let change = false;
143
143
  const upcharge = this._calculateUpcharge();
144
144
  if (this._upcharge !== upcharge) {
@@ -152,11 +152,25 @@ export class _CfgOptionInternal {
152
152
  else {
153
153
  features = this.features; // This will generate all children
154
154
  }
155
- if ((yield Promise.all(features.map((f) => f._internal.setApiSelection(apiOptionSelection ? apiOptionSelection.next : undefined)))).some((b) => b)) {
155
+ if ((yield Promise.all(features.map((f) => f._internal.setApiSelection(apiOptionSelection ? apiOptionSelection.next : undefined, apiOptionConstraint === null || apiOptionConstraint === void 0 ? void 0 : apiOptionConstraint.next)))).some((b) => b)) {
156
156
  change = true;
157
157
  }
158
158
  return change;
159
159
  });
160
+ this.getApiConstrained = (constrOptions) => {
161
+ var _a;
162
+ const next = {};
163
+ // use _features to avoid populating when the option is not selected
164
+ for (const feature of (_a = this._features) !== null && _a !== void 0 ? _a : []) {
165
+ feature._internal.addForApiConstrained(next);
166
+ }
167
+ return {
168
+ code: this.code,
169
+ feature: this.parent.code,
170
+ constrOptions: constrOptions.map((o) => o.code),
171
+ next,
172
+ };
173
+ };
160
174
  this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => this.keyMatch(other, descriptionMatch) &&
161
175
  compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
162
176
  this.tryMatchSelection = (other, descriptionMatch = false) => __awaiter(this, void 0, void 0, function* () {
@@ -270,6 +284,9 @@ export class _CfgOptionInternal {
270
284
  get selected() {
271
285
  return this.parent.isSelected(this);
272
286
  }
287
+ get disabled() {
288
+ return this.parent.isDisabled(this);
289
+ }
273
290
  get selectedChangeInProgress() {
274
291
  const syncGroupHandler = this.rootProduct.syncGroupHandler;
275
292
  if (syncGroupHandler === undefined) {
@@ -415,6 +432,9 @@ export class CfgOption {
415
432
  get selected() {
416
433
  return this._internal.selected;
417
434
  }
435
+ get disabled() {
436
+ return this._internal.disabled;
437
+ }
418
438
  /**
419
439
  * Selection state is in progress to be changed. This can be used in GUI
420
440
  * to display the state as transitioning, or as already changed.
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, LengthValue, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoFeature, DtoFeatureConf, DtoFeatureRef, DtoSelectedOption } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoFeatureConf, DtoFeatureRef, DtoPartsConstrainedOption, DtoSelectedOption } from "../CatalogueAPI.js";
3
3
  import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
5
5
  import { ProductConfigurationBubbleMode } from "./CfgOption.js";
@@ -36,12 +36,13 @@ export declare class _CfgProductConfigurationInternal {
36
36
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
37
37
  getDtoConf: (includeExtendedData: boolean) => DtoFeatureConf[];
38
38
  getApiSelection: () => DtoSelectedOption[];
39
+ getApiConstrained: () => DtoPartsConstrainedOption[];
39
40
  /**
40
41
  * When used internally the notifications are taken care off by the caller, but if set from
41
42
  * outside we want notifications to bubble all the way to the root.
42
43
  * This method will not cause validation calls. Data is assumed to already be validated.
43
44
  */
44
- setApiSelection: (selectedOptions: DtoSelectedOption[], bubbleToRoot: boolean) => Promise<boolean>;
45
+ setApiSelection: (selectedOptions: DtoSelectedOption[], constrOptions: readonly DtoPartsConstrainedOption[] | undefined, bubbleToRoot: boolean) => Promise<boolean>;
45
46
  structureCompare: (other: _CfgProductConfigurationInternal, strictOrder: boolean, descriptionMatch: boolean) => boolean;
46
47
  /**
47
48
  * When used internally the notifications are taken care off by the caller, but if set from
@@ -76,7 +77,7 @@ export declare class CfgProductConfiguration {
76
77
  * has been called.
77
78
  */
78
79
  static make(initSuccess: (c: CfgProductConfiguration) => void, initFail: (error: Error) => void, rootFeatureRefs: DtoFeatureRef[], rawFeatures: DtoFeature[], // Flat packed. All the features that can currently appear anyplace in the selection tree.
79
- apiSelection: DtoSelectedOption[], parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgProductConfiguration;
80
+ apiSelection: DtoSelectedOption[], apiConstraints: readonly DtoPartsConstrainedOption[] | undefined, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgProductConfiguration;
80
81
  /**
81
82
  * Makes an object wrapping the passed object. This is not a clone method, it is a method to
82
83
  * make a new outer reference. Like a shallow copy.
@@ -9,7 +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 { convertDtoFeatureConfsToSelOptions } from "../ConfigurationConverter.js";
12
+ import { convertDtoFeatureConfsToSelOptions } from "../utilitiesConfiguration.js";
13
13
  import { ProductConfigurationBubbleMode } from "./CfgOption.js";
14
14
  import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
15
15
  /**
@@ -56,18 +56,33 @@ export class _CfgProductConfigurationInternal {
56
56
  });
57
57
  this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
58
58
  this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
59
+ this.getApiConstrained = () => this._features.map((f) => {
60
+ const next = {};
61
+ f._internal.addForApiConstrained(next);
62
+ return {
63
+ code: "!~!",
64
+ feature: "",
65
+ next,
66
+ };
67
+ });
59
68
  /**
60
69
  * When used internally the notifications are taken care off by the caller, but if set from
61
70
  * outside we want notifications to bubble all the way to the root.
62
71
  * This method will not cause validation calls. Data is assumed to already be validated.
63
72
  */
64
- this.setApiSelection = (selectedOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
73
+ this.setApiSelection = (selectedOptions, constrOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
65
74
  const featuresLength = this._features.length;
66
75
  const selectedOptionsLength = selectedOptions.length;
67
76
  if (featuresLength !== selectedOptionsLength) {
68
77
  throw new Error(`Wrong selection count. Features on this configuration: ${featuresLength}. Passed feature count: ${selectedOptionsLength}.`);
69
78
  }
70
- const change = (yield Promise.all(this._features.map((f, i) => f._internal.setApiSelection(selectedOptions[i].next)))).some((b) => b);
79
+ if (constrOptions && featuresLength !== constrOptions.length) {
80
+ throw new Error(`Wrong constraint feature count. Features on this configuration: ${featuresLength}. Passed constraint feature count: ${constrOptions.length}.`);
81
+ }
82
+ const change = (yield Promise.all(this._features.map((f, i) => {
83
+ var _a;
84
+ return f._internal.setApiSelection(selectedOptions[i].next, (_a = (constrOptions !== null && constrOptions !== void 0 ? constrOptions : [])[i]) === null || _a === void 0 ? void 0 : _a.next);
85
+ }))).some((b) => b);
71
86
  if (change) {
72
87
  yield this._notifyAllOfChange(bubbleToRoot
73
88
  ? ProductConfigurationBubbleMode.ToRoot
@@ -284,12 +299,12 @@ export class CfgProductConfiguration {
284
299
  * has been called.
285
300
  */
286
301
  static make(initSuccess, initFail, rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
287
- apiSelection, parentProduct, rootProduct) {
302
+ apiSelection, apiConstraints, parentProduct, rootProduct) {
288
303
  const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs, rawFeatures, parentProduct, rootProduct);
289
304
  const external = new this(internal);
290
305
  // Note the async-callback at the end of the following line. The call is async.
291
306
  internal
292
- .setApiSelection(apiSelection, false)
307
+ .setApiSelection(apiSelection, apiConstraints, false)
293
308
  .then(() => initSuccess(external))
294
309
  .catch((e) => initFail(toError(e)));
295
310
  return external;
@@ -1,10 +1,12 @@
1
- import { Filters, Matches } from "@configura/web-utilities";
1
+ import { Filters } from "@configura/web-utilities";
2
2
  import { DtoCatalogueParams, DtoLevel, DtoProductRef } from "../CatalogueAPI.js";
3
- export declare function applyCatalogueFilters<T extends DtoCatalogueParams>(filters: Filters<DtoCatalogueParams>, catalogues: T[]): [Matches<DtoCatalogueParams>, T[]];
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[]): [Matches<ProductRefParams>, 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 { match, pick } from "@configura/web-utilities";
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 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
- let picked = pick(filters.enterprise, priceList.matching);
9
- picked = pick(filters.prdCat, picked);
10
- picked = pick(filters.prdCatVersion, picked);
11
- picked = pick(filters.vendor, picked);
12
- picked = pick(filters.priceList, picked);
13
- const matches = {
14
- enterprise,
15
- prdCat,
16
- prdCatVersion,
17
- priceList,
18
- vendor,
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
- return [matches, picked];
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 partNr = match("partNr", filters.partNr, productRefs);
24
- const result = pick(filters.partNr, partNr.matching);
25
- const args = {
26
- partNr,
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
- return [args, result];
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.
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { augmentErrorMessage, Observable } from "@configura/web-utilities";
11
11
  import { dtoExportFormatNames, dtoRenderFormatNames, } from "../CatalogueAPI.js";
12
- import { convertDtoProductConfToV1 } from "../ConfigurationConverter.js";
12
+ import { convertDtoProductConfToV1 } from "../utilitiesConfiguration.js";
13
13
  import { isExportFormat, isRenderFormat } from "./formats.js";
14
14
  export class _TaskHandlerInternal {
15
15
  constructor(api) {
@@ -0,0 +1,4 @@
1
+ import { DtoPartsConstrainedOption } from "../../CatalogueAPI";
2
+ export declare const testConstrOptions: readonly DtoPartsConstrainedOption[];
3
+ export declare const testUpdatedConstrOptions: readonly DtoPartsConstrainedOption[];
4
+ //# sourceMappingURL=testDataConstraints.d.ts.map
@@ -0,0 +1,174 @@
1
+ export const testConstrOptions = Object.freeze([
2
+ {
3
+ code: "!~!",
4
+ feature: "",
5
+ next: {
6
+ "option-ab": {
7
+ code: "option-ab",
8
+ feature: "feature-a",
9
+ constrOptions: ["option-aa"],
10
+ next: {
11
+ "option-multi-nested-a": {
12
+ feature: "feature-multiple-nested",
13
+ code: "option-multi-nested-a",
14
+ constrOptions: [],
15
+ next: { "option-ca": { code: "option-ca", feature: "feature-c", constrOptions: [], next: {} } }
16
+ },
17
+ "option-multi-nested-b": {
18
+ feature: "feature-multiple-nested",
19
+ code: "option-multi-nested-b",
20
+ constrOptions: [],
21
+ next: { "option-optional-b": { code: "option-optional-b", feature: "feature-optional", constrOptions: [], next: {} } }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ },
27
+ {
28
+ code: "!~!",
29
+ feature: "",
30
+ next: {
31
+ "option-bb": {
32
+ feature: "feature-b",
33
+ code: "option-bb",
34
+ constrOptions: [],
35
+ next: {
36
+ "option-multi-nested-a": {
37
+ code: "option-multi-nested-a",
38
+ feature: "feature-multiple-nested",
39
+ constrOptions: [],
40
+ next: { "option-ca": { feature: "feature-c", code: "option-ca", constrOptions: [], next: {} } }
41
+ },
42
+ "option-multi-nested-b": {
43
+ feature: "feature-multiple-nested",
44
+ code: "option-multi-nested-b",
45
+ constrOptions: [],
46
+ next: {}
47
+ }
48
+ }
49
+ }
50
+ }
51
+ },
52
+ {
53
+ code: "!~!",
54
+ feature: "",
55
+ next: {
56
+ "option-multi-a": {
57
+ feature: "feature-multiple",
58
+ code: "option-multi-a",
59
+ constrOptions: ["option-multi-b"],
60
+ next: {
61
+ "option-db": { code: "option-db", feature: "feature-d", constrOptions: ["option-da"], next: {} },
62
+ "option-ea": { code: "option-ea", feature: "feature-e", constrOptions: ["option-eb"], next: {} }
63
+ }
64
+ },
65
+ "option-multi-b": {
66
+ feature: "feature-multiple",
67
+ code: "option-multi-b",
68
+ constrOptions: ["option-multi-b"],
69
+ next: {
70
+ "option-ga": { code: "option-ga", feature: "feature-g", constrOptions: ["option-gb"], next: {} },
71
+ "option-1h": { code: "option-1h", feature: "feature-h", constrOptions: ["option-2h"], next: {} }
72
+ }
73
+ }
74
+ }
75
+ },
76
+ {
77
+ code: "!~!",
78
+ feature: "",
79
+ next: {
80
+ "option-optional-a": { code: "option-optional-a", feature: "feature-optional", constrOptions: [], next: {} }
81
+ }
82
+ }
83
+ ]);
84
+ export const testUpdatedConstrOptions = Object.freeze([
85
+ {
86
+ code: "!~!",
87
+ feature: "",
88
+ next: {
89
+ "option-ab": {
90
+ code: "option-ab",
91
+ feature: "feature-a",
92
+ constrOptions: [],
93
+ next: {
94
+ "option-multi-nested-a": {
95
+ feature: "feature-multiple-nested",
96
+ code: "option-multi-nested-a",
97
+ constrOptions: [],
98
+ next: { "option-ca": { code: "option-ca", feature: "feature-c", constrOptions: [], next: {} } }
99
+ },
100
+ "option-multi-nested-b": {
101
+ feature: "feature-multiple-nested",
102
+ code: "option-multi-nested-b",
103
+ constrOptions: [],
104
+ next: {
105
+ "option-optional-a": { code: "option-optional-a", feature: "feature-optional", constrOptions: [], next: {} },
106
+ "option-optional-b": { code: "option-optional-b", feature: "feature-optional", constrOptions: [], next: {} }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ },
113
+ {
114
+ code: "!~!",
115
+ feature: "",
116
+ next: {
117
+ "option-bb": {
118
+ feature: "feature-b",
119
+ code: "option-bb",
120
+ constrOptions: [],
121
+ next: {
122
+ "option-multi-nested-a": {
123
+ code: "option-multi-nested-a",
124
+ feature: "feature-multiple-nested",
125
+ constrOptions: [],
126
+ next: {
127
+ "option-cb": { feature: "feature-c", code: "option-cb", constrOptions: [], next: {} }
128
+ }
129
+ },
130
+ "option-multi-nested-b": {
131
+ feature: "feature-multiple-nested",
132
+ code: "option-multi-nested-b",
133
+ constrOptions: [],
134
+ next: {
135
+ "option-optional-b": { feature: "feature-optional", code: "option-optional-b", constrOptions: [], next: {} }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+ },
142
+ {
143
+ code: "!~!",
144
+ feature: "",
145
+ next: {
146
+ "option-multi-a": {
147
+ feature: "feature-multiple",
148
+ code: "option-multi-a",
149
+ constrOptions: [],
150
+ next: {
151
+ "option-da": { code: "option-da", feature: "feature-d", constrOptions: [], next: {} },
152
+ "option-eb": { code: "option-eb", feature: "feature-e", constrOptions: [], next: {} }
153
+ }
154
+ },
155
+ "option-multi-b": {
156
+ feature: "feature-multiple",
157
+ code: "option-multi-b",
158
+ constrOptions: [],
159
+ next: {
160
+ "option-ga": { code: "option-ga", feature: "feature-g", constrOptions: [], next: {} },
161
+ "option-1h": { code: "option-1h", feature: "feature-h", constrOptions: [], next: {} }
162
+ }
163
+ }
164
+ }
165
+ },
166
+ {
167
+ code: "!~!",
168
+ feature: "",
169
+ next: {
170
+ "option-optional-a": { code: "option-optional-a", feature: "feature-optional", constrOptions: [], next: {} },
171
+ "option-optional-b": { code: "option-optional-b", feature: "feature-optional", constrOptions: [], next: {} },
172
+ }
173
+ }
174
+ ]);
@@ -1,4 +1,15 @@
1
1
  import { DtoAdditionalProductConf, DtoAdditionalProductConfiguration, DtoFeatureConf, DtoProductConf, DtoSelectedOption } from "./CatalogueAPI.js";
2
+ /**
3
+ * @param ExtendedData Extra data, i.e. units and groupCodes
4
+ * @param ProductParams What Product the conf is for, and the same for any Additional Products.
5
+ * @param SyncGroupState The current sync group state
6
+ */
7
+ export declare enum CfgProdConfParts {
8
+ NoExtra = 0,
9
+ ExtendedData = 1,
10
+ ProdParams = 2,
11
+ SyncGroupState = 4
12
+ }
2
13
  /** Is the newer version of product configuration */
3
14
  export declare const isProductConf: (value: DtoAdditionalProductConfiguration | DtoProductConf) => value is DtoAdditionalProductConf;
4
15
  /** Is the older version of product configuration */
@@ -14,5 +25,5 @@ export declare const dtoProductConfigurationToCompactString: (conf: DtoProductCo
14
25
  * Deserializes and inflates the configuration from the compacted format
15
26
  */
16
27
  export declare const compactStringToDtoProductConf: (versionAndConf: string) => DtoProductConf;
17
- export declare const stripExtendedDataFromDtoProductConf: (conf: DtoProductConf) => DtoProductConf;
18
- //# sourceMappingURL=ConfigurationConverter.d.ts.map
28
+ export declare const stripExtendedDataFromDtoProductConf: (conf: DtoProductConf, toStrip: CfgProdConfParts) => DtoProductConf;
29
+ //# sourceMappingURL=utilitiesConfiguration.d.ts.map
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @param ExtendedData Extra data, i.e. units and groupCodes
3
+ * @param ProductParams What Product the conf is for, and the same for any Additional Products.
4
+ * @param SyncGroupState The current sync group state
5
+ */
6
+ export var CfgProdConfParts;
7
+ (function (CfgProdConfParts) {
8
+ CfgProdConfParts[CfgProdConfParts["NoExtra"] = 0] = "NoExtra";
9
+ CfgProdConfParts[CfgProdConfParts["ExtendedData"] = 1] = "ExtendedData";
10
+ CfgProdConfParts[CfgProdConfParts["ProdParams"] = 2] = "ProdParams";
11
+ CfgProdConfParts[CfgProdConfParts["SyncGroupState"] = 4] = "SyncGroupState";
12
+ })(CfgProdConfParts || (CfgProdConfParts = {}));
1
13
  /** Is the newer version of product configuration */
2
14
  export const isProductConf = (value) => !("selOptions" in value);
3
15
  /** Is the older version of product configuration */
@@ -149,27 +161,40 @@ export const compactStringToDtoProductConf = (versionAndConf) => {
149
161
  }
150
162
  return JSON.parse(expandDtoProductConfJsonKeys(jsonStringSwapCharsForUrl(conf)));
151
163
  };
152
- export const stripExtendedDataFromDtoProductConf = (conf) => {
164
+ export const stripExtendedDataFromDtoProductConf = (conf, toStrip) => {
153
165
  var _a, _b;
154
- return ({
155
- features: (_a = conf.features) === null || _a === void 0 ? void 0 : _a.map(stripExtendedDataFromDtoFeatureConf),
166
+ const stripped = {
167
+ features: (_a = conf.features) === null || _a === void 0 ? void 0 : _a.map((f) => stripExtendedDataFromDtoFeatureConf(f, toStrip)),
156
168
  additionalProducts: (_b = conf.additionalProducts) === null || _b === void 0 ? void 0 : _b.map(stripExtendedDataFromDtoAdditionalProductConfiguration),
157
- });
169
+ };
170
+ if ((toStrip & CfgProdConfParts.SyncGroupState) !== CfgProdConfParts.SyncGroupState) {
171
+ stripped.syncGroupState = conf.syncGroupState;
172
+ }
173
+ if ((toStrip & CfgProdConfParts.ProdParams) !== CfgProdConfParts.ProdParams) {
174
+ stripped.prodParams = conf.prodParams;
175
+ }
176
+ return stripped;
158
177
  };
159
- const stripExtendedDataFromDtoAdditionalProductConfiguration = (conf) => (Object.assign(Object.assign({}, stripExtendedDataFromDtoProductConf(conf)), { refKey: conf.refKey, selected: conf.selected }));
160
- const stripExtendedDataFromDtoFeatureConf = (conf) => {
178
+ const stripExtendedDataFromDtoAdditionalProductConfiguration = (conf, toStrip) => (Object.assign(Object.assign({}, stripExtendedDataFromDtoProductConf(conf, toStrip)), { refKey: conf.refKey, selected: conf.selected }));
179
+ const stripExtendedDataFromDtoFeatureConf = (conf, toStrip) => {
161
180
  var _a;
162
- return ({
181
+ const stripped = {
163
182
  code: conf.code,
164
- options: (_a = conf.options) === null || _a === void 0 ? void 0 : _a.map(stripExtendedDataFromDtoOptionConf),
165
- });
183
+ options: (_a = conf.options) === null || _a === void 0 ? void 0 : _a.map((o) => stripExtendedDataFromDtoOptionConf(o, toStrip)),
184
+ };
185
+ if ((toStrip & CfgProdConfParts.ExtendedData) !== CfgProdConfParts.ExtendedData) {
186
+ // Keep in sync with getDtoConf in CfgFeature
187
+ stripped.groupCode = conf.groupCode;
188
+ stripped.unit = conf.unit;
189
+ }
190
+ return stripped;
166
191
  };
167
- const stripExtendedDataFromDtoOptionConf = (conf) => {
192
+ const stripExtendedDataFromDtoOptionConf = (conf, toStrip) => {
168
193
  var _a;
169
194
  return ({
170
195
  code: conf.code,
171
196
  selected: conf.selected,
172
197
  numericValue: conf.numericValue,
173
- features: (_a = conf.features) === null || _a === void 0 ? void 0 : _a.map(stripExtendedDataFromDtoFeatureConf),
198
+ features: (_a = conf.features) === null || _a === void 0 ? void 0 : _a.map((f) => stripExtendedDataFromDtoFeatureConf(f, toStrip)),
174
199
  });
175
200
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configura/web-api",
3
- "version": "2.0.0",
3
+ "version": "2.1.0-alpha.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@configura/web-utilities": "2.0.0"
26
+ "@configura/web-utilities": "2.1.0-alpha.1"
27
27
  },
28
- "gitHead": "efc959fe673f0ef172d332fae1bd53093f88b134"
28
+ "gitHead": "0eec1ba88fc2fa4d0f3f9a36173818f721752786"
29
29
  }