@configura/web-api 2.0.0-alpha.16 → 2.0.0-alpha.17

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.
@@ -101,6 +101,7 @@ export declare class _CfgProductInternal {
101
101
  * change.
102
102
  */
103
103
  _updateAdditionalProdRef(p: DtoAdditionalProductRef): void;
104
+ get hasRootFeaturesChanged(): boolean;
104
105
  get description(): string | undefined;
105
106
  get rootNodeSources(): RootNodeSource[] | undefined;
106
107
  get mtrlApplications(): DtoMtrlApplication[] | undefined;
@@ -224,6 +225,18 @@ export declare class CfgProduct {
224
225
  * assumed to always be legal.
225
226
  */
226
227
  setSelected: (v: boolean) => Promise<boolean>;
228
+ /**
229
+ * Functional selection is a Catalogues feature where selecting Options on Features result in that you
230
+ * "jump" to another Product as a result of the Validate call. You normally do not notice that a functional
231
+ * selection has occurred except for the styleNr changing. Functional selection can change which Features
232
+ * from the original product call are used as root Features. This can in turn affect if serialized
233
+ * configuration can be applied or not.
234
+ *
235
+ * The SDK can currently only apply serialized configuration if the list of root Features has not changed.
236
+ * For this reason, when functional selection has happened, extracting data for external systems might work
237
+ * well, but reapplying back into Stage will probably fail.
238
+ */
239
+ get hasRootFeaturesChanged(): boolean;
227
240
  get rawProductData(): CfgProductData;
228
241
  get uuid(): string;
229
242
  get unit(): LengthUnit;
@@ -456,6 +456,10 @@ export class _CfgProductInternal {
456
456
  this._selected = p.optional ? false : undefined;
457
457
  }
458
458
  }
459
+ get hasRootFeaturesChanged() {
460
+ return (this._configuration._internal.hasRootFeaturesChanged ||
461
+ this.additionalProducts.some((p) => p._internal.hasRootFeaturesChanged));
462
+ }
459
463
  get description() {
460
464
  var _a, _b;
461
465
  return (_b = (_a = this._additionalProductRef) === null || _a === void 0 ? void 0 : _a.refDescription) !== null && _b !== void 0 ? _b : this._rawProductData.description;
@@ -772,6 +776,21 @@ export class CfgProduct {
772
776
  get visible() {
773
777
  return this._internal.visible;
774
778
  }
779
+ // A similar text to the one below exists in global-message-managers.md and should be kept in sync.
780
+ /**
781
+ * Functional selection is a Catalogues feature where selecting Options on Features result in that you
782
+ * "jump" to another Product as a result of the Validate call. You normally do not notice that a functional
783
+ * selection has occurred except for the styleNr changing. Functional selection can change which Features
784
+ * from the original product call are used as root Features. This can in turn affect if serialized
785
+ * configuration can be applied or not.
786
+ *
787
+ * The SDK can currently only apply serialized configuration if the list of root Features has not changed.
788
+ * For this reason, when functional selection has happened, extracting data for external systems might work
789
+ * well, but reapplying back into Stage will probably fail.
790
+ */
791
+ get hasRootFeaturesChanged() {
792
+ return this._internal.hasRootFeaturesChanged;
793
+ }
775
794
  get rawProductData() {
776
795
  return this._internal.rawProductData;
777
796
  }
@@ -59,6 +59,12 @@ export class CfgHistoryManager extends CfgWindowEventManager {
59
59
  */
60
60
  send(messageKey, data) {
61
61
  const { qsKeyValues, message, mode } = data;
62
+ const warnings = this.getWarnings();
63
+ if (warnings.length !== 0) {
64
+ console.warn("History updating blocked by warnings");
65
+ warnings.forEach((w) => console.warn(w));
66
+ return;
67
+ }
62
68
  for (const keyValue of qsKeyValues) {
63
69
  this._aggregatedQsKeyValues.set(keyValue[0], keyValue[1]);
64
70
  }
@@ -1,3 +1,4 @@
1
+ import { CfgIOWarningSupplier } from "./CfgIOWarningSupplier";
1
2
  declare type ConfiguraAttribute = "C0nf1gura";
2
3
  declare type ConfiguraShebang = "arug1fn0C";
3
4
  declare const CONFIGURA_ATTRIBUTE: ConfiguraAttribute;
@@ -17,6 +18,10 @@ export declare type CfgIOContainer = {
17
18
  * Base class for classes handling input and output in globally shared environments.
18
19
  */
19
20
  export declare abstract class CfgIOManager<S> {
21
+ private _warningSuppliers;
22
+ addWarningSupplier(supplier: CfgIOWarningSupplier): void;
23
+ removeWarningSupplier(supplier: CfgIOWarningSupplier): void;
24
+ getWarnings(): string[];
20
25
  /**
21
26
  * Listen for the message messageKey being received.
22
27
  */
@@ -18,12 +18,31 @@ const hasConfiguraAttribute = (data) => {
18
18
  */
19
19
  export class CfgIOManager {
20
20
  constructor() {
21
+ this._warningSuppliers = [];
21
22
  // A lock to avoid circular write. Asynchronous conditions can make this not be enough.
22
23
  // Avoid creating pre-conditions where this can happen.
23
24
  this._receiveInProgress = false;
24
25
  this._messageListeners = [];
25
26
  this._getIndexOfMessageListener = (l) => this._messageListeners.findIndex((item) => l === item.l);
26
27
  }
28
+ addWarningSupplier(supplier) {
29
+ this._warningSuppliers.push(supplier);
30
+ }
31
+ removeWarningSupplier(supplier) {
32
+ const i = this._warningSuppliers.indexOf(supplier);
33
+ if (i === -1) {
34
+ return;
35
+ }
36
+ this._warningSuppliers.splice(i, 1);
37
+ }
38
+ getWarnings() {
39
+ return this._warningSuppliers.reduce((aggregated, supplier) => {
40
+ for (const warning of supplier.getWarnings()) {
41
+ aggregated.push(warning);
42
+ }
43
+ return aggregated;
44
+ }, []);
45
+ }
27
46
  /**
28
47
  * Listen for the message messageKey being received.
29
48
  */
@@ -1,6 +1,7 @@
1
1
  import { DtoAdditionalProductConfiguration, DtoProductConf } from "../CatalogueAPI.js";
2
2
  import { CfgProduct, CfgProductChangeNotification } from "../CfgProduct.js";
3
3
  import { CfgIOManager } from "./CfgIOManager.js";
4
+ import { CfgIOWarningSupplier } from "./CfgIOWarningSupplier.js";
4
5
  export declare const isCfgProdConfMessage: (data: unknown) => data is CfgProdConfMessageV1 | CfgProdConfMessageV2;
5
6
  export declare type CfgProdConfMessageV1 = {
6
7
  version: "1.0";
@@ -27,16 +28,17 @@ declare type ProdConfCallback = (conf: DtoProductConf) => Promise<void>;
27
28
  /**
28
29
  * Base class for connecting the product configuration to an IO channel
29
30
  */
30
- export declare abstract class CfgIOProdConfConnector<S> {
31
- private readonly _ioManager;
31
+ export declare abstract class CfgIOProdConfConnector<S> implements CfgIOWarningSupplier {
32
+ protected readonly _ioManager: CfgIOManager<S>;
32
33
  private readonly _includeExtendedDataInSend;
33
34
  private readonly _includeProdParamsInSend;
34
- private _product;
35
+ protected _product: CfgProduct | undefined;
35
36
  private _stopListenToMessage;
36
37
  private _stopListenToProdConf;
37
- constructor(_ioManager: CfgIOManager<S>, _includeExtendedDataInSend: boolean, // Only v2.0
38
+ constructor(_ioManager: CfgIOManager<S>, _includeExtendedDataInSend: boolean, // Only for v2.0
38
39
  _includeProdParamsInSend: boolean);
39
- destroy: () => void;
40
+ destroy(): void;
41
+ getWarnings(): string[];
40
42
  setProduct: (product: CfgProduct | undefined) => Promise<void>;
41
43
  private _send;
42
44
  protected getInitialProdConf(): DtoProductConf | undefined;
@@ -24,19 +24,14 @@ export const STAGE_PROD_CONF_MESSAGE_KEY = "stageprodconf";
24
24
  * Base class for connecting the product configuration to an IO channel
25
25
  */
26
26
  export class CfgIOProdConfConnector {
27
- constructor(_ioManager, _includeExtendedDataInSend, // Only v2.0
28
- _includeProdParamsInSend // Only v2.0
27
+ constructor(_ioManager, _includeExtendedDataInSend, // Only for v2.0
28
+ _includeProdParamsInSend // Only for v2.0
29
29
  ) {
30
30
  this._ioManager = _ioManager;
31
31
  this._includeExtendedDataInSend = _includeExtendedDataInSend;
32
32
  this._includeProdParamsInSend = _includeProdParamsInSend;
33
33
  this._stopListenToMessage = undefined;
34
34
  this._stopListenToProdConf = undefined;
35
- this.destroy = () => {
36
- var _a, _b;
37
- (_a = this._stopListenToMessage) === null || _a === void 0 ? void 0 : _a.call(this);
38
- (_b = this._stopListenToProdConf) === null || _b === void 0 ? void 0 : _b.call(this);
39
- };
40
35
  this.setProduct = (product) => __awaiter(this, void 0, void 0, function* () {
41
36
  var _a, _b;
42
37
  const currentProduct = this._product;
@@ -88,6 +83,22 @@ export class CfgIOProdConfConnector {
88
83
  this._stopListenToProdConf = CfgIOProdConfConnector.listenForProdConf(newProduct, (conf) => __awaiter(this, void 0, void 0, function* () { return this._send(this.makeSendData(conf, false)); }), this._includeExtendedDataInSend, this._includeProdParamsInSend);
89
84
  });
90
85
  this._send = (data) => this._ioManager.send(STAGE_PROD_CONF_MESSAGE_KEY, data);
86
+ _ioManager.addWarningSupplier(this);
87
+ }
88
+ destroy() {
89
+ var _a, _b;
90
+ (_a = this._stopListenToMessage) === null || _a === void 0 ? void 0 : _a.call(this);
91
+ (_b = this._stopListenToProdConf) === null || _b === void 0 ? void 0 : _b.call(this);
92
+ this._ioManager.removeWarningSupplier(this);
93
+ }
94
+ getWarnings() {
95
+ const product = this._product;
96
+ if (product !== undefined && product.hasRootFeaturesChanged) {
97
+ return [
98
+ "In at least one of the Products, Functional Selection has taken place, thereby changing what root Features are used. The SDK can not yet apply a serialized configuration in these cases. Extracting this data from the SDK for external applications can work, but reinserting the data into Stage will most likely fail.",
99
+ ];
100
+ }
101
+ return [];
91
102
  }
92
103
  getInitialProdConf() {
93
104
  return undefined;
@@ -0,0 +1,4 @@
1
+ export interface CfgIOWarningSupplier {
2
+ getWarnings(): string[];
3
+ }
4
+ //# sourceMappingURL=CfgIOWarningSupplier.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -70,6 +70,10 @@ export class CfgWindowMessageManager extends CfgWindowEventManager {
70
70
  const container = CfgIOManager.makeContainer({
71
71
  [messageKey]: data,
72
72
  });
73
+ const warnings = this.getWarnings();
74
+ if (warnings.length !== 0) {
75
+ warnings.forEach((w) => console.warn(w));
76
+ }
73
77
  for (const remoteEnd of this._remoteEnds) {
74
78
  remoteEnd.postMessage(container, this._targetOrigin);
75
79
  }
@@ -20,6 +20,7 @@ export declare class _CfgProductConfigurationInternal {
20
20
  readonly allRawFeatures: DtoFeature[];
21
21
  readonly parentProduct: _CfgProductInternal;
22
22
  readonly rootProduct: _CfgProductInternal;
23
+ private readonly _initialRootFeatureRefs;
23
24
  static _makeUninitialized(rootFeatureRefs: DtoFeatureRef[], allRawFeatures: DtoFeature[], // Flat packed. All the features that can appear anyplace in the selection tree.
24
25
  parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): _CfgProductConfigurationInternal;
25
26
  private constructor();
@@ -50,6 +51,12 @@ export declare class _CfgProductConfigurationInternal {
50
51
  tryMatchSelection: (other: _CfgProductConfigurationInternal, descriptionMatch: boolean | undefined, validate: boolean) => Promise<boolean>;
51
52
  /** Only selected features. */
52
53
  _getFeaturesWithCode: (code: string) => _CfgFeatureInternal[];
54
+ private _hasRootFeaturesChanged;
55
+ /**
56
+ * True if what root Features are used is not the same as at initial load.
57
+ * This means that functional selection has happened.
58
+ */
59
+ get hasRootFeaturesChanged(): boolean;
53
60
  populateFeatures: (rootFeatureRefs: DtoFeatureRef[]) => void;
54
61
  setStretchReferenceLength: (measureParamCode: string, referenceLength: number | undefined, unit: LengthUnit) => Promise<boolean>;
55
62
  }
@@ -20,10 +20,11 @@ import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
20
20
  */
21
21
  export class _CfgProductConfigurationInternal {
22
22
  constructor(allRawFeatures, // Flat packed. All the features that can appear anyplace in the selection tree.
23
- parentProduct, rootProduct) {
23
+ parentProduct, rootProduct, _initialRootFeatureRefs) {
24
24
  this.allRawFeatures = allRawFeatures;
25
25
  this.parentProduct = parentProduct;
26
26
  this.rootProduct = rootProduct;
27
+ this._initialRootFeatureRefs = _initialRootFeatureRefs;
27
28
  this.key = "~";
28
29
  this._rootFeatureRefs = [];
29
30
  this._features = [];
@@ -113,8 +114,10 @@ export class _CfgProductConfigurationInternal {
113
114
  agg.push(...feature._internal._getFeaturesWithCode(code));
114
115
  return agg;
115
116
  }, []);
117
+ this._hasRootFeaturesChanged = false;
116
118
  this.populateFeatures = (rootFeatureRefs) => {
117
119
  this._rootFeatureRefs = rootFeatureRefs;
120
+ this._hasRootFeaturesChanged = !compareArrays(this._initialRootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code);
118
121
  this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.allRawFeatures, this, this, this.parentProduct, this.rootProduct);
119
122
  };
120
123
  this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
@@ -198,7 +201,7 @@ export class _CfgProductConfigurationInternal {
198
201
  }
199
202
  static _makeUninitialized(rootFeatureRefs, allRawFeatures, // Flat packed. All the features that can appear anyplace in the selection tree.
200
203
  parentProduct, rootProduct) {
201
- const configuration = new this(allRawFeatures, parentProduct, rootProduct);
204
+ const configuration = new this(allRawFeatures, parentProduct, rootProduct, rootFeatureRefs);
202
205
  configuration.populateFeatures(rootFeatureRefs);
203
206
  return configuration;
204
207
  }
@@ -217,6 +220,13 @@ export class _CfgProductConfigurationInternal {
217
220
  features[i] = CfgFeature._makeNewRefFrom(featureInternal);
218
221
  }
219
222
  }
223
+ /**
224
+ * True if what root Features are used is not the same as at initial load.
225
+ * This means that functional selection has happened.
226
+ */
227
+ get hasRootFeaturesChanged() {
228
+ return this._hasRootFeaturesChanged;
229
+ }
220
230
  }
221
231
  export class CfgProductConfiguration {
222
232
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configura/web-api",
3
- "version": "2.0.0-alpha.16",
3
+ "version": "2.0.0-alpha.17",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@configura/web-utilities": "2.0.0-alpha.16"
26
+ "@configura/web-utilities": "2.0.0-alpha.17"
27
27
  },
28
- "gitHead": "8c03272c5c4eb3445ad9a06dda0abe1d1fefab49"
28
+ "gitHead": "7894d44db1eb25eab4affba49513cc56ac83fd75"
29
29
  }