@configura/web-api 1.6.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 (40) hide show
  1. package/dist/CfgProduct.d.ts +12 -31
  2. package/dist/CfgProduct.js +41 -130
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +4 -2
  5. package/dist/io/CfgHistoryManager.d.ts +30 -0
  6. package/dist/io/CfgHistoryManager.js +62 -0
  7. package/dist/io/CfgHistoryToProdConfConnector.d.ts +10 -0
  8. package/dist/io/CfgHistoryToProdConfConnector.js +18 -0
  9. package/dist/io/CfgIOManager.d.ts +29 -0
  10. package/dist/io/CfgIOManager.js +89 -0
  11. package/dist/io/CfgIOProdConfConnector.d.ts +31 -0
  12. package/dist/io/CfgIOProdConfConnector.js +100 -0
  13. package/dist/io/CfgWindowMessageManager.d.ts +13 -0
  14. package/dist/io/CfgWindowMessageManager.js +28 -0
  15. package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +13 -0
  16. package/dist/io/CfgWindowMessageToProdConfConnector.js +17 -0
  17. package/dist/productConfiguration/CfgFeature.d.ts +2 -5
  18. package/dist/productConfiguration/CfgFeature.js +7 -44
  19. package/dist/productConfiguration/CfgOption.d.ts +1 -12
  20. package/dist/productConfiguration/CfgOption.js +3 -30
  21. package/dist/productConfiguration/CfgProductConfiguration.d.ts +4 -5
  22. package/dist/productConfiguration/CfgProductConfiguration.js +8 -26
  23. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +95 -24
  24. package/dist/tests/testData/testDataCachedGetProduct.js +19 -8
  25. package/dist/tests/testData/testDataProductAggregatedPrice.js +23 -12
  26. package/dist/tests/testData/testDataUpcharge.js +48 -16
  27. package/dist/utilitiesCatalogueData.js +4 -3
  28. package/package.json +3 -3
  29. package/dist/syncGroups/SyncGroupsApplier.d.ts +0 -20
  30. package/dist/syncGroups/SyncGroupsApplier.js +0 -518
  31. package/dist/syncGroups/SyncGroupsApplyMode.d.ts +0 -15
  32. package/dist/syncGroups/SyncGroupsApplyMode.js +0 -15
  33. package/dist/syncGroups/SyncGroupsHandler.d.ts +0 -30
  34. package/dist/syncGroups/SyncGroupsHandler.js +0 -71
  35. package/dist/syncGroups/SyncGroupsState.d.ts +0 -20
  36. package/dist/syncGroups/SyncGroupsState.js +0 -61
  37. package/dist/syncGroups/SyncGroupsTransaction.d.ts +0 -50
  38. package/dist/syncGroups/SyncGroupsTransaction.js +0 -106
  39. package/dist/tests/testData/testDataOptions.d.ts +0 -13
  40. package/dist/tests/testData/testDataOptions.js +0 -60
