@configura/web-api 1.6.0-alpha.0 → 1.6.0-iotest.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CfgProduct.d.ts +12 -31
- package/dist/CfgProduct.js +41 -130
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/io/CfgHistoryManager.d.ts +30 -0
- package/dist/io/CfgHistoryManager.js +62 -0
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +10 -0
- package/dist/io/CfgHistoryToProdConfConnector.js +20 -0
- package/dist/io/CfgIOManager.d.ts +29 -0
- package/dist/io/CfgIOManager.js +89 -0
- package/dist/io/CfgIOProdConfConnector.d.ts +33 -0
- package/dist/io/CfgIOProdConfConnector.js +100 -0
- package/dist/io/CfgWindowMessageManager.d.ts +13 -0
- package/dist/io/CfgWindowMessageManager.js +28 -0
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +13 -0
- package/dist/io/CfgWindowMessageToProdConfConnector.js +17 -0
- package/dist/productConfiguration/CfgFeature.d.ts +2 -5
- package/dist/productConfiguration/CfgFeature.js +7 -44
- package/dist/productConfiguration/CfgOption.d.ts +1 -12
- package/dist/productConfiguration/CfgOption.js +3 -30
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +4 -5
- package/dist/productConfiguration/CfgProductConfiguration.js +8 -26
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +95 -24
- package/dist/tests/testData/testDataCachedGetProduct.js +19 -8
- package/dist/tests/testData/testDataProductAggregatedPrice.js +23 -12
- package/dist/tests/testData/testDataUpcharge.js +48 -16
- package/dist/utilitiesCatalogueData.js +4 -3
- package/package.json +3 -3
- package/dist/syncGroups/SyncGroupsApplier.d.ts +0 -20
- package/dist/syncGroups/SyncGroupsApplier.js +0 -518
- package/dist/syncGroups/SyncGroupsApplyMode.d.ts +0 -15
- package/dist/syncGroups/SyncGroupsApplyMode.js +0 -15
- package/dist/syncGroups/SyncGroupsHandler.d.ts +0 -30
- package/dist/syncGroups/SyncGroupsHandler.js +0 -71
- package/dist/syncGroups/SyncGroupsState.d.ts +0 -20
- package/dist/syncGroups/SyncGroupsState.js +0 -61
- package/dist/syncGroups/SyncGroupsTransaction.d.ts +0 -50
- package/dist/syncGroups/SyncGroupsTransaction.js +0 -106
- package/dist/tests/testData/testDataOptions.d.ts +0 -13
- package/dist/tests/testData/testDataOptions.js +0 -60
|
@@ -0,0 +1,20 @@
|
|
|
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: initial
|
|
16
|
+
? undefined
|
|
17
|
+
: new Map([[STAGE_PROD_CONF_MESSAGE_KEY, prodConfAsString]]),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -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,33 @@
|
|
|
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
|
+
declare type ProdConfMessageCallback = (message: CfgProdConfMessage) => Promise<void>;
|
|
11
|
+
declare type ProdConfStringCallback = (prodConfAsString: string) => Promise<void>;
|
|
12
|
+
export declare abstract class CfgIOProdConfConnector<K extends keyof WindowEventMap, S, M extends CfgIOManager<K, S>> {
|
|
13
|
+
protected readonly _ioManager: M;
|
|
14
|
+
protected readonly _doValidate: boolean;
|
|
15
|
+
protected _product: CfgProduct | undefined;
|
|
16
|
+
private _stopListenToMessage;
|
|
17
|
+
private _stopListenToProdConf;
|
|
18
|
+
constructor(_ioManager: M, _doValidate: boolean);
|
|
19
|
+
setProduct: (product: CfgProduct | undefined) => Promise<void>;
|
|
20
|
+
protected abstract getInitialProdConf(): string | undefined;
|
|
21
|
+
protected abstract makeSendData(prodConfAsString: string, initial: boolean): S;
|
|
22
|
+
makeMessage(prodConfAsString: string, initial: boolean): CfgProdConfMessage;
|
|
23
|
+
makeMessageListener(callback: ProdConfMessageCallback): (message: unknown) => Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Register the callback to listen for Product Configuration messages
|
|
26
|
+
* @returns A function which when called will cancel listening
|
|
27
|
+
*/
|
|
28
|
+
listenForMessage(callback: ProdConfMessageCallback): () => void;
|
|
29
|
+
makeProdConfListener(callback: ProdConfStringCallback): (n: CfgProductChangeNotification) => void;
|
|
30
|
+
listenForProdConf(product: CfgProduct, callback: ProdConfStringCallback): () => void;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# 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
|
+
this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, this.makeSendData(newProduct.getApiSelectionAsString(), true));
|
|
43
|
+
this._stopListenToMessage = this.listenForMessage((message) => __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
const prodConfAsString = message.prodConfAsString;
|
|
45
|
+
if (prodConfAsString === newProduct.getApiSelectionAsString()) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
yield newProduct.setFromApiSelectionString(prodConfAsString, this._doValidate);
|
|
49
|
+
}));
|
|
50
|
+
this._stopListenToProdConf = this.listenForProdConf(newProduct, (prodConfAsString) => __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, this.makeSendData(prodConfAsString, false));
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
makeMessage(prodConfAsString, initial) {
|
|
56
|
+
return {
|
|
57
|
+
version: STAGE_PROD_CONF_MESSAGE_VERSION,
|
|
58
|
+
initial,
|
|
59
|
+
prodConfAsString,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
makeMessageListener(callback) {
|
|
63
|
+
return (message) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
const prodConfMessage = message;
|
|
65
|
+
const version = prodConfMessage.version;
|
|
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(prodConfMessage);
|
|
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
|
|
3
|
-
import {
|
|
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
|
-
|
|
371
|
-
if
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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.
|
|
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 {
|
|
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.
|
|
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.
|
|
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 {
|
|
3
|
+
import { CfgProduct, _CfgProductInternal } from "../CfgProduct.js";
|
|
4
4
|
import { CfgFeature, _CfgFeatureInternal } from "./CfgFeature.js";
|
|
5
|
-
import { ProductConfigurationBubbleMode
|
|
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
|
|
56
|
+
setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit) => Promise<boolean>;
|
|
58
57
|
}
|
|
59
58
|
export declare class CfgProductConfiguration {
|
|
60
59
|
readonly _internal: _CfgProductConfigurationInternal;
|