@configura/web-api 1.5.0-alpha.0 → 1.6.0-iotest.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/CatalogueAPI.d.ts +9 -2
  2. package/dist/CatalogueAPI.js +23 -0
  3. package/dist/CfgMeasure.d.ts +2 -2
  4. package/dist/CfgMeasure.js +1 -1
  5. package/dist/CfgProduct.d.ts +31 -4
  6. package/dist/CfgProduct.js +58 -20
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.js +4 -0
  9. package/dist/io/CfgHistoryManager.d.ts +30 -0
  10. package/dist/io/CfgHistoryManager.js +62 -0
  11. package/dist/io/CfgHistoryToProdConfConnector.d.ts +10 -0
  12. package/dist/io/CfgHistoryToProdConfConnector.js +18 -0
  13. package/dist/io/CfgIOManager.d.ts +29 -0
  14. package/dist/io/CfgIOManager.js +89 -0
  15. package/dist/io/CfgIOProdConfConnector.d.ts +31 -0
  16. package/dist/io/CfgIOProdConfConnector.js +100 -0
  17. package/dist/io/CfgWindowMessageManager.d.ts +13 -0
  18. package/dist/io/CfgWindowMessageManager.js +28 -0
  19. package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +13 -0
  20. package/dist/io/CfgWindowMessageToProdConfConnector.js +17 -0
  21. package/dist/productConfiguration/CfgFeature.d.ts +14 -0
  22. package/dist/productConfiguration/CfgFeature.js +15 -1
  23. package/dist/productConfiguration/CfgOption.js +1 -1
  24. package/dist/productConfiguration/CfgProductConfiguration.d.ts +2 -1
  25. package/dist/productConfiguration/CfgProductConfiguration.js +8 -9
  26. package/dist/productLoader.d.ts +1 -1
  27. package/dist/tasks/TaskHandler.js +4 -3
  28. package/dist/tasks/formats.d.ts +1 -3
  29. package/dist/tasks/formats.js +3 -4
  30. package/dist/tests/testData/dummyProductForTest.d.ts +2 -2
  31. package/dist/tests/testData/dummyProductForTest.js +1 -1
  32. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.d.ts +3 -3
  33. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +3 -3
  34. package/dist/tests/testData/testDataProductAggregatedPrice.d.ts +3 -3
  35. package/dist/tests/testData/testDataProductAggregatedPrice.js +2 -2
  36. package/dist/utilitiesCatalogueData.d.ts +1 -1
  37. package/dist/utilitiesCatalogueData.js +4 -3
  38. package/dist/utilitiesNumericValues.d.ts +1 -1
  39. package/package.json +3 -3
@@ -80,8 +80,9 @@ export interface ErrorResponse {
80
80
  code: number;
81
81
  eventId?: string;
82
82
  }
83
- /** ExportFormat - The values must be the file extension used by each format. */
84
- export declare type ExportFormat = "fbx" | "dwg" | "cmdrw" | "cmfav" | "cmsym";
83
+ /** ExportFormat - Format of the exported product, identical to the format's file extension. */
84
+ export declare type ExportFormat = "glb" | "gltf" | "fbx" | "dwg" | "cmdrw" | "cmfav" | "cmsym";
85
+ export declare const exportFormatNames: ExportFormat[];
85
86
  /** ExportRequest */