@@ -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
+ }
@@ -1,6 +1,6 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { Feature, SelectedOption, SyncGroup } from "../CatalogueAPI.js";
3
- import { CfgPath, CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
2
+ import { Feature, SelectedOption } from "../CatalogueAPI.js";
3
+ import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { CfgOption, ProductConfigurationBubbleMode, _CfgOptionInternal } from "./CfgOption.js";
6
6
  import { _CfgProductConfigurationInternal } from "./CfgProductConfiguration.js";
@@ -49,7 +49,6 @@ export declare class _CfgFeatureInternal {
49
49
  get isUseNumericValue(): boolean;
50
50
  get numericValue(): number | undefined;
51
51
  setNumericValue: (val: number) => Promise<boolean>;
52
- get syncGroup(): SyncGroup | undefined;
53
52
  get description(): string;
54
53
  /**
55
54
  * The MeasureParam class is re-used for different purposes. In Features it is used
@@ -96,8 +95,6 @@ export declare class _CfgFeatureInternal {
96
95
  setApiSelection: (apiOptionSelectionMap: {
97
96
  [index: string]: SelectedOption;
98
97
  } | undefined) => Promise<boolean>;
99
- get path(): CfgPath;
100
- getFromPath(path: CfgPath): _CfgFeatureInternal | _CfgOptionInternal;
101
98
  /** Pushes to refresh stretch. Does not cause validation. */
102
99
  pushStretch: () => Promise<boolean>;
103
100
  structureCompare: (other: _CfgFeatureInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
@@ -11,7 +11,6 @@ import { compareArrays, convertLength, count, Observable, someMatch, toLengthUni
11
11
  import { CfgProduct } from "../CfgProduct.js";
12
12
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
13
13
  import { CfgMtrlApplicationSource } from "../material/CfgMtrlApplicationSource.js";
14
- import { wrapWithCache } from "../productLoader.js";
15
14
  import { CfgOption, ProductConfigurationBubbleMode } from "./CfgOption.js";
16
15
  import { _CfgProductConfigurationInternal } from "./CfgProductConfiguration.js";
17
16
  import { getMtrlPreview } from "./utilitiesProductConfiguration.js";
@@ -87,9 +86,9 @@ export class _CfgFeatureInternal {
87
86
  if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
88
87
  return;
89
88
  }
90
- const parent = this.parent;
91
89
  const freshRef = CfgFeature._makeNewRefFrom(this);
92
90
  this.changeObservable.notifyAll({ freshRef });
91
+ const parent = this.parent;
93
92
  if (parent !== undefined) {
94
93
  yield parent._childHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
95
94
  ? ProductConfigurationBubbleMode.Stop
@@ -307,15 +306,6 @@ export class _CfgFeatureInternal {
307
306
  * Using a validate bubbleMode will cause validation calls to the server.
308
307
  */
309
308
  this.selectOption = (optionInternal, on, bubbleMode) => __awaiter(this, void 0, void 0, function* () {
310
- if (bubbleMode ===
311
- ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups) {
312
- const product = this.rootProduct;
313
- const syncGroupHandler = product.syncGroupHandler;
314
- if (syncGroupHandler === undefined) {
315
- throw new Error(`No sync group handler when bubble mode ${ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups}`);
316
- }
317
- return yield syncGroupHandler.selectOption(product, optionInternal.path, on, wrapWithCache(product._productLoaderRaw));
318
- }
319
309
  if (!on) {
320
310
  if (this.selectionType === SelectionType.Group) {
321
311
  throw new Error(`Multiple features are always selected and are not user selectable. Feature key: "${this.key}".`);
@@ -367,18 +357,11 @@ export class _CfgFeatureInternal {
367
357
  if (isAllOptionsAffectedByAnySelection) {
368
358
  this._freshRefAllOptions();
369
359
  }
370
- let nextLevelBubbleMode = bubbleMode;
371
- if (!on) {
372
- // If this was a deselect action we shall not bubble selected, that is, we shall not
373
- // select the ancestors if this action was deselect.
374
- if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected) {
375
- nextLevelBubbleMode = ProductConfigurationBubbleMode.Validate;
376
- }
377
- else if (bubbleMode === ProductConfigurationBubbleMode.BubbleSelected) {
378
- nextLevelBubbleMode = ProductConfigurationBubbleMode.ToRoot;
379
- }
380
- }
381
- yield this._notifyAllOfChange(nextLevelBubbleMode);
360
+ // If this was a deselect action we shall not bubble selected, that is, we shall not
361
+ // select the ancestors if this action was deselect.
362
+ yield this._notifyAllOfChange(!on && bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected
363
+ ? ProductConfigurationBubbleMode.Validate
364
+ : bubbleMode);
382
365
  return isActualChange;
383
366
  });
384
367
  this.isSelected = (option) => this.selectionType === SelectionType.Group ||
@@ -429,9 +412,6 @@ export class _CfgFeatureInternal {
429
412
  }
430
413
  return value;
431
414
  }
432
- get syncGroup() {
433
- return this.rawFeature.syncGroup;
434
- }
435
415
  get description() {
436
416
  return this.rawFeature.description;
437
417
  }
@@ -502,23 +482,6 @@ export class _CfgFeatureInternal {
502
482
  }
503
483
  return this._options;
504
484
  }
505
- get path() {
506
- return [...this.parent.path, this.code];
507
- }
508
- getFromPath(path) {
509
- path = path.slice();
510
- const s = path.shift();
511
- switch (s) {
512
- case undefined:
513
- return this;
514
- default:
515
- const option = this.options.find((o) => o.code === s);
516
- if (option === undefined) {
517
- throw new Error(`Option not found ${s}, ${path.join(", ")}`);
518
- }
519
- return option._internal.getFromPath(path);
520
- }
521
- }
522
485
  /**
523
486
  * Make fresh references to all options on this feature.
524
487
  * Also includes currently selected options.
@@ -568,7 +531,7 @@ export class CfgFeature {
568
531
  * Calling this will cause a validation call to the server.
569
532
  */
570
533
  this.selectOption = (option, on) => __awaiter(this, void 0, void 0, function* () {
571
- return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
534
+ return yield this._internal.selectOption(option._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelected);
572
535
  });
573
536
  this.isSelected = (option) => this._internal.isSelected(option._internal);
574
537
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
@@ -1,6 +1,6 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
2
  import { Feature, Option, SelectedOption } from "../CatalogueAPI.js";
3
- import { CfgPath, CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
3
+ import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgMtrlApplication } from "../material/CfgMtrlApplication.js";
5
5
  import { NumericValuesSelection } from "../utilitiesNumericValues.js";
6
6
  import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
@@ -9,10 +9,6 @@ export declare type OptionChangeNotification = {
9
9
  freshRef: CfgOption;
10
10
  };
11
11
  export declare enum ProductConfigurationBubbleMode {
12
- /**
13
- * If this is select it will turns on all ancestors all the way up.
14
- */
15
- BubbleSelected = "BubbleSelected",
16
12
  /**
17
13
  * Bubble to the closest CfgProduct, let it revalidate, then that will continue
18
14
  * the bubble after validate.
@@ -24,11 +20,6 @@ export declare enum ProductConfigurationBubbleMode {
24
20
  * So with this mode it is possible to select an option where its parents are not selected.
25
21
  */
26
22
  ValidateAndBubbleSelected = "ValidateAndBubbleSelected",
27
- /**
28
- * Like ValidateAndBubbleSelected, but SyncGroups are applied after
29
- * ValidateAndBubbleSelected has been done
30
- */
31
- ValidateAndBubbleSelectedAndApplySyncGroups = "ValidateAndBubbleSelectedAndApplySyncGroups",
32
23
  /**
33
24
  * Stop bubbling
34
25
  * This mode supports internal functionality and is not expected to be used by integrators.
@@ -90,8 +81,6 @@ export declare class _CfgOptionInternal {
90
81
  _childHasChanged: (freshRef: CfgFeature, bubbleMode: ProductConfigurationBubbleMode) => Promise<void>;
91
82
  getApiSelection: () => SelectedOption;
92
83
  setApiSelection: (apiOptionSelection: SelectedOption | undefined) => Promise<boolean>;
93
- get path(): CfgPath;
94
- getFromPath(path: CfgPath): _CfgFeatureInternal | _CfgOptionInternal;
95
84
  structureCompare: (other: _CfgOptionInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
96
85
  tryMatchSelection: (other: CfgOption, descriptionMatch?: boolean) => Promise<boolean>;
97
86
  keyMatch: (other: _CfgOptionInternal, descriptionMatch?: boolean) => boolean;
@@ -17,10 +17,6 @@ import { CfgFeature, SelectionType } from "./CfgFeature.js";
17
17
  import { getMtrlPreview, syncCfgFeatures } from "./utilitiesProductConfiguration.js";
18
18
  export var ProductConfigurationBubbleMode;
19
19
  (function (ProductConfigurationBubbleMode) {
20
- /**
21
- * If this is select it will turns on all ancestors all the way up.
22
- */
23
- ProductConfigurationBubbleMode["BubbleSelected"] = "BubbleSelected";
24
20
  /**
25
21
  * Bubble to the closest CfgProduct, let it revalidate, then that will continue
26
22
  * the bubble after validate.
@@ -32,11 +28,6 @@ export var ProductConfigurationBubbleMode;
32
28
  * So with this mode it is possible to select an option where its parents are not selected.
33
29
  */
34
30
  ProductConfigurationBubbleMode["ValidateAndBubbleSelected"] = "ValidateAndBubbleSelected";
35
- /**
36
- * Like ValidateAndBubbleSelected, but SyncGroups are applied after
37
- * ValidateAndBubbleSelected has been done
38
- */
39
- ProductConfigurationBubbleMode["ValidateAndBubbleSelectedAndApplySyncGroups"] = "ValidateAndBubbleSelectedAndApplySyncGroups";
40
31
  /**
41
32
  * Stop bubbling
42
33
  * This mode supports internal functionality and is not expected to be used by integrators.
@@ -102,8 +93,7 @@ export class _CfgOptionInternal {
102
93
  features[i] = freshRef;
103
94
  // In CfgOption we let stop bubble slip through. This is because CfgOption is sort of
104
95
  // a semi level. Like Feature + Option together constitutes one level.
105
- if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected ||
106
- bubbleMode === ProductConfigurationBubbleMode.BubbleSelected) {
96
+ if (bubbleMode === ProductConfigurationBubbleMode.ValidateAndBubbleSelected) {
107
97
  // selectOption takes care of the bubble
108
98
  yield this.parent.selectOption(this, true, bubbleMode);
109
99
  }
@@ -243,7 +233,7 @@ export class _CfgOptionInternal {
243
233
  }
244
234
  else {
245
235
  if (change) {
246
- yield this.parent._childHasChanged(this, ProductConfigurationBubbleMode.OneLevel);
236
+ yield this.parent._childHasChanged(this, ProductConfigurationBubbleMode.Stop);
247
237
  }
248
238
  }
249
239
  return change;
@@ -310,23 +300,6 @@ export class _CfgOptionInternal {
310
300
  }
311
301
  return this._features;
312
302
  }
313
- get path() {
314
- return [...this.parent.path, this.code];
315
- }
316
- getFromPath(path) {
317
- path = path.slice();
318
- const s = path.shift();
319
- switch (s) {
320
- case undefined:
321
- return this;
322
- default:
323
- const feature = this.features.find((o) => o.code === s);
324
- if (feature === undefined) {
325
- throw new Error(`Feature not found ${s}, ${path.join(", ")}`);
326
- }
327
- return feature._internal.getFromPath(path);
328
- }
329
- }
330
303
  _freshRefDescendants() {
331
304
  const features = this._features || [];
332
305
  for (let i = 0; i < features.length; i++) {
@@ -353,7 +326,7 @@ export class CfgOption {
353
326
  * Calling this will cause a validation call to the server.
354
327
  */
355
328
  this.setSelected = (on) => __awaiter(this, void 0, void 0, function* () {
356
- return yield this._internal.parent.selectOption(this._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelectedAndApplySyncGroups);
329
+ return yield this._internal.parent.selectOption(this._internal, on, ProductConfigurationBubbleMode.ValidateAndBubbleSelected);
357
330
  });
358
331
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
359
332
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
@@ -1,10 +1,11 @@
1
1
  import { LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
2
  import { Feature, FeatureRef, SelectedOption } from "../CatalogueAPI.js";
3
- import { CfgPath, CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
3
+ import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
4
4
  import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
5
- import { ProductConfigurationBubbleMode, _CfgOptionInternal } from "./CfgOption.js";
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;
@@ -43,8 +44,6 @@ export declare class _CfgProductConfigurationInternal {
43
44
  * outside we want notifications to bubble all the way to the root.
44
45
  */
45
46
  setApiSelection: (selectedOptions: SelectedOption[], bubbleToRoot: boolean) => Promise<boolean>;
46
- get path(): CfgPath;
47
- getFromPath(path: CfgPath): _CfgProductConfigurationInternal | _CfgFeatureInternal | _CfgOptionInternal;
48
47
  structureCompare: (other: _CfgProductConfigurationInternal, strictOrder?: boolean, descriptionMatch?: boolean) => boolean;
49
48
  /**
50
49
  * When used internally the notifications are taken care off by the caller, but if set from
@@ -54,7 +53,7 @@ export declare class _CfgProductConfigurationInternal {
54
53
  /** Only selected features. */
55
54
  _getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
56
55
  populateFeatures: (rootFeatureRefs: FeatureRef[]) => void;
57
- setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit, doNotify?: boolean) => Promise<boolean>;
56
+ setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit) => Promise<boolean>;
58
57
  }
59
58
  export declare class CfgProductConfiguration {
60
59
  readonly _internal: _CfgProductConfigurationInternal;