@configura/web-api 2.0.0-alpha.2 → 2.0.0-alpha.20

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.
Files changed (52) hide show
  1. package/dist/CatalogueAPI.d.ts +73 -43
  2. package/dist/CatalogueAPI.js +37 -2
  3. package/dist/CfgProduct.d.ts +73 -11
  4. package/dist/CfgProduct.js +130 -29
  5. package/dist/CfgReferencePathHelper.d.ts +16 -3
  6. package/dist/CfgReferencePathHelper.js +14 -1
  7. package/dist/ConfigurationConverter.d.ts +13 -4
  8. package/dist/ConfigurationConverter.js +106 -12
  9. package/dist/io/CfgHistoryManager.d.ts +37 -4
  10. package/dist/io/CfgHistoryManager.js +76 -8
  11. package/dist/io/CfgHistoryToProdConfConnector.d.ts +7 -10
  12. package/dist/io/CfgHistoryToProdConfConnector.js +29 -38
  13. package/dist/io/CfgIOManager.d.ts +5 -0
  14. package/dist/io/CfgIOManager.js +20 -1
  15. package/dist/io/CfgIOProdConfConnector.d.ts +21 -17
  16. package/dist/io/CfgIOProdConfConnector.js +54 -37
  17. package/dist/io/CfgIOWarningSupplier.d.ts +4 -0
  18. package/dist/io/CfgIOWarningSupplier.js +1 -0
  19. package/dist/io/CfgObservableStateManager.d.ts +4 -0
  20. package/dist/io/CfgObservableStateManager.js +4 -0
  21. package/dist/io/CfgObservableStateToProdConfConnector.d.ts +4 -4
  22. package/dist/io/CfgObservableStateToProdConfConnector.js +4 -4
  23. package/dist/io/CfgWindowMessageManager.d.ts +2 -2
  24. package/dist/io/CfgWindowMessageManager.js +9 -2
  25. package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +4 -4
  26. package/dist/io/CfgWindowMessageToProdConfConnector.js +4 -4
  27. package/dist/productConfiguration/CfgFeature.d.ts +8 -6
  28. package/dist/productConfiguration/CfgFeature.js +19 -6
  29. package/dist/productConfiguration/CfgOption.d.ts +5 -5
  30. package/dist/productConfiguration/CfgOption.js +11 -5
  31. package/dist/productConfiguration/CfgProductConfiguration.d.ts +27 -15
  32. package/dist/productConfiguration/CfgProductConfiguration.js +54 -21
  33. package/dist/productConfiguration/filters.d.ts +2 -2
  34. package/dist/productConfiguration/productParamsGenerator.d.ts +3 -3
  35. package/dist/productConfiguration/utilitiesProductConfiguration.d.ts +1 -1
  36. package/dist/productConfiguration/utilitiesProductConfiguration.js +11 -4
  37. package/dist/productLoader.d.ts +3 -3
  38. package/dist/syncGroups/SyncGroupsHandler.d.ts +4 -1
  39. package/dist/syncGroups/SyncGroupsHandler.js +6 -2
  40. package/dist/syncGroups/SyncGroupsTransaction.js +34 -21
  41. package/dist/tasks/TaskHandler.d.ts +2 -2
  42. package/dist/tasks/TaskHandler.js +2 -1
  43. package/dist/tests/testData/dummyProductForTest.d.ts +2 -2
  44. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +1 -0
  45. package/dist/tests/testData/testDataCachedGetProduct.js +1 -0
  46. package/dist/tests/testData/testDataCachedPostValidate.js +1 -0
  47. package/dist/tests/testData/testDataProductAggregatedPrice.js +1 -0
  48. package/dist/tests/testData/testDataUpcharge.js +1 -0
  49. package/dist/utilitiesCatalogueData.d.ts +14 -9
  50. package/dist/utilitiesCatalogueData.js +7 -0
  51. package/dist/utilitiesCataloguePermission.d.ts +4 -4
  52. package/package.json +3 -3
@@ -1,17 +1,17 @@
1
- import { DtoConfProd } from "../CatalogueAPI.js";
1
+ import { DtoProductConf } from "../CatalogueAPI.js";
2
2
  import { CfgIOProdConfConnector, CfgProdConfMessage, CfgProdConfMessageVersions } from "./CfgIOProdConfConnector.js";
3
3
  import { CfgWindowMessageManager } from "./CfgWindowMessageManager.js";