86
87
  export interface ExportRequest {
87
88
  format: ExportFormat;
@@ -102,6 +103,7 @@ export interface ExportStatus {
102
103
  }
103
104
  /** ExportStatusStatus - WIP */
104
105
  export declare type ExportStatusStatus = "pending" | "running" | "finished" | "failed";
106
+ export declare const exportStatusStatusNames: ExportStatusStatus[];
105
107
  /** Feature */
106
108
  export interface Feature {
107
109
  code: string;
@@ -338,6 +340,8 @@ export interface ProductData {
338
340
  depth?: string;
339
341
  description?: string;
340
342
  height?: string;
343
+ hideIfMainProduct?: boolean;
344
+ hideIfAdditionalProduct?: boolean;
341
345
  length?: string;
342
346
  mtrlApplications?: Array<MtrlApplication>;
343
347
  additionalProductRefs?: Array<AdditionalProductRef>;
@@ -379,6 +383,7 @@ export interface RefreshSessionTokenResponse {
379
383
  }
380
384
  /** RenderFormat */
381
385
  export declare type RenderFormat = "jpg" | "png";
386
+ export declare const renderFormatNames: RenderFormat[];
382
387
  /** RenderRequest */
383
388
  export interface RenderRequest {
384
389
  width: number;
@@ -402,6 +407,7 @@ export interface RenderStatus {
402
407
  }
403
408
  /** RenderStatusStatus - WIP */
404
409
  export declare type RenderStatusStatus = "pending" | "running" | "finished" | "failed";
410
+ export declare const renderStatusStatusNames: RenderStatusStatus[];
405
411
  /** SelectedOption */
406
412
  export interface SelectedOption {
407
413
  code: string;
@@ -422,6 +428,7 @@ export interface SyncGroup {
422
428
  }
423
429
  /** SyncGroupMethods */
424
430
  export declare type SyncGroupMethods = "pull" | "push" | "twoWay";
431
+ export declare const syncGroupMethodsNames: SyncGroupMethods[];
425
432
  /** TargetCameraArgs */
426
433
  export interface TargetCameraArgs {
427
434
  location?: Point;
@@ -9,6 +9,29 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  step((generator = generator.apply(thisArg, _arguments || [])).next());
10
10
  });
11
11
  };
12
+ export const exportFormatNames = [
13
+ "glb",
14
+ "gltf",
15
+ "fbx",
16
+ "dwg",
17
+ "cmdrw",
18
+ "cmfav",
19
+ "cmsym",
20
+ ];
21
+ export const exportStatusStatusNames = [
22
+ "pending",
23
+ "running",
24
+ "finished",
25
+ "failed",
26
+ ];
27
+ export const renderFormatNames = ["jpg", "png"];
28
+ export const renderStatusStatusNames = [
29
+ "pending",
30
+ "running",
31
+ "finished",
32
+ "failed",
33
+ ];
34
+ export const syncGroupMethodsNames = ["pull", "push", "twoWay"];
12
35
  export class APIError extends Error {
13
36
  }
14
37
  export class CatalogueAPI {
@@ -1,4 +1,4 @@
1
- import { Measurement, ValueWithUnit } from "./CatalogueAPI";
1
+ import { Measurement, ValueWithUnit } from "./CatalogueAPI.js";
2
2
  /**
3
3
  * Measures can be used to Anchor items (Models or Additional Products).
4
4
  *
@@ -19,7 +19,7 @@ export declare type CfgMeasurePriority = {
19
19
  };
20
20
  /**
21
21
  * This class strips the Measurement of things that are not actually used or relevant
22
- * to Stage, specifically anchoring and stretching. Measurments can also contain
22
+ * to Stage, specifically anchoring and stretching. Measurements can also contain
23
23
  * volume and area, but these are ignored. Here Measures are used to define defaults
24
24
  * such as its preferences when dealing with ambiguity or its default value.
25
25
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * This class strips the Measurement of things that are not actually used or relevant
3
- * to Stage, specifically anchoring and stretching. Measurments can also contain
3
+ * to Stage, specifically anchoring and stretching. Measurements can also contain
4
4
  * volume and area, but these are ignored. Here Measures are used to define defaults
5
5
  * such as its preferences when dealing with ambiguity or its default value.
6
6
  */
@@ -8,6 +8,7 @@ import { ProductLoader } from "./productLoader.js";
8
8
  import { CfgProductData, RootNodeSource } from "./utilitiesCatalogueData.js";
9
9
  export declare type CfgProductChangeNotification = {
10
10
  freshRef: CfgProduct;
11
+ committed: boolean;
11
12
  };
12
13
  export declare type CfgProductSettings = {
13
14
  /**
@@ -97,15 +98,32 @@ export declare class _CfgProductInternal {
97
98
  setSelected(v: boolean, bubbleMode: CfgProductBubbleMode): Promise<boolean>;
98
99
  get configuration(): CfgProductConfiguration;
99
100
  get rawProductData(): CfgProductData;
100
- _notifyAllOfChange: (bubbleMode: CfgProductBubbleMode) => Promise<void>;
101
+ /**
102
+ * Please note that this relates to the visibility in the Configuration tree.
103
+ * It does not affect the visibility of anything in the 3D view at all.
104
+ */
105
+ get visibleIfAdditionalProduct(): boolean;
106
+ /**
107
+ * Please note that this relates to the visibility in the Configuration tree.
108
+ * It does not affect the visibility of anything in the 3D view at all.
109
+ */
110
+ get visibleIfMainProduct(): boolean;
111
+ /**
112
+ * Please note that this relates to the visibility in the Configuration tree.
113
+ * It does not affect the visibility of anything in the 3D view at all.
114
+ */
115
+ get visible(): boolean;
116
+ _notifyAllOfChange: (bubbleMode: CfgProductBubbleMode, committed: boolean) => Promise<void>;
101
117
  /** Called when a child (additional product or the configuration) has changed. */
102
118
  private _childHasChanged;
103
119
  /** Called by child to tell its parent that it has changed. */
104
- _additionalProductHasChanged: (freshRef: CfgProduct, bubbleMode: CfgProductBubbleMode) => Promise<void>;
120
+ _additionalProductHasChanged: (freshRef: CfgProduct, bubbleMode: CfgProductBubbleMode, committed: boolean) => Promise<void>;
105
121
  /** Called by the configuration to tell its parent that it has changed. */
106
- _configurationHasChanged: (freshRef: CfgProductConfiguration, bubbleMode: ProductConfigurationBubbleMode) => Promise<void>;
122
+ _configurationHasChanged: (freshRef: CfgProductConfiguration, bubbleMode: ProductConfigurationBubbleMode, committed: boolean) => Promise<void>;
107
123
  getApiSelection: () => AdditionalProductConfiguration;
108
124
  setApiSelection: (s: AdditionalProductConfiguration, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
125
+ getApiSelectionAsString: () => string;
126
+ setFromApiSelectionString: (str: string, doValidate: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
109
127
  structureCompare: (other: _CfgProductInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
110
128
  tryMatchSelection: (other: _CfgProductInternal, descriptionMatch?: boolean, productLoaderForGroupedLoad?: ProductLoader | undefined) => Promise<boolean>;
111
129
  /** Only features in selected options and selected additional products. */
@@ -116,7 +134,7 @@ export declare class _CfgProductInternal {
116
134
  * product in isolation. The validation result is applied on the configuration. Then additional
117
135
  * products are synced (unloaded, loaded etc.) Finally the changes bubble up the tree.
118
136
  */
119
- _revalidate: (bubbleMode: CfgProductBubbleMode, productLoader: ProductLoader) => Promise<boolean>;
137
+ _revalidate: (bubbleMode: CfgProductBubbleMode, productLoader: ProductLoader, committed: boolean) => Promise<boolean>;
120
138
  /**
121
139
  * Based on this configuration find what additional products should be shown and not, unload
122
140
  * (i.e. destroy) those that should no longer be shown, load the new ones.
@@ -163,6 +181,13 @@ export declare class CfgProduct {
163
181
  * always true.
164
182
  */
165
183
  get selected(): boolean;
184
+ /**
185
+ * Please note that this relates to the visibility in the Configuration tree.
186
+ * It does not affect the visibility of anything in the 3D view at all.
187
+ * Visibility is affects the Configuration for this Product, but any Additional Products
188
+ * will not be affected.
189
+ */
190
+ get visible(): boolean;
166
191
  /**
167
192
  * Only applicable when this product is optional.
168
193
  * Setting this does not cause a validation call as toggling an optional additional product is
@@ -208,6 +233,8 @@ export declare class CfgProduct {
208
233
  */
209
234
  getApiSelection: () => AdditionalProductConfiguration;
210
235
  setApiSelection: (s: AdditionalProductConfiguration, doValidate?: boolean) => Promise<boolean>;
236
+ getApiSelectionAsString: () => string;
237
+ setFromApiSelectionString: (str: string, doValidate?: boolean) => Promise<boolean>;
211
238
  listenForChange: (l: SingleArgCallback<CfgProductChangeNotification>) => void;
212
239
  stopListenForChange: (l: SingleArgCallback<CfgProductChangeNotification>) => void;
213
240
  stopAllListenForChange: () => void;
@@ -76,31 +76,31 @@ export class _CfgProductInternal {
76
76
  additionalProduct.destroy();
77
77
  }
78
78
  };
79
- this._notifyAllOfChange = (bubbleMode) => __awaiter(this, void 0, void 0, function* () {
79
+ this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
80
80
  if (bubbleMode === CfgProductBubbleMode.Stop) {
81
81
  return;
82
82
  }
83
83
  const parent = this.parent;
84
84
  const freshRef = CfgProduct._makeNewRefFrom(this);
85
- this.changeObservable.notifyAll({ freshRef });
85
+ this.changeObservable.notifyAll({ freshRef, committed });
86
86
  if (parent !== undefined) {
87
87
  yield parent._additionalProductHasChanged(freshRef, bubbleMode === CfgProductBubbleMode.OneLevel
88
88
  ? CfgProductBubbleMode.Stop
89
- : bubbleMode);
89
+ : bubbleMode, committed);
90
90
  }
91
91
  });
92
92
  /** Called when a child (additional product or the configuration) has changed. */
93
- this._childHasChanged = (bubbleMode) => __awaiter(this, void 0, void 0, function* () {
93
+ this._childHasChanged = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
94
94
  if (bubbleMode === CfgProductBubbleMode.ToRootAndBubbleSelected &&
95
95
  this.optional &&
96
96
  !this.selected) {
97
97
  yield this.setSelected(true, bubbleMode);
98
98
  return;
99
99
  }
100
- yield this._notifyAllOfChange(bubbleMode);
100
+ yield this._notifyAllOfChange(bubbleMode, committed);
101
101
  });
102
102
  /** Called by child to tell its parent that it has changed. */
103
- this._additionalProductHasChanged = (freshRef, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
103
+ this._additionalProductHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
104
104
  const i = this.additionalProducts.findIndex((a) => a.isBackedBySame(freshRef));
105
105
  if (i !== -1) {
106
106
  // Child additional product might not be found. This probably means that propagate
@@ -110,31 +110,31 @@ export class _CfgProductInternal {
110
110
  // C no longer is part of the tree. Odd, but fully permitted.
111
111
  this.additionalProducts[i] = freshRef;
112
112
  }
113
- yield this._childHasChanged(bubbleMode);
113
+ yield this._childHasChanged(bubbleMode, committed);
114
114
  });
115
115
  /** Called by the configuration to tell its parent that it has changed. */
116
- this._configurationHasChanged = (freshRef, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
116
+ this._configurationHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
117
117
  this._configuration = freshRef;
118
118
  switch (bubbleMode) {
119
119
  case ProductConfigurationBubbleMode.ValidateAndBubbleSelected:
120
120
  // The revalidate call will continue the bubble
121
- yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, this._productLoaderRaw);
121
+ yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, this._productLoaderRaw, committed);
122
122
  return;
123
123
  case ProductConfigurationBubbleMode.Validate:
124
124
  // The revalidate call will continue the bubble
125
- yield this._revalidate(CfgProductBubbleMode.ToRoot, this._productLoaderRaw);
125
+ yield this._revalidate(CfgProductBubbleMode.ToRoot, this._productLoaderRaw, committed);
126
126
  return;
127
127
  case ProductConfigurationBubbleMode.ToParentProduct:
128
128
  // Do not continue bubble as we have reached the parent CfgProduct
129
129
  return;
130
130
  case ProductConfigurationBubbleMode.OneLevel:
131
- yield this._childHasChanged(CfgProductBubbleMode.OneLevel);
131
+ yield this._childHasChanged(CfgProductBubbleMode.OneLevel, committed);
132
132
  return;
133
133
  case ProductConfigurationBubbleMode.Stop:
134
- yield this._childHasChanged(CfgProductBubbleMode.Stop);
134
+ yield this._childHasChanged(CfgProductBubbleMode.Stop, committed);
135
135
  return;
136
136
  case ProductConfigurationBubbleMode.ToRoot:
137
- yield this._childHasChanged(CfgProductBubbleMode.ToRoot);
137
+ yield this._childHasChanged(CfgProductBubbleMode.ToRoot, committed);
138
138
  return;
139
139
  }
140
140
  });
@@ -180,16 +180,20 @@ export class _CfgProductInternal {
180
180
  change = true;
181
181
  }
182
182
  if (doValidate && configurationChange) {
183
- yield this._revalidate(CfgProductBubbleMode.ToRoot, productLoaderForGroupedLoad);
183
+ yield this._revalidate(CfgProductBubbleMode.ToRoot, productLoaderForGroupedLoad, true);
184
184
  }
185
185
  else if (change) {
186
186
  // As setApiSelection is done recursively each level takes care of its own notifications
187
187
  // so we only need to bubble one level to notify this and swap out the reference in the
188
188
  // parent.
189
- yield this._notifyAllOfChange(CfgProductBubbleMode.OneLevel);
189
+ yield this._notifyAllOfChange(CfgProductBubbleMode.OneLevel, true);
190
190
  }
191
191
  return change;
192
192
  });
193
+ this.getApiSelectionAsString = () => JSON.stringify(this.getApiSelection(), undefined, "");
194
+ this.setFromApiSelectionString = (str, doValidate, productLoaderForGroupedLoad) => __awaiter(this, void 0, void 0, function* () {
195
+ return this.setApiSelection(JSON.parse(decodeURIComponent(str)), doValidate, productLoaderForGroupedLoad);
196
+ });
193
197
  this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => {
194
198
  if (!this.configuration.structureCompare(other.configuration, strictOrder, descriptionMatch)) {
195
199
  return false;
@@ -212,10 +216,10 @@ export class _CfgProductInternal {
212
216
  const configurationChange = yield this.configuration._internal.tryMatchSelection(other.configuration._internal, descriptionMatch, false);
213
217
  if (configurationChange) {
214
218
  change = true;
215
- yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, productLoaderForGroupedLoad);
219
+ yield this._revalidate(CfgProductBubbleMode.ToRootAndBubbleSelected, productLoaderForGroupedLoad, true);
216
220
  }
217
221
  else if (change) {
218
- yield this._notifyAllOfChange(CfgProductBubbleMode.ToRootAndBubbleSelected);
222
+ yield this._notifyAllOfChange(CfgProductBubbleMode.ToRootAndBubbleSelected, true);
219
223
  }
220
224
  const thisAdditionalProducts = this.additionalProducts;
221
225
  const otherAdditionalProducts = other.additionalProducts;
@@ -264,7 +268,7 @@ export class _CfgProductInternal {
264
268
  * product in isolation. The validation result is applied on the configuration. Then additional
265
269
  * products are synced (unloaded, loaded etc.) Finally the changes bubble up the tree.
266
270
  */
267
- this._revalidate = (bubbleMode, productLoader) => __awaiter(this, void 0, void 0, function* () {
271
+ this._revalidate = (bubbleMode, productLoader, committed) => __awaiter(this, void 0, void 0, function* () {
268
272
  const { _configuration: configuration } = this;
269
273
  const token = this.loadingObservable.startChildLoading();
270
274
  this._revalidateInProgressToken = token;
@@ -303,7 +307,7 @@ export class _CfgProductInternal {
303
307
  if (this._destroyed) {
304
308
  return false;
305
309
  }
306
- yield this._notifyAllOfChange(bubbleMode);
310
+ yield this._notifyAllOfChange(bubbleMode, committed);
307
311
  return true;
308
312
  }
309
313
  catch (e) {
@@ -461,7 +465,7 @@ export class _CfgProductInternal {
461
465
  return false;
462
466
  }
463
467
  this._selected = v;
464
- yield this._notifyAllOfChange(bubbleMode);
468
+ yield this._notifyAllOfChange(bubbleMode, true);
465
469
  return true;
466
470
  });
467
471
  }
@@ -471,6 +475,29 @@ export class _CfgProductInternal {
471
475
  get rawProductData() {
472
476
  return this._rawProductData;
473
477
  }
478
+ /**
479
+ * Please note that this relates to the visibility in the Configuration tree.
480
+ * It does not affect the visibility of anything in the 3D view at all.
481
+ */
482
+ get visibleIfAdditionalProduct() {
483
+ return this.rawProductData.hideIfAdditionalProduct !== true;
484
+ }
485
+ /**
486
+ * Please note that this relates to the visibility in the Configuration tree.
487
+ * It does not affect the visibility of anything in the 3D view at all.
488
+ */
489
+ get visibleIfMainProduct() {
490
+ return this.rawProductData.hideIfMainProduct !== true;
491
+ }
492
+ /**
493
+ * Please note that this relates to the visibility in the Configuration tree.
494
+ * It does not affect the visibility of anything in the 3D view at all.
495
+ */
496
+ get visible() {
497
+ return this.isAdditionalProduct
498
+ ? this.visibleIfAdditionalProduct
499
+ : this.visibleIfMainProduct;
500
+ }
474
501
  }
475
502
  _CfgProductInternal.make = (productLoaderRaw, productLoaderForGroupedLoad, // Used when instantiating the current product
476
503
  lang, catId, partNumber, settings, optional, loadingObservable, refKey, refDescription, parent, root, transform, anchor) => __awaiter(void 0, void 0, void 0, function* () {
@@ -531,6 +558,8 @@ export class CfgProduct {
531
558
  */
532
559
  this.getApiSelection = () => this._internal.getApiSelection();
533
560
  this.setApiSelection = (s, doValidate = false) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setApiSelection(s, doValidate); });
561
+ this.getApiSelectionAsString = () => this._internal.getApiSelectionAsString();
562
+ this.setFromApiSelectionString = (str, doValidate = false) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.setFromApiSelectionString(str, doValidate); });
534
563
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
535
564
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
536
565
  this.stopAllListenForChange = () => this._internal.changeObservable.stopAllListen();
@@ -589,6 +618,15 @@ export class CfgProduct {
589
618
  get selected() {
590
619
  return this._internal.selected;
591
620
  }
621
+ /**
622
+ * Please note that this relates to the visibility in the Configuration tree.
623
+ * It does not affect the visibility of anything in the 3D view at all.
624
+ * Visibility is affects the Configuration for this Product, but any Additional Products
625
+ * will not be affected.
626
+ */
627
+ get visible() {
628
+ return this._internal.visible;
629
+ }
592
630
  get rawProductData() {
593
631
  return this._internal.rawProductData;
594
632
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
+ export * from "./io/CfgHistoryManager.js";
4
+ export * from "./io/CfgHistoryToProdConfConnector.js";
5
+ export * from "./io/CfgWindowMessageManager.js";
6
+ export * from "./io/CfgWindowMessageToProdConfConnector.js";
3
7
  export * from "./material/CfgMaterialMapping.js";
4
8
  export * from "./material/CfgMtrlApplication.js";
5
9
  export * from "./material/CfgMtrlApplicationSource.js";
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from "./CatalogueAPI.js";
2
2
  export * from "./CfgProduct.js";
3
+ export * from "./io/CfgHistoryManager.js";
4
+ export * from "./io/CfgHistoryToProdConfConnector.js";
5
+ export * from "./io/CfgWindowMessageManager.js";
6
+ export * from "./io/CfgWindowMessageToProdConfConnector.js";
3
7
  export * from "./material/CfgMaterialMapping.js";
4
8
  export * from "./material/CfgMtrlApplication.js";
5
9
  export * from "./material/CfgMtrlApplicationSource.js";
@@ -0,0 +1,30 @@
1
+ import { CfgIOManager } from "./CfgIOManager.js";
2
+ export declare type CfgHistoryManagerSendData<D> = {
3
+ message: D;
4
+ qsKeyValues: Map<string, string | undefined>;
5
+ };
6
+ /**
7
+ * Instantiating the class will use the history api to update your
8
+ * url with configuration changes
9
+ * Only handles configuration, not product
10
+ */
11
+ export declare class CfgHistoryManager<D extends {
12
+ initial: boolean;
13
+ }> extends CfgIOManager<"popstate", CfgHistoryManagerSendData<D>> {
14
+ private readonly _useHistoryPush;
15
+ /**
16
+ * @param _useHistoryPush As opposed to replace. Push makes the web browser navigation buttons navigate configuration changes. Replace just updates the URL.
17
+ */
18
+ constructor(_useHistoryPush: boolean);
19
+ protected doSend(messageKey: string, data: CfgHistoryManagerSendData<D>): void;
20
+ private static _makeUpdatedUrl;
21
+ private static _makeUpdatedQueryString;
22
+ /**
23
+ * @returns The current query string as a Map
24
+ */
25
+ static _currentQsKeyValues(): Map<string, string>;
26
+ private static _makeUpdatedState;
27
+ protected readonly eventType = "popstate";
28
+ protected getDataFromEvent(event: PopStateEvent): unknown;
29
+ }
30
+ //# sourceMappingURL=CfgHistoryManager.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { mapQueryString, unmapQueryString } from "@configura/web-utilities";
2
+ import { CfgIOManager } from "./CfgIOManager.js";
3
+ /**
4
+ * Instantiating the class will use the history api to update your
5
+ * url with configuration changes
6
+ * Only handles configuration, not product
7
+ */
8
+ export class CfgHistoryManager extends CfgIOManager {
9
+ /**
10
+ * @param _useHistoryPush As opposed to replace. Push makes the web browser navigation buttons navigate configuration changes. Replace just updates the URL.
11
+ */
12
+ constructor(_useHistoryPush) {
13
+ super();
14
+ this._useHistoryPush = _useHistoryPush;
15
+ this.eventType = "popstate";
16
+ }
17
+ doSend(messageKey, data) {
18
+ const { qsKeyValues, message } = data;
19
+ const newUrl = CfgHistoryManager._makeUpdatedUrl(qsKeyValues);
20
+ const newState = CfgHistoryManager._makeUpdatedState(message, messageKey);
21
+ if (!message.initial && this._useHistoryPush) {
22
+ window.history.pushState(newState, "", newUrl);
23
+ }
24
+ else {
25
+ window.history.replaceState(newState, "", newUrl);
26
+ }
27
+ }
28
+ static _makeUpdatedUrl(qsKeyValues) {
29
+ const qs = this._makeUpdatedQueryString(qsKeyValues);
30
+ return `${window.location.origin}${window.location.pathname}${qs ? "?" : ""}${qs}${window.location.hash}`;
31
+ }
32
+ static _makeUpdatedQueryString(qsKeyValues) {
33
+ const currentKeyValues = this._currentQsKeyValues();
34
+ for (const [key, value] of qsKeyValues) {
35
+ if (value === undefined) {
36
+ currentKeyValues.delete(key);
37
+ }
38
+ else {
39
+ currentKeyValues.set(key, value);
40
+ }
41
+ }
42
+ return unmapQueryString(currentKeyValues);
43
+ }
44
+ /**
45
+ * @returns The current query string as a Map
46
+ */
47
+ static _currentQsKeyValues() {
48
+ return mapQueryString(window.location.search);
49
+ }
50
+ static _makeUpdatedState(message, messageKey) {
51
+ let messages = {};
52
+ const currentState = window.history.state;
53
+ if (CfgIOManager.isIOContainer(currentState)) {
54
+ messages = currentState.messages;
55
+ }
56
+ messages[messageKey] = message;
57
+ return CfgIOManager.makeContainer(messages);
58
+ }
59
+ getDataFromEvent(event) {
60
+ return event.state;
61
+ }
62
+ }
@@ -0,0 +1,10 @@
1
+ import { CfgHistoryManager, CfgHistoryManagerSendData } from "./CfgHistoryManager.js";
2
+ import { CfgIOProdConfConnector, CfgProdConfMessage } from "./CfgIOProdConfConnector.js";
3
+ export declare const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
4
+ export declare class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector<"popstate", CfgHistoryManagerSendData<CfgProdConfMessage>, CfgHistoryManager<CfgProdConfMessage>> {
5
+ private readonly _qsKey;
6
+ constructor(manager: CfgHistoryManager<CfgProdConfMessage>, _qsKey?: string, doValidate?: boolean);
7
+ protected getInitialProdConf(): string | undefined;
8
+ protected makeSendData(prodConfAsString: string, initial: boolean): CfgHistoryManagerSendData<CfgProdConfMessage>;
9
+ }
10
+ //# sourceMappingURL=CfgHistoryToProdConfConnector.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { CfgHistoryManager } from "./CfgHistoryManager.js";
2
+ import { CfgIOProdConfConnector } from "./CfgIOProdConfConnector.js";
3
+ export const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
4
+ export class CfgHistoryToProdConfConnector extends CfgIOProdConfConnector {
5
+ constructor(manager, _qsKey = STAGE_PROD_CONF_MESSAGE_KEY, doValidate = true) {
6
+ super(manager, doValidate);
7
+ this._qsKey = _qsKey;
8
+ }
9
+ getInitialProdConf() {
10
+ return CfgHistoryManager._currentQsKeyValues().get(this._qsKey);
11
+ }
12
+ makeSendData(prodConfAsString, initial) {
13
+ return {
14
+ message: this.makeMessage(prodConfAsString, initial),
15
+ qsKeyValues: new Map([[STAGE_PROD_CONF_MESSAGE_KEY, prodConfAsString]]),
16
+ };
17
+ }
18
+ }
@@ -0,0 +1,29 @@
1
+ declare type ConfiguraShebang = "c0nf1guraarug1fn0c";
2
+ declare type Listener = (m: unknown) => Promise<void>;
3
+ export declare type CfgIOContainer = {
4
+ shebang: ConfiguraShebang;
5
+ messages: {
6
+ [index: string]: unknown;
7
+ };
8
+ };
9
+ export declare abstract class CfgIOManager<K extends keyof WindowEventMap, S> {
10
+ static isIOContainer: (data: any) => data is CfgIOContainer;
11
+ static hasIOContainerMessageKey: (container: CfgIOContainer, messageKey: string) => boolean;
12
+ static getMessageFromIOContainer: (container: any, messageKey: string) => unknown;
13
+ static makeContainer: (messages: {
14
+ [index: string]: unknown;
15
+ }) => CfgIOContainer;
16
+ private _inhibitSend;
17
+ private _listeners;
18
+ private _getIndexOfListener;
19
+ listen: (l: Listener, messageKey: string) => void;
20
+ stopListen: (l: Listener) => void;
21
+ private _containerListenerBound;
22
+ protected _containerListener(event: WindowEventMap[K]): void;
23
+ send: (messageKey: string, data: S) => void;
24
+ protected abstract doSend(messageKey: string, data: S): void;
25
+ protected abstract readonly eventType: K;
26
+ protected abstract getDataFromEvent(event: WindowEventMap[K]): unknown;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=CfgIOManager.d.ts.map
@@ -0,0 +1,89 @@
1
+ const CONFIGURA_SHEBANG = "c0nf1guraarug1fn0c";
2
+ export class CfgIOManager {
3
+ constructor() {
4
+ // A lock to avoid circular write
5
+ this._inhibitSend = false;
6
+ this._listeners = [];
7
+ this._getIndexOfListener = (l) => this._listeners.findIndex((item) => l === item.l);
8
+ this.listen = (l, messageKey) => {
9
+ if (this._getIndexOfListener(l) !== -1) {
10
+ console.warn("Tried to add listener twice");
11
+ return;
12
+ }
13
+ const startListenToWindow = this._listeners.length === 0;
14
+ this._listeners.push({ l, messageKey });
15
+ if (startListenToWindow) {
16
+ window.addEventListener(this.eventType, this._containerListenerBound);
17
+ }
18
+ };
19
+ this.stopListen = (l) => {
20
+ const i = this._getIndexOfListener(l);
21
+ if (i === -1) {
22
+ console.warn("Tried to stopListen on unknown listener");
23
+ return;
24
+ }
25
+ this._listeners.splice(i, 1);
26
+ if (this._listeners.length === 0) {
27
+ window.removeEventListener(this.eventType, this._containerListenerBound);
28
+ }
29
+ };
30
+ this._containerListenerBound = this._containerListener.bind(this);
31
+ this.send = (messageKey, data) => {
32
+ if (this._inhibitSend) {
33
+ return;
34
+ }
35
+ this.doSend(messageKey, data);
36
+ };
37
+ }
38
+ _containerListener(event) {
39
+ const data = this.getDataFromEvent(event);
40
+ if (!CfgIOManager.isIOContainer(data)) {
41
+ return;
42
+ }
43
+ // The 15 or so rows below is one of the cases where I believe building a clever
44
+ // data structure of so would probably be worse for performance than just looping
45
+ // as the subscribers are expected to be very few
46
+ const listeners = this._listeners;
47
+ const allMessageKeys = listeners.reduce((a, c) => {
48
+ a.add(c.messageKey);
49
+ return a;
50
+ }, new Set());
51
+ this._inhibitSend = true;
52
+ const promises = [];
53
+ for (const messageKey of allMessageKeys) {
54
+ if (!CfgIOManager.hasIOContainerMessageKey(data, messageKey)) {
55
+ continue;
56
+ }
57
+ const message = CfgIOManager.getMessageFromIOContainer(data, messageKey);
58
+ for (const item of listeners) {
59
+ if (item.messageKey !== messageKey) {
60
+ continue;
61
+ }
62
+ promises.push(item.l(message));
63
+ }
64
+ }
65
+ Promise.all(promises)
66
+ .then(() => {
67
+ this._inhibitSend = false;
68
+ })
69
+ .catch(() => {
70
+ this._inhibitSend = false;
71
+ });
72
+ }
73
+ }
74
+ CfgIOManager.isIOContainer = (data) => data && data.shebang === CONFIGURA_SHEBANG;
75
+ CfgIOManager.hasIOContainerMessageKey = (container, messageKey) => messageKey in container.messages;
76
+ CfgIOManager.getMessageFromIOContainer = (container, messageKey) => {
77
+ if (!CfgIOManager.isIOContainer(container)) {
78
+ throw new Error("The passed data was not a CfgIOContainer. It is to be expected that such data messages can arrive, so please use isIOContainer function to filter them out before calling this.");
79
+ }
80
+ if (!CfgIOManager.hasIOContainerMessageKey(container, messageKey)) {
81
+ throw new Error(`The passed data did not have the messageKey "${messageKey}". You can test for this using hasIOContainerMessageKey function.`);
82
+ }
83
+ // It is assumed that if a message arrives with the right subMessageKey it can cast to T
84
+ return container.messages[messageKey];
85
+ };
86
+ CfgIOManager.makeContainer = (messages) => ({
87
+ shebang: CONFIGURA_SHEBANG,
88
+ messages,
89
+ });
@@ -0,0 +1,31 @@
1
+ import { CfgProduct, CfgProductChangeNotification } from "../CfgProduct.js";
2
+ import { CfgIOManager } from "./CfgIOManager.js";
3
+ export declare type CfgProdConfMessage = {
4
+ version: string;
5
+ initial: boolean;
6
+ prodConfAsString: string;
7
+ };
8
+ export declare const STAGE_PROD_CONF_MESSAGE_KEY = "stageProdConf";
9
+ export declare const STAGE_PROD_CONF_MESSAGE_VERSION = "1.0";
10
+ export declare type ProdConfCallback = (prodConfAsString: string) => Promise<void>;
11
+ export declare abstract class CfgIOProdConfConnector<K extends keyof WindowEventMap, S, M extends CfgIOManager<K, S>> {
12
+ protected readonly _ioManager: M;
13
+ protected readonly _doValidate: boolean;
14
+ protected _product: CfgProduct | undefined;
15
+ private _stopListenToMessage;
16
+ private _stopListenToProdConf;
17
+ constructor(_ioManager: M, _doValidate: boolean);
18
+ setProduct: (product: CfgProduct | undefined) => Promise<void>;
19
+ protected abstract getInitialProdConf(): string | undefined;
20
+ protected abstract makeSendData(prodConfAsString: string, initial: boolean): S;
21
+ makeMessage(prodConfAsString: string, initial: boolean): CfgProdConfMessage;
22
+ makeMessageListener(callback: ProdConfCallback): (message: unknown) => Promise<void>;
23
+ /**
24
+ * Register the callback to listen for Product Configuration messages
25
+ * @returns A function which when called will cancel listening
26
+ */
27
+ listenForMessage(callback: ProdConfCallback): () => void;
28
+ makeProdConfListener(callback: ProdConfCallback): (n: CfgProductChangeNotification) => void;
29
+ listenForProdConf(product: CfgProduct, callback: ProdConfCallback): () => void;
30
+ }
31
+ //# sourceMappingURL=CfgIOProdConfConnector.d.ts.map
@@ -0,0 +1,100 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ export const STAGE_PROD_CONF_MESSAGE_KEY = "stageProdConf";
11
+ export const STAGE_PROD_CONF_MESSAGE_VERSION = "1.0";
12
+ export class CfgIOProdConfConnector {
13
+ constructor(_ioManager, _doValidate) {
14
+ this._ioManager = _ioManager;
15
+ this._doValidate = _doValidate;
16
+ this._stopListenToMessage = undefined;
17
+ this._stopListenToProdConf = undefined;
18
+ this.setProduct = (product) => __awaiter(this, void 0, void 0, function* () {
19
+ var _a, _b;
20
+ const currentProduct = this._product;
21
+ const newProduct = product;
22
+ this._product = newProduct;
23
+ // If same product don't do anything at all
24
+ if (currentProduct !== undefined &&
25
+ newProduct !== undefined &&
26
+ currentProduct.isBackedBySame(newProduct)) {
27
+ return;
28
+ }
29
+ if (currentProduct !== undefined) {
30
+ (_a = this._stopListenToMessage) === null || _a === void 0 ? void 0 : _a.call(this);
31
+ (_b = this._stopListenToProdConf) === null || _b === void 0 ? void 0 : _b.call(this);
32
+ }
33
+ if (newProduct === undefined) {
34
+ return;
35
+ }
36
+ if (currentProduct === undefined) {
37
+ const initialProdConf = this.getInitialProdConf();
38
+ if (initialProdConf !== undefined) {
39
+ yield newProduct.setFromApiSelectionString(initialProdConf, this._doValidate);
40
+ }
41
+ }
42
+ else {
43
+ this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, this.makeSendData(newProduct.getApiSelectionAsString(), true));
44
+ }
45
+ this._stopListenToMessage = this.listenForMessage((prodConfAsString) => __awaiter(this, void 0, void 0, function* () {
46
+ if (prodConfAsString === newProduct.getApiSelectionAsString()) {
47
+ return;
48
+ }
49
+ yield newProduct.setFromApiSelectionString(prodConfAsString, this._doValidate);
50
+ }));
51
+ this._stopListenToProdConf = this.listenForProdConf(newProduct, (prodConfAsString) => __awaiter(this, void 0, void 0, function* () {
52
+ this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, this.makeSendData(prodConfAsString, false));
53
+ }));
54
+ });
55
+ }
56
+ makeMessage(prodConfAsString, initial) {
57
+ return {
58
+ version: STAGE_PROD_CONF_MESSAGE_VERSION,
59
+ initial,
60
+ prodConfAsString,
61
+ };
62
+ }
63
+ makeMessageListener(callback) {
64
+ return (message) => __awaiter(this, void 0, void 0, function* () {
65
+ const { version, prodConfAsString } = message;
66
+ if (version !== "1.0") {
67
+ console.error(`The a message was passed with an unsupported version "${version}". Currently only ${STAGE_PROD_CONF_MESSAGE_VERSION} is supported.`);
68
+ return;
69
+ }
70
+ yield callback(prodConfAsString);
71
+ });
72
+ }
73
+ /**
74
+ * Register the callback to listen for Product Configuration messages
75
+ * @returns A function which when called will cancel listening
76
+ */
77
+ listenForMessage(callback) {
78
+ const ioManager = this._ioManager;
79
+ const listener = this.makeMessageListener(callback);
80
+ ioManager.listen(listener, STAGE_PROD_CONF_MESSAGE_KEY);
81
+ return () => {
82
+ ioManager.stopListen(listener);
83
+ };
84
+ }
85
+ makeProdConfListener(callback) {
86
+ return (n) => {
87
+ if (!n.committed) {
88
+ return;
89
+ }
90
+ callback(n.freshRef.getApiSelectionAsString());
91
+ };
92
+ }
93
+ listenForProdConf(product, callback) {
94
+ const listener = this.makeProdConfListener(callback);
95
+ product.listenForChange(listener);
96
+ return () => {
97
+ product.stopListenForChange(listener);
98
+ };
99
+ }
100
+ }
@@ -0,0 +1,13 @@
1
+ import { CfgIOManager } from "./CfgIOManager.js";
2
+ export declare type CfgWindowMessageManagerSendData = unknown;
3
+ export declare class CfgWindowMessageManager extends CfgIOManager<"message", CfgWindowMessageManagerSendData> {
4
+ private readonly _remoteEnds;
5
+ private readonly _targetOrigin;
6
+ private readonly _acceptableMessageOrigin?;
7
+ constructor(_remoteEnds: Window[], _targetOrigin?: string, _acceptableMessageOrigin?: string | undefined);
8
+ protected doSend(messageKey: string, data: unknown): void;
9
+ protected _containerListener(event: MessageEvent<any>): void;
10
+ protected readonly eventType = "message";
11
+ protected getDataFromEvent(event: MessageEvent<any>): unknown;
12
+ }
13
+ //# sourceMappingURL=CfgWindowMessageManager.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { CfgIOManager } from "./CfgIOManager.js";
2
+ export class CfgWindowMessageManager extends CfgIOManager {
3
+ constructor(_remoteEnds, _targetOrigin = "*", _acceptableMessageOrigin) {
4
+ super();
5
+ this._remoteEnds = _remoteEnds;
6
+ this._targetOrigin = _targetOrigin;
7
+ this._acceptableMessageOrigin = _acceptableMessageOrigin;
8
+ this.eventType = "message";
9
+ }
10
+ doSend(messageKey, data) {
11
+ const container = CfgIOManager.makeContainer({
12
+ [messageKey]: data,
13
+ });
14
+ for (const remoteEnd of this._remoteEnds) {
15
+ remoteEnd.postMessage(container, this._targetOrigin);
16
+ }
17
+ }
18
+ _containerListener(event) {
19
+ if (this._acceptableMessageOrigin !== undefined &&
20
+ event.origin !== this._acceptableMessageOrigin) {
21
+ return;
22
+ }
23
+ super._containerListener(event);
24
+ }
25
+ getDataFromEvent(event) {
26
+ return event.data;
27
+ }
28
+ }
@@ -0,0 +1,13 @@
1
+ import { CfgIOProdConfConnector } from "./CfgIOProdConfConnector.js";
2
+ import { CfgWindowMessageManager, CfgWindowMessageManagerSendData } from "./CfgWindowMessageManager.js";
3
+ /**
4
+ * Instantiating the class will expose your product to:
5
+ * - Listen for configuration changes posted to this window
6
+ * - Send configuration changes using sendMessage
7
+ */
8
+ export declare class CfgWindowMessageToProdConfConnector extends CfgIOProdConfConnector<"message", CfgWindowMessageManagerSendData, CfgWindowMessageManager> {
9
+ constructor(manager: CfgWindowMessageManager, doValidate?: boolean);
10
+ protected getInitialProdConf(): string | undefined;
11
+ protected makeSendData(prodConfAsString: string, initial: boolean): CfgWindowMessageManagerSendData;
12
+ }
13
+ //# sourceMappingURL=CfgWindowMessageToProdConfConnector.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { CfgIOProdConfConnector } from "./CfgIOProdConfConnector.js";
2
+ /**
3
+ * Instantiating the class will expose your product to:
4
+ * - Listen for configuration changes posted to this window
5
+ * - Send configuration changes using sendMessage
6
+ */
7
+ export class CfgWindowMessageToProdConfConnector extends CfgIOProdConfConnector {
8
+ constructor(manager, doValidate = true) {
9
+ super(manager, doValidate);
10
+ }
11
+ getInitialProdConf() {
12
+ return undefined;
13
+ }
14
+ makeSendData(prodConfAsString, initial) {
15
+ return this.makeMessage(prodConfAsString, initial);
16
+ }
17
+ }
@@ -66,8 +66,20 @@ export declare class _CfgFeatureInternal {
66
66
  */
67
67
  private get isAllOptionsAffectedByAnySelection();
68
68
  get preview(): string | undefined;
69
+ /**
70
+ * Please note that this relates to the visibility in the Configuration tree.
71
+ * It does not affect the visibility of anything in the 3D view at all.
72
+ */
69
73
  get visibleIfAdditionalProduct(): boolean;
74
+ /**
75
+ * Please note that this relates to the visibility in the Configuration tree.
76
+ * It does not affect the visibility of anything in the 3D view at all.
77
+ */
70
78
  get visibleIfMainProduct(): boolean;
79
+ /**
80
+ * Please note that this relates to the visibility in the Configuration tree.
81
+ * It does not affect the visibility of anything in the 3D view at all.
82
+ */
71
83
  get visible(): boolean;
72
84
  get options(): CfgOption[];
73
85
  private _notifyAllOfChange;
@@ -148,6 +160,8 @@ export declare class CfgFeature {
148
160
  get preview(): string | undefined;
149
161
  get options(): CfgOption[];
150
162
  /**
163
+ * Please note that this relates to the visibility in the Configuration tree.
164
+ * It does not affect the visibility of anything in the 3D view at all.
151
165
  * Visibility is not inherited. If this is hidden the children
152
166
  * of this Feature might still be visible, depending on their settings.
153
167
  */
@@ -86,9 +86,9 @@ export class _CfgFeatureInternal {
86
86
  if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
87
87
  return;
88
88
  }
89
- const parent = this.parent;
90
89
  const freshRef = CfgFeature._makeNewRefFrom(this);
91
90
  this.changeObservable.notifyAll({ freshRef });
91
+ const parent = this.parent;
92
92
  if (parent !== undefined) {
93
93
  yield parent._childHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
94
94
  ? ProductConfigurationBubbleMode.Stop
@@ -450,12 +450,24 @@ export class _CfgFeatureInternal {
450
450
  get preview() {
451
451
  return getMtrlPreview(this._mtrlApplications);
452
452
  }
453
+ /**
454
+ * Please note that this relates to the visibility in the Configuration tree.
455
+ * It does not affect the visibility of anything in the 3D view at all.
456
+ */
453
457
  get visibleIfAdditionalProduct() {
454
458
  return this.rawFeature.hideIfAdditionalProduct !== true;
455
459
  }
460
+ /**
461
+ * Please note that this relates to the visibility in the Configuration tree.
462
+ * It does not affect the visibility of anything in the 3D view at all.
463
+ */
456
464
  get visibleIfMainProduct() {
457
465
  return this.rawFeature.hideIfMainProduct !== true;
458
466
  }
467
+ /**
468
+ * Please note that this relates to the visibility in the Configuration tree.
469
+ * It does not affect the visibility of anything in the 3D view at all.
470
+ */
459
471
  get visible() {
460
472
  return this.parentProduct.isAdditionalProduct
461
473
  ? this.visibleIfAdditionalProduct
@@ -588,6 +600,8 @@ export class CfgFeature {
588
600
  return this._internal.options;
589
601
  }
590
602
  /**
603
+ * Please note that this relates to the visibility in the Configuration tree.
604
+ * It does not affect the visibility of anything in the 3D view at all.
591
605
  * Visibility is not inherited. If this is hidden the children
592
606
  * of this Feature might still be visible, depending on their settings.
593
607
  */
@@ -233,7 +233,7 @@ export class _CfgOptionInternal {
233
233
  }
234
234
  else {
235
235
  if (change) {
236
- yield this.parent._childHasChanged(this, ProductConfigurationBubbleMode.OneLevel);
236
+ yield this.parent._childHasChanged(this, ProductConfigurationBubbleMode.Stop);
237
237
  }
238
238
  }
239
239
  return change;
@@ -5,6 +5,7 @@ import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
5
5
  import { ProductConfigurationBubbleMode } from "./CfgOption.js";
6
6
  export declare type ProductConfigurationChangeNotification = {
7
7
  freshRef: CfgProductConfiguration;
8
+ committed: boolean;
8
9
  };
9
10
  export declare type LengthValue = {
10
11
  length: number;
@@ -52,7 +53,7 @@ export declare class _CfgProductConfigurationInternal {
52
53
  /** Only selected features. */
53
54
  _getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
54
55
  populateFeatures: (rootFeatureRefs: FeatureRef[]) => void;
55
- setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit, doNotify?: boolean) => Promise<boolean>;
56
+ setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit) => Promise<boolean>;
56
57
  }
57
58
  export declare class CfgProductConfiguration {
58
59
  readonly _internal: _CfgProductConfigurationInternal;
@@ -27,7 +27,7 @@ export class _CfgProductConfigurationInternal {
27
27
  this._rootFeatureRefs = [];
28
28
  this._features = [];
29
29
  this.changeObservable = new Observable();
30
- this._notifyAllOfChange = (bubbleMode) => __awaiter(this, void 0, void 0, function* () {
30
+ this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
31
31
  if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
32
32
  return;
33
33
  }
@@ -35,13 +35,14 @@ export class _CfgProductConfigurationInternal {
35
35
  const parent = this.parentProduct;
36
36
  this.changeObservable.notifyAll({
37
37
  freshRef,
38
+ committed,
38
39
  });
39
40
  if (parent === undefined) {
40
41
  return;
41
42
  }
42
43
  yield parent._configurationHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
43
44
  ? ProductConfigurationBubbleMode.Stop
44
- : bubbleMode);
45
+ : bubbleMode, committed);
45
46
  });
46
47
  /** Called by child to tell its parent that it has changed. */
47
48
  this._childHasChanged = (freshRef, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
@@ -51,7 +52,7 @@ export class _CfgProductConfigurationInternal {
51
52
  throw Error("Child feature not found");
52
53
  }
53
54
  features[i] = freshRef;
54
- yield this._notifyAllOfChange(bubbleMode);
55
+ yield this._notifyAllOfChange(bubbleMode, true);
55
56
  });
56
57
  this.getApiSelection = () => this._features.map((f) => {
57
58
  return { code: "!~!", next: f._internal.getApiSelection() };
@@ -70,7 +71,7 @@ export class _CfgProductConfigurationInternal {
70
71
  if (change) {
71
72
  yield this._notifyAllOfChange(bubbleToRoot
72
73
  ? ProductConfigurationBubbleMode.ToRoot
73
- : ProductConfigurationBubbleMode.OneLevel);
74
+ : ProductConfigurationBubbleMode.OneLevel, true);
74
75
  }
75
76
  return change;
76
77
  });
@@ -102,7 +103,7 @@ export class _CfgProductConfigurationInternal {
102
103
  if (change) {
103
104
  yield this._notifyAllOfChange(validate
104
105
  ? ProductConfigurationBubbleMode.Validate
105
- : ProductConfigurationBubbleMode.OneLevel);
106
+ : ProductConfigurationBubbleMode.OneLevel, true);
106
107
  }
107
108
  return change;
108
109
  });
@@ -115,7 +116,7 @@ export class _CfgProductConfigurationInternal {
115
116
  this._rootFeatureRefs = rootFeatureRefs;
116
117
  this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.allRawFeatures, this, this, this.parentProduct, this.rootProduct);
117
118
  };
118
- this.setStretchReferenceLength = (measureParamCode, referenceLength, unit, doNotify = true) => __awaiter(this, void 0, void 0, function* () {
119
+ this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
119
120
  if (measureParamCode === "") {
120
121
  return false;
121
122
  }
@@ -146,9 +147,7 @@ export class _CfgProductConfigurationInternal {
146
147
  }
147
148
  stretchReferenceLength.current = referenceLengthWithUnit;
148
149
  }
149
- if (doNotify) {
150
- yield this._notifyAllOfChange(ProductConfigurationBubbleMode.ToRoot);
151
- }
150
+ yield this._notifyAllOfChange(ProductConfigurationBubbleMode.ToRoot, false);
152
151
  return true;
153
152
  });
154
153
  // Useful debug tool:
@@ -1,4 +1,4 @@
1
- import { GetProductParams, PostValidateParams, ValidateRequest } from "./CatalogueAPI";
1
+ import { GetProductParams, PostValidateParams, ValidateRequest } from "./CatalogueAPI.js";
2
2
  import { CfgProductResponse, CfgValidateResponse } from "./utilitiesCatalogueData.js";
3
3
  export declare type GetProduct = (params: GetProductParams) => Promise<CfgProductResponse>;
4
4
  export declare type PostValidate = (params: PostValidateParams, body: ValidateRequest) => Promise<CfgValidateResponse>;
@@ -8,7 +8,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { Observable } from "@configura/web-utilities";
11
- import { allExportFormats, allRenderFormats, isExportFormat, isRenderFormat, } from "./formats.js";
11
+ import { exportFormatNames, renderFormatNames, } from "../CatalogueAPI.js";
12
+ import { isExportFormat, isRenderFormat } from "./formats.js";
12
13
  const productToParams = (product) => (Object.assign(Object.assign({ lang: product.lang }, product.catId), { partNumber: product.partNumber }));
13
14
  export class _TaskHandlerInternal {
14
15
  constructor(api) {
@@ -55,10 +56,10 @@ export class _TaskHandlerInternal {
55
56
  get availableFormats() {
56
57
  const result = [];
57
58
  if (this.hasExport) {
58
- result.push(...allExportFormats);
59
+ result.push(...exportFormatNames);
59
60
  }
60
61
  if (this.hasRender) {
61
- result.push(...allRenderFormats);
62
+ result.push(...renderFormatNames);
62
63
  }
63
64
  return result;
64
65
  }
@@ -1,6 +1,4 @@
1
- import { ExportFormat, RenderFormat } from "../CatalogueAPI";
2
- export declare const allRenderFormats: RenderFormat[];
3
- export declare const allExportFormats: ExportFormat[];
1
+ import { ExportFormat, RenderFormat } from "../CatalogueAPI.js";
4
2
  export declare type RenderOrExportFormat = RenderFormat | ExportFormat;
5
3
  export declare function isRenderFormat(type: unknown): type is RenderFormat;
6
4
  export declare function isExportFormat(type: unknown): type is ExportFormat;
@@ -1,8 +1,7 @@
1
- export const allRenderFormats = ["jpg", "png"];
2
- export const allExportFormats = ["fbx", "dwg", "cmdrw", "cmfav", "cmsym"];
1
+ import { exportFormatNames, renderFormatNames, } from "../CatalogueAPI.js";
3
2
  export function isRenderFormat(type) {
4
- return allRenderFormats.some((f) => type === f);
3
+ return renderFormatNames.some((f) => type === f);
5
4
  }
6
5
  export function isExportFormat(type) {
7
- return allExportFormats.some((f) => type === f);
6
+ return exportFormatNames.some((f) => type === f);
8
7
  }
@@ -1,5 +1,5 @@
1
- import { CatalogueParams } from "../../CatalogueAPI";
2
- import { CfgProduct } from "../../CfgProduct";
1
+ import { CatalogueParams } from "../../CatalogueAPI.js";
2
+ import { CfgProduct } from "../../CfgProduct.js";
3
3
  export declare const dummyCatId: CatalogueParams;
4
4
  export declare const getDummyCfgProduct: () => Promise<CfgProduct>;
5
5
  //# sourceMappingURL=dummyProductForTest.d.ts.map
@@ -1,4 +1,4 @@
1
- import { CfgProduct } from "../../CfgProduct";
1
+ import { CfgProduct } from "../../CfgProduct.js";
2
2
  export const dummyCatId = {
3
3
  enterprise: "enterprise",
4
4
  prdCat: "prdCat",
@@ -1,6 +1,6 @@
1
- import { GetProductParams } from "../../CatalogueAPI";
2
- import { CfgProduct } from "../../CfgProduct";
3
- import { CfgProductResponse } from "../../utilitiesCatalogueData";
1
+ import { GetProductParams } from "../../CatalogueAPI.js";
2
+ import { CfgProduct } from "../../CfgProduct.js";
3
+ import { CfgProductResponse } from "../../utilitiesCatalogueData.js";
4
4
  export declare const getTestProduct: (params: GetProductParams) => Promise<CfgProductResponse>;
5
5
  export declare const cfgProductTest: (testFunc: (product: CfgProduct) => Promise<void>, prepFunc?: ((product: CfgProduct) => Promise<void>) | undefined) => Promise<{
6
6
  beforeSnapshot: {
@@ -7,9 +7,9 @@ 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 { CfgProduct } from "../../CfgProduct";
11
- import { Collector } from "./collectorForTest";
12
- import { dummyCatId } from "./dummyProductForTest";
10
+ import { CfgProduct } from "../../CfgProduct.js";
11
+ import { Collector } from "./collectorForTest.js";
12
+ import { dummyCatId } from "./dummyProductForTest.js";
13
13
  const A = () => ({
14
14
  uuid: "A",
15
15
  unit: "m",
@@ -1,6 +1,6 @@
1
- import { GetProductParams, SelectedOption } from "../../CatalogueAPI";
2
- import { CfgProduct } from "../../CfgProduct";
3
- import { CfgProductResponse } from "../../utilitiesCatalogueData";
1
+ import { GetProductParams, SelectedOption } from "../../CatalogueAPI.js";
2
+ import { CfgProduct } from "../../CfgProduct.js";
3
+ import { CfgProductResponse } from "../../utilitiesCatalogueData.js";
4
4
  export declare const getTestProduct: (params: GetProductParams) => Promise<CfgProductResponse>;
5
5
  export declare function getSelOptions(option: string): SelectedOption[];
6
6
  export declare const cfgProductPriceTest: (testFunc?: ((cfgProduct: CfgProduct) => Promise<void>) | undefined, featureOption?: string | undefined) => Promise<CfgProduct>;
@@ -7,8 +7,8 @@ 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 { CfgProduct } from "../../CfgProduct";
11
- import { dummyCatId } from "./dummyProductForTest";
10
+ import { CfgProduct } from "../../CfgProduct.js";
11
+ import { dummyCatId } from "./dummyProductForTest.js";
12
12
  const A = () => ({
13
13
  uuid: "A",
14
14
  unit: "m",
@@ -1,4 +1,4 @@
1
- import { CatalogueParams, GetProductParams, Model, PartsData, Prices, ProductData, ProductResponse, SelectedOption, ValidateResponse } from "./CatalogueAPI";
1
+ import { CatalogueParams, GetProductParams, Model, PartsData, Prices, ProductData, ProductResponse, SelectedOption, ValidateResponse } from "./CatalogueAPI.js";
2
2
  export declare const makeCatalogueKey: (cat: CatalogueParams) => string;
3
3
  export declare const makeProductKey: (cat: CatalogueParams, pKey: string) => string;
4
4
  export declare const makeSelOptionsKey: (options: SelectedOption[]) => string;
@@ -2,14 +2,15 @@ import { shallowCompareDictionaries } from "@configura/web-utilities";
2
2
  export const makeCatalogueKey = (cat) => `${cat.enterprise}-${cat.prdCat}-${cat.prdCatVersion}-${cat.priceList}-${cat.vendor}`;
3
3
  export const makeProductKey = (cat, pKey) => `${makeCatalogueKey(cat)}-${pKey}`;
4
4
  export const makeSelOptionsKey = (options) => options.reduce((p, option) => {
5
- const { code, next } = option;
6
- p += "_{" + code;
5
+ var _a;
6
+ const { code, numericValue, next } = option;
7
+ p += `_{${code}${numericValue === undefined ? "" : `_${numericValue.value}${(_a = numericValue.unit) !== null && _a !== void 0 ? _a : ""}`}`;
7
8
  if (next === undefined) {
8
9
  return p;
9
10
  }
10
11
  for (const key of Object.keys(next)) {
11
12
  const innerOption = next[key];
12
- p += "_{" + key + "_" + makeSelOptionsKey([innerOption]) + "_}";
13
+ p += `_{${key}_${makeSelOptionsKey([innerOption])}_}`;
13
14
  }
14
15
  p += "_}";
15
16
  return p;
@@ -1,4 +1,4 @@
1
- import { CodeRange } from "./CatalogueAPI";
1
+ import { CodeRange } from "./CatalogueAPI.js";
2
2
  export declare class NumericValuesSelection {
3
3
  constructor(rawRanges: CodeRange[]);
4
4
  readonly ranges: (NumericValueRangeDefinition | NumericValueDiscrete)[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configura/web-api",
3
- "version": "1.5.0-alpha.0",
3
+ "version": "1.6.0-iotest.0",
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": "^1.5.0-alpha.0"
26
+ "@configura/web-utilities": "1.6.0-iotest.0"
27
27
  },
28
- "gitHead": "6e24920b36ac225b17fcb519c0f4b7c6af924fbd"
28
+ "gitHead": "afcb290fa6c4a3f87ab1b4ac781bd704acaa0ad9"
29
29
  }