4
4
  /**
5
5
  * Instantiating this will make Stage send product configuration changes using the post message-API.
6
6
  * It will also make Stage listen for incoming product configuration update messages.
7
7
  * This can be used to communicate in and out of an iframe for example.
8
- * @param doValidate Run server side product validation for incoming
9
8
  * @param sendVersions What versions of the productConfiguration shall be sent? Multiple can be selected
10
9
  * @param includeExtendedDataInSend Only for version 2.0. Includes unit and groupCode.
11
10
  * @param includeProdParamsInSend Only for version 2.0. Includes product params, in both main and additional products.
12
11
  */
13
12
  export declare class CfgWindowMessageToProdConfConnector extends CfgIOProdConfConnector<CfgProdConfMessage> {
14
- constructor(manager: CfgWindowMessageManager, doValidate?: boolean, sendVersions?: CfgProdConfMessageVersions, includeExtendedDataInSend?: boolean, includeProdParamsInSend?: boolean);
15
- protected makeSendData(conf: DtoConfProd, initial: boolean): CfgProdConfMessage;
13
+ private _sendVersions;
14
+ constructor(manager: CfgWindowMessageManager, _sendVersions?: CfgProdConfMessageVersions, includeExtendedDataInSend?: boolean, includeProdParamsInSend?: boolean);
15
+ protected makeSendData(conf: DtoProductConf, initial: boolean): CfgProdConfMessage;
16
16
  }
17
17
  //# sourceMappingURL=CfgWindowMessageToProdConfConnector.d.ts.map
@@ -3,16 +3,16 @@ import { CfgIOProdConfConnector, CfgProdConfMessageVersions, } from "./CfgIOProd
3
3
  * Instantiating this will make Stage send product configuration changes using the post message-API.
4
4
  * It will also make Stage listen for incoming product configuration update messages.
5
5
  * This can be used to communicate in and out of an iframe for example.
6
- * @param doValidate Run server side product validation for incoming
7
6
  * @param sendVersions What versions of the productConfiguration shall be sent? Multiple can be selected
8
7
  * @param includeExtendedDataInSend Only for version 2.0. Includes unit and groupCode.
9
8
  * @param includeProdParamsInSend Only for version 2.0. Includes product params, in both main and additional products.
10
9
  */
11
10
  export class CfgWindowMessageToProdConfConnector extends CfgIOProdConfConnector {
12
- constructor(manager, doValidate = true, sendVersions = CfgProdConfMessageVersions.V2dot0, includeExtendedDataInSend = false, includeProdParamsInSend = false) {
13
- super(manager, doValidate, sendVersions, includeExtendedDataInSend, includeProdParamsInSend);
11
+ constructor(manager, _sendVersions = CfgProdConfMessageVersions.V2dot0, includeExtendedDataInSend = false, includeProdParamsInSend = false) {
12
+ super(manager, includeExtendedDataInSend, includeProdParamsInSend);
13
+ this._sendVersions = _sendVersions;
14
14
  }
15
15
  makeSendData(conf, initial) {
16
- return this.makeMessage(conf, initial);
16
+ return CfgIOProdConfConnector.makeMessage(conf, initial, this._sendVersions);
17
17
  }
18
18
  }
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoConfFeature, DtoFeature, DtoSelectedOption, DtoSyncGroup, DtoSyncGroupMethods } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoFeatureConf, 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";
@@ -32,13 +32,13 @@ export declare type FeatureChangeNotification = {
32
32
  */
33
33
  export declare class _CfgFeatureInternal {
34
34
  readonly rawFeature: DtoFeature;
35
- private readonly allRawFeatures;
36
- readonly key: string;
35
+ private readonly rawFeatures;
36
+ private _key;
37
37
  readonly parent: _CfgProductConfigurationInternal | _CfgOptionInternal;
38
38
  readonly parentConfiguration: _CfgProductConfigurationInternal;
39
39
  readonly parentProduct: _CfgProductInternal;
40
40
  readonly rootProduct: _CfgProductInternal;
41
- constructor(rawFeature: DtoFeature, allRawFeatures: DtoFeature[], key: string, // Unique amongst siblings
41
+ constructor(rawFeature: DtoFeature, rawFeatures: DtoFeature[], _key: string, // Unique amongst siblings
42
42
  parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
43
43
  readonly selectionType: SelectionType;
44
44
  private _options;
@@ -48,6 +48,8 @@ export declare class _CfgFeatureInternal {
48
48
  readonly changeObservable: Observable<FeatureChangeNotification>;
49
49
  get code(): string;
50
50
  get groupCode(): string | undefined;
51
+ get key(): string;
52
+ set key(k: string);
51
53
  get isUseNumericValue(): boolean;
52
54
  get numericValue(): number | undefined;
53
55
  setNumericValue: (val: number) => Promise<boolean>;
@@ -99,7 +101,7 @@ export declare class _CfgFeatureInternal {
99
101
  * as nonexisting children can not call their parent.
100
102
  */
101
103
  _childHasChanged: (childOption: _CfgOptionInternal, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
102
- getDtoConf: (includeExtendedData: boolean) => DtoConfFeature;
104
+ getDtoConf: (includeExtendedData: boolean) => DtoFeatureConf;
103
105
  setApiSelection: (apiOptionSelectionMap: {
104
106
  [index: string]: DtoSelectedOption;
105
107
  } | undefined) => Promise<boolean>;
@@ -128,7 +130,7 @@ export declare class _CfgFeatureInternal {
128
130
  }
129
131
  export declare class CfgFeature {
130
132
  readonly _internal: _CfgFeatureInternal;
131
- static make(rawFeature: DtoFeature, allRawFeatures: DtoFeature[], key: string, parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgFeature;
133
+ static make(rawFeature: DtoFeature, rawFeatures: DtoFeature[], key: string, parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgFeature;
132
134
  /**
133
135
  * Makes an object wrapping the passed object. This is not a clone method,
134
136
  * it is a method to make a new outer reference. Like a shallow copy.
@@ -62,11 +62,11 @@ function doFreshRefOption(options, optionInternal, committed, beforeNotify) {
62
62
  * should be used and interacted with.
63
63
  */
64
64
  export class _CfgFeatureInternal {
65
- constructor(rawFeature, allRawFeatures, key, // Unique amongst siblings
65
+ constructor(rawFeature, rawFeatures, _key, // Unique amongst siblings
66
66
  parent, parentConfiguration, parentProduct, rootProduct) {
67
67
  this.rawFeature = rawFeature;
68
- this.allRawFeatures = allRawFeatures;
69
- this.key = key;
68
+ this.rawFeatures = rawFeatures;
69
+ this._key = _key;
70
70
  this.parent = parent;
71
71
  this.parentConfiguration = parentConfiguration;
72
72
  this.parentProduct = parentProduct;
@@ -128,6 +128,12 @@ export class _CfgFeatureInternal {
128
128
  }
129
129
  return result;
130
130
  };
131
+ // DtoFeatureConf is the newer more easily readable format for configuration. As
132
+ // the API:s are still using the older format (and will for the forseeable future) we need
133
+ // to support both formats. The new format can be converted to the old, but not the other
134
+ // way around. For that reason the get-method above uses the new format, and the set-method
135
+ // below the old format. As these functions are meant to only be used internally this should't
136
+ // cause too much confusion.
131
137
  this.setApiSelection = (apiOptionSelectionMap) => __awaiter(this, void 0, void 0, function* () {
132
138
  const selectionType = this.selectionType;
133
139
  const isGroup = selectionType === SelectionType.Group;
@@ -407,6 +413,12 @@ export class _CfgFeatureInternal {
407
413
  get groupCode() {
408
414
  return this.rawFeature.groupCode;
409
415
  }
416
+ get key() {
417
+ return this._key;
418
+ }
419
+ set key(k) {
420
+ this._key = k;
421
+ }
410
422
  get isUseNumericValue() {
411
423
  return this.rawFeature.numericOrder;
412
424
  }
@@ -512,7 +524,7 @@ export class _CfgFeatureInternal {
512
524
  const hasDuplicateDescription = someMatch(this.rawFeature.options, (l, r) => {
513
525
  return l.description.toLowerCase() === r.description.toLowerCase();
514
526
  });
515
- this._options = this.rawFeature.options.map((o) => CfgOption.make(o, this.allRawFeatures, hasDuplicateDescription, this, this.parentConfiguration, this.parentProduct, this.rootProduct));
527
+ this._options = this.rawFeature.options.map((o) => CfgOption.make(o, this.rawFeatures, hasDuplicateDescription, this, this.parentConfiguration, this.parentProduct, this.rootProduct));
516
528
  }
517
529
  return this._options;
518
530
  }
@@ -571,8 +583,8 @@ export class CfgFeature {
571
583
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
572
584
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
573
585
  }
574
- static make(rawFeature, allRawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct) {
575
- return new this(new _CfgFeatureInternal(rawFeature, allRawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
586
+ static make(rawFeature, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct) {
587
+ return new this(new _CfgFeatureInternal(rawFeature, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
576
588
  }
577
589
  /**
578
590
  * Makes an object wrapping the passed object. This is not a clone method,
@@ -591,6 +603,7 @@ export class CfgFeature {
591
603
  get selectionType() {
592
604
  return this._internal.selectionType;
593
605
  }
606
+ // Unique amongst siblings. Can change. Only use for presentation layer i.e. React.
594
607
  get key() {
595
608
  return this._internal.key;
596
609
  }
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoConfOption, DtoFeature, DtoOption, DtoSelectedOption } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoOption, DtoOptionConf, 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";
@@ -60,12 +60,12 @@ export declare enum ProductConfigurationBubbleMode {
60
60
  */
61
61
  export declare class _CfgOptionInternal {
62
62
  readonly rawOption: DtoOption;
63
- private readonly allRawFeatures;
63
+ private readonly rawFeatures;
64
64
  readonly parent: _CfgFeatureInternal;
65
65
  readonly parentConfiguration: _CfgProductConfigurationInternal;
66
66
  readonly parentProduct: _CfgProductInternal;
67
67
  readonly rootProduct: _CfgProductInternal;
68
- constructor(rawOption: DtoOption, allRawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
68
+ constructor(rawOption: DtoOption, rawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
69
69
  private _features;
70
70
  private _mtrlApplications;
71
71
  readonly key: string;
@@ -89,7 +89,7 @@ export declare class _CfgOptionInternal {
89
89
  get features(): CfgFeature[];
90
90
  /** Called by child to tell its parent that it has changed. */
91
91
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
92
- getDtoConf: (includeExtendedData: boolean) => DtoConfOption;
92
+ getDtoConf: (includeExtendedData: boolean) => DtoOptionConf;
93
93
  setApiSelection: (apiOptionSelection: DtoSelectedOption | undefined) => Promise<boolean>;
94
94
  structureCompare: (other: _CfgOptionInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
95
95
  tryMatchSelection: (other: CfgOption, descriptionMatch?: boolean) => Promise<boolean>;
@@ -99,7 +99,7 @@ export declare class _CfgOptionInternal {
99
99
  }
100
100
  export declare class CfgOption {
101
101
  readonly _internal: _CfgOptionInternal;
102
- static make(rawOption: DtoOption, allRawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgOption;
102
+ static make(rawOption: DtoOption, rawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgOption;
103
103
  /**
104
104
  * Makes an object wrapping the passed object. This is not a clone method,
105
105
  * it is a method to make a new outer reference. Like a shallow copy.
@@ -80,9 +80,9 @@ function doesChildrenShareOptionsCode(features) {
80
80
  * the class that should be used and interacted with.
81
81
  */
82
82
  export class _CfgOptionInternal {
83
- constructor(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
83
+ constructor(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
84
84
  this.rawOption = rawOption;
85
- this.allRawFeatures = allRawFeatures;
85
+ this.rawFeatures = rawFeatures;
86
86
  this.parent = parent;
87
87
  this.parentConfiguration = parentConfiguration;
88
88
  this.parentProduct = parentProduct;
@@ -132,6 +132,12 @@ export class _CfgOptionInternal {
132
132
  }
133
133
  return result;
134
134
  };
135
+ // DtoOptionConf is the newer more easily readable format for configuration. As
136
+ // the API:s are still using the older format (and will for the forseeable future) we need
137
+ // to support both formats. The new format can be converted to the old, but not the other
138
+ // way around. For that reason the get-method above uses the new format, and the set-method
139
+ // below the old format. As these functions are meant to only be used internally this should't
140
+ // cause too much confusion.
135
141
  this.setApiSelection = (apiOptionSelection) => __awaiter(this, void 0, void 0, function* () {
136
142
  let features;
137
143
  if (apiOptionSelection === undefined) {
@@ -304,7 +310,7 @@ export class _CfgOptionInternal {
304
310
  get features() {
305
311
  if (this._features === undefined) {
306
312
  const allRefs = this.rawOption.featureRefs || [];
307
- const features = syncCfgFeatures(allRefs, [], this.allRawFeatures, this, this.parentConfiguration, this.parentProduct, this.rootProduct);
313
+ const features = syncCfgFeatures(allRefs, [], this.rawFeatures, this, this.parentConfiguration, this.parentProduct, this.rootProduct);
308
314
  if (doesChildrenShareOptionsCode(features)) {
309
315
  throw new Error("Stage does not yet properly support Options that has multiple sub-features with overlapping option codes.");
310
316
  }
@@ -343,8 +349,8 @@ export class CfgOption {
343
349
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
344
350
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
345
351
  }
346
- static make(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
347
- return new this(new _CfgOptionInternal(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct));
352
+ static make(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
353
+ return new this(new _CfgOptionInternal(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct));
348
354
  }
349
355
  /**
350
356
  * Makes an object wrapping the passed object. This is not a clone method,
@@ -1,5 +1,5 @@
1
1
  import { LengthUnit, LengthValue, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoConfFeature, DtoFeature, DtoFeatureRef, DtoSelectedOption } from "../CatalogueAPI.js";
2
+ import { DtoFeature, DtoFeatureConf, DtoFeatureRef, 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";
@@ -17,14 +17,15 @@ export declare type StretchMap = Map<string, {
17
17
  * modified. CfgProductConfiguration is the class that should be used and interacted with.
18
18
  */
19
19
  export declare class _CfgProductConfigurationInternal {
20
- readonly allRawFeatures: DtoFeature[];
21
20
  readonly parentProduct: _CfgProductInternal;
22
21
  readonly rootProduct: _CfgProductInternal;
23
- static _makeUninitialized(rootFeatureRefs: DtoFeatureRef[], allRawFeatures: DtoFeature[], // Flat packed. All the features that can appear anyplace in the selection tree.
22
+ private readonly _initialRootFeatureRefs;
23
+ static _makeUninitialized(rootFeatureRefs: DtoFeatureRef[], rawFeatures: DtoFeature[], // Flat packed. All the features that can currently appear anyplace in the selection tree.
24
24
  parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): _CfgProductConfigurationInternal;
25
25
  private constructor();
26
26
  readonly key = "~";
27
27
  private _rootFeatureRefs;
28
+ readonly accumulatedRawFeatures: DtoFeature[];
28
29
  private _features;
29
30
  readonly stretchReferenceLengthsByMeasureParamCode: StretchMap;
30
31
  readonly changeObservable: Observable<ProductConfigurationChangeNotification>;
@@ -34,10 +35,12 @@ export declare class _CfgProductConfigurationInternal {
34
35
  _freshRefDescendants(): void;
35
36
  /** Called by child to tell its parent that it has changed. */
36
37
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
37
- getDtoConf: (includeExtendedData: boolean) => DtoConfFeature[];
38
+ getDtoConf: (includeExtendedData: boolean) => DtoFeatureConf[];
39
+ getApiSelection: () => DtoSelectedOption[];
38
40
  /**
39
41
  * When used internally the notifications are taken care off by the caller, but if set from
40
42
  * outside we want notifications to bubble all the way to the root.
43
+ * This method will not cause validation calls. Data is assumed to already be validated.
41
44
  */
42
45
  setApiSelection: (selectedOptions: DtoSelectedOption[], bubbleToRoot: boolean) => Promise<boolean>;
43
46
  structureCompare: (other: _CfgProductConfigurationInternal, strictOrder: boolean, descriptionMatch: boolean) => boolean;
@@ -48,7 +51,22 @@ export declare class _CfgProductConfigurationInternal {
48
51
  tryMatchSelection: (other: _CfgProductConfigurationInternal, descriptionMatch: boolean | undefined, validate: boolean) => Promise<boolean>;
49
52
  /** Only selected features. */
50
53
  _getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
51
- populateFeatures: (rootFeatureRefs: DtoFeatureRef[]) => void;
54
+ /**
55
+ * Extends the list of loaded potentially used features. Will warn for but ignore duplicates.
56
+ * Returns true if a change happened.
57
+ */
58
+ addRawFeatures: (rawFeatures: DtoFeature[], warnForDuplicates: boolean) => boolean;
59
+ private _hasRootFeaturesChanged;
60
+ /**
61
+ * True if what root Features are used is not the same as at initial load.
62
+ * This means that functional selection has happened.
63
+ */
64
+ get hasRootFeaturesChanged(): boolean;
65
+ /**
66
+ * Populates _features based on the passed @param rootFeatureRefs .
67
+ * @return true if a change happened.
68
+ */
69
+ populateFeatures: (rootFeatureRefs: DtoFeatureRef[]) => boolean;
52
70
  setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit) => Promise<boolean>;
53
71
  }
54
72
  export declare class CfgProductConfiguration {
@@ -58,7 +76,7 @@ export declare class CfgProductConfiguration {
58
76
  * CfgProductConfiguration, but is not properly initialized until the initDone-callback
59
77
  * has been called.
60
78
  */
61
- static make(initSuccess: (c: CfgProductConfiguration) => void, initFail: (error: Error) => void, rootFeatureRefs: DtoFeatureRef[], allRawFeatures: DtoFeature[], // Flat packed. All the features that can appear anyplace in the selection tree.
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.
62
80
  apiSelection: DtoSelectedOption[], parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgProductConfiguration;
63
81
  /**
64
82
  * Makes an object wrapping the passed object. This is not a clone method, it is a method to
@@ -78,11 +96,11 @@ export declare class CfgProductConfiguration {
78
96
  get rootProduct(): CfgProduct;
79
97
  get key(): string;
80
98
  /**
81
- * Every (unprocessed) feature which might be used in this product. This is constant for a
82
- * product load. What features are actually used is controlled by rootFeatureRefs and what
99
+ * Every (unprocessed) feature that is currently loaded for this product. This can be extended
100
+ * by validation calls. What features are actually used is controlled by rootFeatureRefs and what
83
101
  * options are selected.
84
102
  */
85
- get allRawFeatures(): DtoFeature[];
103
+ get rawFeatures(): DtoFeature[];
86
104
  /** What features are used in the root of this. This can change with new validate calls. */
87
105
  get rootFeatureRefs(): DtoFeatureRef[];
88
106
  /** The root features at the root of the selection tree. */
@@ -94,12 +112,6 @@ export declare class CfgProductConfiguration {
94
112
  * This method will cause validation calls.
95
113
  */
96
114
  tryMatchSelection: (other: CfgProductConfiguration, descriptionMatch?: boolean) => Promise<boolean>;
97
- getApiSelection: () => DtoSelectedOption[];
98
- /**
99
- * This method does not propagate its selections.
100
- * This method will not cause validation calls. Data is assumed to already be validated.
101
- */
102
- setApiSelection: (selectedOptions: DtoSelectedOption[]) => Promise<boolean>;
103
115
  /**
104
116
  * Set how stretched a certain measure should be measureParamCode is the measure to be
105
117
  * stretched referenceLength is a value relative to the initial length of the measure. If the
@@ -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 { convertDtoConfFeaturesToSelOptions } from "../ConfigurationConverter.js";
12
+ import { convertDtoFeatureConfsToSelOptions } from "../ConfigurationConverter.js";
13
13
  import { CfgFeature } from "./CfgFeature.js";
14
14
  import { ProductConfigurationBubbleMode } from "./CfgOption.js";
15
15
  import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
@@ -19,13 +19,13 @@ import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
19
19
  * modified. CfgProductConfiguration is the class that should be used and interacted with.
20
20
  */
21
21
  export class _CfgProductConfigurationInternal {
22
- constructor(allRawFeatures, // Flat packed. All the features that can appear anyplace in the selection tree.
23
- parentProduct, rootProduct) {
24
- this.allRawFeatures = allRawFeatures;
22
+ constructor(rawFeatures, parentProduct, rootProduct, _initialRootFeatureRefs) {
25
23
  this.parentProduct = parentProduct;
26
24
  this.rootProduct = rootProduct;
25
+ this._initialRootFeatureRefs = _initialRootFeatureRefs;
27
26
  this.key = "~";
28
27
  this._rootFeatureRefs = [];
28
+ this.accumulatedRawFeatures = []; // Flat packed. May be extended in validate calls.
29
29
  this._features = [];
30
30
  this.changeObservable = new Observable();
31
31
  this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
@@ -56,9 +56,11 @@ export class _CfgProductConfigurationInternal {
56
56
  yield this._notifyAllOfChange(bubbleMode, committed);
57
57
  });
58
58
  this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
59
+ this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
59
60
  /**
60
61
  * When used internally the notifications are taken care off by the caller, but if set from
61
62
  * outside we want notifications to bubble all the way to the root.
63
+ * This method will not cause validation calls. Data is assumed to already be validated.
62
64
  */
63
65
  this.setApiSelection = (selectedOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
64
66
  const featuresLength = this._features.length;
@@ -111,9 +113,39 @@ export class _CfgProductConfigurationInternal {
111
113
  agg.push(...feature._internal._getFeaturesWithCode(code));
112
114
  return agg;
113
115
  }, []);
116
+ /**
117
+ * Extends the list of loaded potentially used features. Will warn for but ignore duplicates.
118
+ * Returns true if a change happened.
119
+ */
120
+ this.addRawFeatures = (rawFeatures, warnForDuplicates) => {
121
+ let change = false;
122
+ const accumulatedRawFeatures = this.accumulatedRawFeatures;
123
+ for (const rawFeature of rawFeatures) {
124
+ const code = rawFeature.code;
125
+ if (accumulatedRawFeatures.find((f) => code === f.code)) {
126
+ if (warnForDuplicates) {
127
+ console.warn(`Feature ${code} was already loaded. Will ignore it.`);
128
+ }
129
+ continue;
130
+ }
131
+ accumulatedRawFeatures.push(rawFeature);
132
+ change = true;
133
+ }
134
+ return change;
135
+ };
136
+ this._hasRootFeaturesChanged = false;
137
+ /**
138
+ * Populates _features based on the passed @param rootFeatureRefs .
139
+ * @return true if a change happened.
140
+ */
114
141
  this.populateFeatures = (rootFeatureRefs) => {
142
+ if (compareArrays(this._rootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code, true)) {
143
+ return false;
144
+ }
115
145
  this._rootFeatureRefs = rootFeatureRefs;
116
- this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.allRawFeatures, this, this, this.parentProduct, this.rootProduct);
146
+ this._hasRootFeaturesChanged = !compareArrays(this._initialRootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code);
147
+ this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.accumulatedRawFeatures, this, this, this.parentProduct, this.rootProduct);
148
+ return true;
117
149
  };
118
150
  this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
119
151
  if (measureParamCode === "") {
@@ -158,6 +190,8 @@ export class _CfgProductConfigurationInternal {
158
190
  console.log(`Use "window['${dbgName}']" or window.conf to access conf.`);
159
191
  }
160
192
  /* eslint-enable */
193
+ this.addRawFeatures(rawFeatures, true);
194
+ this.populateFeatures(_initialRootFeatureRefs);
161
195
  /**
162
196
  * Although the measurement-datas are also passed in validate-calls they are only used at
163
197
  * initial product creation. The data is assumed to always be the same for a product, so
@@ -194,11 +228,9 @@ export class _CfgProductConfigurationInternal {
194
228
  }
195
229
  this.stretchReferenceLengthsByMeasureParamCode = stretchReferenceLengthsByMeasureParamCode;
196
230
  }
197
- static _makeUninitialized(rootFeatureRefs, allRawFeatures, // Flat packed. All the features that can appear anyplace in the selection tree.
231
+ static _makeUninitialized(rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
198
232
  parentProduct, rootProduct) {
199
- const configuration = new this(allRawFeatures, parentProduct, rootProduct);
200
- configuration.populateFeatures(rootFeatureRefs);
201
- return configuration;
233
+ return new this(rawFeatures, parentProduct, rootProduct, rootFeatureRefs);
202
234
  }
203
235
  get rootFeatureRefs() {
204
236
  return this._rootFeatureRefs;
@@ -215,6 +247,13 @@ export class _CfgProductConfigurationInternal {
215
247
  features[i] = CfgFeature._makeNewRefFrom(featureInternal);
216
248
  }
217
249
  }
250
+ /**
251
+ * True if what root Features are used is not the same as at initial load.
252
+ * This means that functional selection has happened.
253
+ */
254
+ get hasRootFeaturesChanged() {
255
+ return this._hasRootFeaturesChanged;
256
+ }
218
257
  }
219
258
  export class CfgProductConfiguration {
220
259
  /**
@@ -233,12 +272,6 @@ export class CfgProductConfiguration {
233
272
  */
234
273
  this.tryMatchSelection = (other, descriptionMatch = false // Match on case insensitive description, not code
235
274
  ) => __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
275
  /**
243
276
  * Set how stretched a certain measure should be measureParamCode is the measure to be
244
277
  * stretched referenceLength is a value relative to the initial length of the measure. If the
@@ -259,9 +292,9 @@ export class CfgProductConfiguration {
259
292
  * CfgProductConfiguration, but is not properly initialized until the initDone-callback
260
293
  * has been called.
261
294
  */
262
- static make(initSuccess, initFail, rootFeatureRefs, allRawFeatures, // Flat packed. All the features that can appear anyplace in the selection tree.
295
+ static make(initSuccess, initFail, rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
263
296
  apiSelection, parentProduct, rootProduct) {
264
- const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs, allRawFeatures, parentProduct, rootProduct);
297
+ const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs, rawFeatures, parentProduct, rootProduct);
265
298
  const external = new this(internal);
266
299
  // Note the async-callback at the end of the following line. The call is async.
267
300
  internal
@@ -289,12 +322,12 @@ export class CfgProductConfiguration {
289
322
  return this._internal.key;
290
323
  }
291
324
  /**
292
- * Every (unprocessed) feature which might be used in this product. This is constant for a
293
- * product load. What features are actually used is controlled by rootFeatureRefs and what
325
+ * Every (unprocessed) feature that is currently loaded for this product. This can be extended
326
+ * by validation calls. What features are actually used is controlled by rootFeatureRefs and what
294
327
  * options are selected.
295
328
  */
296
- get allRawFeatures() {
297
- return this._internal.allRawFeatures;
329
+ get rawFeatures() {
330
+ return this._internal.accumulatedRawFeatures;
298
331
  }
299
332
  /** What features are used in the root of this. This can change with new validate calls. */
300
333
  get rootFeatureRefs() {
@@ -1,6 +1,6 @@
1
1
  import { Filters, Matches } from "@configura/web-utilities";
2
- import { DtoCatalogueParamsWithoutCid, DtoLevel, DtoProductRef } from "../CatalogueAPI.js";
3
- export declare function applyCatalogueFilters<T extends DtoCatalogueParamsWithoutCid>(filters: Filters<DtoCatalogueParamsWithoutCid>, catalogues: T[]): [Matches<DtoCatalogueParamsWithoutCid>, T[]];
2
+ import { DtoCatalogueParams, DtoLevel, DtoProductRef } from "../CatalogueAPI.js";
3
+ export declare function applyCatalogueFilters<T extends DtoCatalogueParams>(filters: Filters<DtoCatalogueParams>, catalogues: T[]): [Matches<DtoCatalogueParams>, T[]];
4
4
  export interface ProductRefParams {
5
5
  partNr: string;
6
6
  }
@@ -1,16 +1,16 @@
1
1
  import { Filters } from "@configura/web-utilities";
2
- import { CatalogueAPI, DtoApplicationAreasResponse, DtoCatalogueParams, DtoCatalogueParamsWithLang } from "../CatalogueAPI.js";
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: DtoCatalogueParamsWithLang;
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: DtoCatalogueParams[], filters: Filters<ProductRefParams>, settings?: Partial<CfgProductSettings>): AsyncIterableIterator<GeneratedProductConfiguration | Error>;
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[], allRawFeatures: DtoFeature[], parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): 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, allRawFeatures, parent, parentConfiguration, parentProduct, rootProduct) {
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 = allRawFeatures.find((f) => c === f.code);
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 && cfgF.key === key);
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, allRawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
53
+ newFeatures.push(CfgFeature.make(f, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
47
54
  }
48
55
  return newFeatures;
49
56
  }
@@ -1,7 +1,7 @@
1
- import { DtoProductParamsWithLang, DtoValidateRequest } from "./CatalogueAPI.js";
1
+ import { DtoProductParamsWithCidAndLang, DtoValidateRequest } from "./CatalogueAPI.js";
2
2
  import { CfgProductResponse, CfgValidateResponse } from "./utilitiesCatalogueData.js";
3
- export declare type GetProduct = (params: DtoProductParamsWithLang) => Promise<CfgProductResponse>;
4
- export declare type PostValidate = (params: DtoProductParamsWithLang, body: DtoValidateRequest) => Promise<CfgValidateResponse>;
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;
@@ -24,7 +24,10 @@ export declare class SyncGroupsHandler {
24
24
  clone(): SyncGroupsHandler;
25
25
  get verboseLogging(): boolean;
26
26
  set verboseLogging(v: boolean);
27
- /** Used to initially apply the sync state onto a new product so that it is "in sync". */
27
+ /**
28
+ * Used to initially apply the sync state onto a new product so that it is "in sync"
29
+ * and to reapply the sync state when an optional additional product is selected.
30
+ */
28
31
  init(product: _CfgProductInternal, productLoader: ProductLoader): Promise<void>;
29
32
  /**
30
33
  * 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.
@@ -275,7 +276,10 @@ export class SyncGroupsHandler {
275
276
  set verboseLogging(v) {
276
277
  this._syncState.verboseLogging = v;
277
278
  }
278
- /** Used to initially apply the sync state onto a new product so that it is "in sync". */
279
+ /**
280
+ * Used to initially apply the sync state onto a new product so that it is "in sync"
281
+ * and to reapply the sync state when an optional additional product is selected.
282
+ */
279
283
  init(product, productLoader) {
280
284
  return __awaiter(this, void 0, void 0, function* () {
281
285
  const transaction = yield this.newTransaction(product, productLoader, true);