config-editor-base 3.1.3 → 3.2.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.
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
3
3
  import classNames from 'classnames';
4
4
  import validator from '@rjsf/validator-ajv6';
5
5
  import Form from '@rjsf/core';
6
- import saveAs from 'file-saver';
6
+ import saveAs, { saveAs as saveAs$1 } from 'file-saver';
7
7
  import Select from 'react-select';
8
8
  import Files from 'react-files';
9
9
  import applyNav, { GENERIC_NAV } from 'rjsf-tabs';
@@ -147,7 +147,7 @@ var loadFile = function loadFile(fileName) {
147
147
  var _require = require('detect-browser'),
148
148
  detect = _require.detect;
149
149
  var browser = detect();
150
- var crcBrowserSupport = ['chrome', 'firefox', 'opera', 'safari', 'edge'].includes(browser.name);
150
+ var crcBrowserSupport = ['chrome', 'firefox', 'opera', 'safari', 'edge'].includes(browser && browser.name);
151
151
 
152
152
  var SET_SCHEMA_LIST = "editor/SET_SCHEMA_LIST";
153
153
  var SET_CONFIG_LIST = "editor/SET_CONFIG_LIST";
@@ -1059,6 +1059,19 @@ var checkConfigAwsEndpoint = function checkConfigAwsEndpoint(content) {
1059
1059
  }
1060
1060
  };
1061
1061
  };
1062
+ var checkS3OtaDisabled = function checkS3OtaDisabled(content) {
1063
+ return function (dispatch) {
1064
+ if (content.connect != undefined && content.connect.s3 != undefined && content.connect.s3.sync != undefined) {
1065
+ if (content.connect.s3.sync.ota != undefined && content.connect.s3.sync.ota == 0) {
1066
+ dispatch(set({
1067
+ type: "warning",
1068
+ message: "Your S3 firmware/config/certificate update interval (OTA) is set to 0, which disables over-the-air updates. The device will not fetch future configuration changes remotely. Set a non-zero interval unless this is intentional",
1069
+ autoClear: false
1070
+ }));
1071
+ }
1072
+ }
1073
+ };
1074
+ };
1062
1075
  var checkS3EncryptedPasswordsNoKpub = function checkS3EncryptedPasswordsNoKpub(content) {
1063
1076
  return function (dispatch) {
1064
1077
  if (content.connect != undefined && content.connect.s3 != undefined && content.connect.s3.server != undefined && content.general != undefined && content.general.security != undefined) {
@@ -1271,6 +1284,7 @@ var runConfigurationWarningChecks = function runConfigurationWarningChecks(conte
1271
1284
  dispatch(checkConfigFilterLimits(content));
1272
1285
  dispatch(checkConfigTls(content));
1273
1286
  dispatch(checkConfigAwsEndpoint(content));
1287
+ dispatch(checkS3OtaDisabled(content));
1274
1288
  dispatch(checkS3EncryptedPasswordsNoKpub(content));
1275
1289
  dispatch(checkWiFiEncryptedPasswordsNoKpub(content));
1276
1290
  dispatch(checkFileSplitOffsetPeriod(content));
@@ -1291,6 +1305,19 @@ var runConfigurationWarningChecks = function runConfigurationWarningChecks(conte
1291
1305
  dispatch(checkCANmodMonitoringMode(content));
1292
1306
  };
1293
1307
  };
1308
+ var collectConfigurationWarnings = function collectConfigurationWarnings(content) {
1309
+ var messages = [];
1310
+ var _capture = function capture(action) {
1311
+ if (typeof action === "function") return action(_capture, function () {
1312
+ return {};
1313
+ });
1314
+ if (action && action.type === "alert/SET" && action.alert && action.alert.type === "warning") {
1315
+ messages.push(action.alert.message);
1316
+ }
1317
+ };
1318
+ _capture(runConfigurationWarningChecks(content));
1319
+ return messages;
1320
+ };
1294
1321
  var checkCANmodMonitoringMode = function checkCANmodMonitoringMode(content) {
1295
1322
  return function (dispatch) {
1296
1323
  var _content$phy, _content$phy$can, _content$phy$can$phy;
@@ -1414,6 +1441,7 @@ var actions = {
1414
1441
  checkConfigControlSignalZeroScalingFactor: checkConfigControlSignalZeroScalingFactor,
1415
1442
  checkConfigTls: checkConfigTls,
1416
1443
  checkConfigAwsEndpoint: checkConfigAwsEndpoint,
1444
+ checkS3OtaDisabled: checkS3OtaDisabled,
1417
1445
  checkS3EncryptedPasswordsNoKpub: checkS3EncryptedPasswordsNoKpub,
1418
1446
  checkWiFiEncryptedPasswordsNoKpub: checkWiFiEncryptedPasswordsNoKpub,
1419
1447
  checkFileSplitOffsetPeriod: checkFileSplitOffsetPeriod,
@@ -1430,6 +1458,7 @@ var actions = {
1430
1458
  checkFileSplitValue: checkFileSplitValue,
1431
1459
  checkGNSSEstimate: checkGNSSEstimate,
1432
1460
  runConfigurationWarningChecks: runConfigurationWarningChecks,
1461
+ collectConfigurationWarnings: collectConfigurationWarnings,
1433
1462
  checkCANmodMonitoringMode: checkCANmodMonitoringMode,
1434
1463
  saveUpdatedConfiguration: saveUpdatedConfiguration,
1435
1464
  setUpdatedFormData: setUpdatedFormData,
@@ -18935,11 +18964,9 @@ var PartialConfigLoader = /*#__PURE__*/function (_React$Component) {
18935
18964
  var _this$props = this.props,
18936
18965
  formData = _this$props.formData,
18937
18966
  schemaContent = _this$props.schemaContent;
18938
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h4", null, "Partial config loader"), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
18967
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h4", null, "Partial config loader"), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
18939
18968
  className: "form-group pl0 field-string"
18940
18969
  }, /*#__PURE__*/React.createElement("p", {
18941
- className: "reduced-margin"
18942
- }, "Upload partial Configuration File"), /*#__PURE__*/React.createElement("p", {
18943
18970
  className: "field-description field-description-shift"
18944
18971
  }, "Select a JSON file containing a partial Configuration File. This lets you e.g. load a list of transmit messages or filters. The loaded JSON is validated vs. the Rule Schema, after which it can be merged into the editor Configuration File (even if it is not valid)")), /*#__PURE__*/React.createElement("div", null, formData ? /*#__PURE__*/React.createElement("div", {
18945
18972
  className: "text-area-wrapper row no-gutters reduced-margin"
@@ -18958,10 +18985,13 @@ var PartialConfigLoader = /*#__PURE__*/function (_React$Component) {
18958
18985
  minFileSize: 0,
18959
18986
  clickable: true
18960
18987
  }, /*#__PURE__*/React.createElement("button", {
18961
- className: "btn btn-primary"
18988
+ className: "btn btn-primary",
18989
+ title: "Upload a partial Configuration File to merge it"
18962
18990
  }, "Load JSON file"), /*#__PURE__*/React.createElement("div", {
18963
18991
  className: "browse-file-name"
18964
- }, jsonFileName))), Object.keys(jsonFile).length ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("pre", {
18992
+ }, jsonFileName))), Object.keys(jsonFile).length ? /*#__PURE__*/React.createElement("div", {
18993
+ className: "text-area-wrapper row no-gutters"
18994
+ }, /*#__PURE__*/React.createElement("pre", {
18965
18995
  className: "browse-file-preview"
18966
18996
  }, JSON.stringify(jsonFile, null, 2)), formData ? /*#__PURE__*/React.createElement("div", null, mergedConfigValid ? /*#__PURE__*/React.createElement("div", {
18967
18997
  className: "btn-highlight",
@@ -19156,6 +19186,57 @@ function ArrayFieldTemplate(props) {
19156
19186
  }), " "))));
19157
19187
  }
19158
19188
 
19189
+ var isPlainObject = function isPlainObject(value) {
19190
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
19191
+ };
19192
+ var jsonEqual = function jsonEqual(a, b) {
19193
+ return JSON.stringify(a) === JSON.stringify(b);
19194
+ };
19195
+ var clone = function clone(value) {
19196
+ return JSON.parse(JSON.stringify(value));
19197
+ };
19198
+ var computeConfigDelta = function computeConfigDelta(past, current) {
19199
+ var deletions = [];
19200
+ if (!isPlainObject(past) || !isPlainObject(current)) {
19201
+ return {
19202
+ partial: isPlainObject(current) ? clone(current) : {},
19203
+ deletions: deletions
19204
+ };
19205
+ }
19206
+ var _walk = function walk(pastNode, currentNode, path) {
19207
+ var partialNode = {};
19208
+ Object.keys(currentNode).forEach(function (key) {
19209
+ var childPath = path ? path + '.' + key : key;
19210
+ var pastValue = pastNode[key];
19211
+ var currentValue = currentNode[key];
19212
+ if (!(key in pastNode)) {
19213
+ partialNode[key] = clone(currentValue);
19214
+ } else if (isPlainObject(pastValue) && isPlainObject(currentValue)) {
19215
+ var childPartial = _walk(pastValue, currentValue, childPath);
19216
+ if (Object.keys(childPartial).length) {
19217
+ partialNode[key] = childPartial;
19218
+ }
19219
+ } else if (!jsonEqual(pastValue, currentValue)) {
19220
+ if (Array.isArray(pastValue) && isPlainObject(currentValue)) {
19221
+ deletions.push(childPath);
19222
+ } else {
19223
+ partialNode[key] = clone(currentValue);
19224
+ }
19225
+ }
19226
+ });
19227
+ Object.keys(pastNode).forEach(function (key) {
19228
+ if (!(key in currentNode)) {
19229
+ deletions.push(path ? path + '.' + key : key);
19230
+ }
19231
+ });
19232
+ return partialNode;
19233
+ };
19234
+ return {
19235
+ partial: _walk(past, current, ''),
19236
+ deletions: deletions
19237
+ };
19238
+ };
19239
+
19159
19240
  var selectOptions$1 = function selectOptions(Files) {
19160
19241
  Files = lodash.orderBy(Files, ["name"], ["desc"]);
19161
19242
  return [].concat(Files, [{
@@ -19171,7 +19252,7 @@ var pastCrc32 = "N/A";
19171
19252
  var _require$1 = require("detect-browser"),
19172
19253
  detect$1 = _require$1.detect;
19173
19254
  var browser$1 = detect$1();
19174
- var crcBrowserSupport$1 = ["chrome", "firefox", "opera", "safari", "edge"].includes(browser$1.name);
19255
+ var crcBrowserSupport$1 = ["chrome", "firefox", "opera", "safari", "edge"].includes(browser$1 && browser$1.name);
19175
19256
  var EditorChangesComparison = /*#__PURE__*/function (_React$Component) {
19176
19257
  function EditorChangesComparison(props) {
19177
19258
  var _this;
@@ -19184,6 +19265,68 @@ var EditorChangesComparison = /*#__PURE__*/function (_React$Component) {
19184
19265
  _this.handleSelectChange = function (selectedValue) {
19185
19266
  _this.props.handleDropdownChange(selectedValue.value, "Previous Configuration File");
19186
19267
  };
19268
+ _this.getPartialDelta = function () {
19269
+ var _this$props = _this.props,
19270
+ past = _this$props.past,
19271
+ current = _this$props.current,
19272
+ showAlert = _this$props.showAlert;
19273
+ var pastObj = null;
19274
+ try {
19275
+ pastObj = JSON.parse(past);
19276
+ } catch (e) {
19277
+ pastObj = null;
19278
+ }
19279
+ if (!pastObj || typeof pastObj !== "object") {
19280
+ if (showAlert) {
19281
+ showAlert("info", "Select a Previous Configuration File first");
19282
+ }
19283
+ return null;
19284
+ }
19285
+ var _computeConfigDelta = computeConfigDelta(pastObj, current),
19286
+ partial = _computeConfigDelta.partial,
19287
+ deletions = _computeConfigDelta.deletions;
19288
+ if (!Object.keys(partial).length) {
19289
+ if (showAlert) {
19290
+ showAlert("info", "No changes detected vs. the Previous Configuration File");
19291
+ }
19292
+ return null;
19293
+ }
19294
+ if (deletions.length && showAlert) {
19295
+ showAlert("warning", deletions.length + " deleted setting(s) cannot be expressed in a partial config and were excluded: " + deletions.join(", "));
19296
+ }
19297
+ return {
19298
+ partial: partial,
19299
+ deletions: deletions
19300
+ };
19301
+ };
19302
+ _this.onDownloadPartial = function () {
19303
+ var delta = _this.getPartialDelta();
19304
+ if (!delta) {
19305
+ return;
19306
+ }
19307
+ var revisedConfigFile = _this.props.revisedConfigFile;
19308
+ var fileName = "partial-" + (revisedConfigFile && revisedConfigFile.value || "config.json");
19309
+ var blob = new Blob([JSON.stringify(delta.partial, null, 2)], {
19310
+ type: "text/json"
19311
+ });
19312
+ saveAs$1(blob, fileName);
19313
+ };
19314
+ _this.onTransferClick = function () {
19315
+ var delta = _this.getPartialDelta();
19316
+ if (!delta) {
19317
+ return;
19318
+ }
19319
+ var _this$props2 = _this.props,
19320
+ onTransferPartial = _this$props2.onTransferPartial,
19321
+ closeChangesModal = _this$props2.closeChangesModal,
19322
+ revisedConfigFile = _this$props2.revisedConfigFile;
19323
+ closeChangesModal();
19324
+ onTransferPartial({
19325
+ partial: delta.partial,
19326
+ deletions: delta.deletions,
19327
+ configName: revisedConfigFile && revisedConfigFile.value || null
19328
+ });
19329
+ };
19187
19330
  _this.toggleCheckbox = _this.toggleCheckbox.bind(_this);
19188
19331
  _this.handleSelectChange = _this.handleSelectChange.bind(_this);
19189
19332
  _this.state = {
@@ -19194,17 +19337,17 @@ var EditorChangesComparison = /*#__PURE__*/function (_React$Component) {
19194
19337
  _inheritsLoose(EditorChangesComparison, _React$Component);
19195
19338
  var _proto = EditorChangesComparison.prototype;
19196
19339
  _proto.render = function render() {
19197
- var _this$props = this.props,
19198
- options = _this$props.options,
19199
- selected = _this$props.selected,
19200
- past = _this$props.past,
19201
- current = _this$props.current,
19202
- closeChangesModal = _this$props.closeChangesModal,
19203
- revisedConfigFile = _this$props.revisedConfigFile,
19204
- crc32EditorLive = _this$props.crc32EditorLive,
19205
- isCompareChanges = _this$props.isCompareChanges,
19206
- enableDownload = _this$props.enableDownload,
19207
- externalSubmit = _this$props.externalSubmit;
19340
+ var _this$props3 = this.props,
19341
+ options = _this$props3.options,
19342
+ selected = _this$props3.selected,
19343
+ past = _this$props3.past,
19344
+ current = _this$props3.current,
19345
+ closeChangesModal = _this$props3.closeChangesModal,
19346
+ revisedConfigFile = _this$props3.revisedConfigFile,
19347
+ crc32EditorLive = _this$props3.crc32EditorLive,
19348
+ isCompareChanges = _this$props3.isCompareChanges,
19349
+ enableDownload = _this$props3.enableDownload,
19350
+ externalSubmit = _this$props3.externalSubmit;
19208
19351
  var pastCleaned = past && Object.keys(past).length ? JSON.stringify(JSON.parse(past), null, 2) : "";
19209
19352
  if (crcBrowserSupport$1 == 1 && past && Object.keys(past).length) {
19210
19353
  var _require2 = require("crc"),
@@ -19213,6 +19356,15 @@ var EditorChangesComparison = /*#__PURE__*/function (_React$Component) {
19213
19356
  } else {
19214
19357
  pastCrc32 = "N/A";
19215
19358
  }
19359
+ var partialAvailable = false;
19360
+ try {
19361
+ var pastObj = past ? JSON.parse(past) : null;
19362
+ if (pastObj && typeof pastObj === "object") {
19363
+ partialAvailable = Object.keys(computeConfigDelta(pastObj, current).partial).length > 0;
19364
+ }
19365
+ } catch (e) {
19366
+ partialAvailable = false;
19367
+ }
19216
19368
  return /*#__PURE__*/React.createElement("div", {
19217
19369
  className: isCompareChanges ? "show modal-custom-wrapper" : "hidden modal-custom-wrapper"
19218
19370
  }, /*#__PURE__*/React.createElement("div", {
@@ -19289,7 +19441,19 @@ var EditorChangesComparison = /*#__PURE__*/function (_React$Component) {
19289
19441
  type: "submit",
19290
19442
  onClick: enableDownload,
19291
19443
  className: "btn btn-primary ml15"
19292
- }, " ", "Download to disk", " "))));
19444
+ }, " ", "Download to disk", " "), /*#__PURE__*/React.createElement("button", {
19445
+ type: "button",
19446
+ onClick: this.onDownloadPartial,
19447
+ className: "btn btn-white ml15",
19448
+ disabled: !partialAvailable,
19449
+ title: "Download the delta changes as a partial config JSON e.g. for application across multiple devices"
19450
+ }, " ", "Download partial JSON to disk", " "), typeof this.props.onTransferPartial === "function" ? /*#__PURE__*/React.createElement("button", {
19451
+ type: "button",
19452
+ onClick: this.onTransferClick,
19453
+ className: "btn btn-white ml15",
19454
+ disabled: !partialAvailable,
19455
+ title: "Transfer the delta changes as a partial config JSON to the OTA batch manager for application across multiple devices"
19456
+ }, " ", "Transfer to OTA batch manager", " ") : null)));
19293
19457
  };
19294
19458
  return EditorChangesComparison;
19295
19459
  }(React.Component);
@@ -19624,7 +19788,9 @@ var EditorSection = /*#__PURE__*/function (_React$Component) {
19624
19788
  handleDropdownChange: this.handleDropdownChange,
19625
19789
  closeChangesModal: this.closeChangesModal,
19626
19790
  enableDownload: this.enableDownload.bind(this),
19627
- externalSubmit: this.props.fetchFileContentExt ? true : false
19791
+ externalSubmit: this.props.fetchFileContentExt ? true : false,
19792
+ showAlert: this.props.showAlert,
19793
+ onTransferPartial: this.props.onTransferPartial
19628
19794
  }), /*#__PURE__*/React.createElement("div", {
19629
19795
  className: classNames({
19630
19796
  'config-bar': true,
@@ -22766,8 +22932,7 @@ var OBDTool = /*#__PURE__*/function (_React$Component) {
22766
22932
  });
22767
22933
  },
22768
22934
  style: {
22769
- marginRight: "6px",
22770
- marginBottom: "4px"
22935
+ marginRight: "6px"
22771
22936
  }
22772
22937
  }), "Add filter to only log OBD data on ", channel === "can_1" ? "CAN-1" : "CAN-2"), /*#__PURE__*/React.createElement("p", {
22773
22938
  className: "field-description field-description-shift"
@@ -22796,8 +22961,7 @@ var OBDTool = /*#__PURE__*/function (_React$Component) {
22796
22961
  },
22797
22962
  disabled: !hasGnssSupport,
22798
22963
  style: {
22799
- marginRight: "6px",
22800
- marginBottom: "4px"
22964
+ marginRight: "6px"
22801
22965
  }
22802
22966
  }), "Add GPS-based speed control signal"), /*#__PURE__*/React.createElement("p", {
22803
22967
  className: "field-description field-description-shift"
@@ -24914,7 +25078,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
24914
25078
  style: {
24915
25079
  width: barWidth + "px",
24916
25080
  height: "10px",
24917
- backgroundColor: "#4a90d9",
25081
+ backgroundColor: "#46a5e0",
24918
25082
  borderRadius: "2px",
24919
25083
  display: "inline-block"
24920
25084
  }
@@ -25032,8 +25196,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25032
25196
  });
25033
25197
  },
25034
25198
  style: {
25035
- marginRight: "6px",
25036
- marginBottom: "2px"
25199
+ marginRight: "6px"
25037
25200
  }
25038
25201
  }), "Group 29-bit IDs as PGNs"), /*#__PURE__*/React.createElement("p", {
25039
25202
  className: "field-description field-description-shift"
@@ -25061,8 +25224,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25061
25224
  },
25062
25225
  disabled: !isEnabled,
25063
25226
  style: {
25064
- marginRight: "6px",
25065
- marginBottom: "2px"
25227
+ marginRight: "6px"
25066
25228
  }
25067
25229
  }), "Show summary with current filters"), /*#__PURE__*/React.createElement("p", {
25068
25230
  className: "field-description field-description-shift"
@@ -25380,7 +25542,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25380
25542
  }
25381
25543
  }, "Select: "), /*#__PURE__*/React.createElement("span", {
25382
25544
  style: {
25383
- color: "#337ab7",
25545
+ color: "#46a5e0",
25384
25546
  cursor: "pointer",
25385
25547
  marginLeft: "4px"
25386
25548
  },
@@ -25394,7 +25556,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25394
25556
  }
25395
25557
  }, "|"), /*#__PURE__*/React.createElement("span", {
25396
25558
  style: {
25397
- color: "#337ab7",
25559
+ color: "#46a5e0",
25398
25560
  cursor: "pointer"
25399
25561
  },
25400
25562
  onClick: function onClick() {
@@ -25407,7 +25569,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25407
25569
  }
25408
25570
  }, "|"), /*#__PURE__*/React.createElement("span", {
25409
25571
  style: {
25410
- color: "#337ab7",
25572
+ color: "#46a5e0",
25411
25573
  cursor: "pointer"
25412
25574
  },
25413
25575
  onClick: function onClick() {
@@ -25420,7 +25582,7 @@ var FilterBuilderTool = /*#__PURE__*/function (_React$Component) {
25420
25582
  }
25421
25583
  }, "|"), /*#__PURE__*/React.createElement("span", {
25422
25584
  style: {
25423
- color: "#337ab7",
25585
+ color: "#46a5e0",
25424
25586
  cursor: "pointer"
25425
25587
  },
25426
25588
  onClick: function onClick() {
@@ -25745,5 +25907,5 @@ var mapDispatchToProps$4 = function mapDispatchToProps(dispatch) {
25745
25907
  };
25746
25908
  var FilterBuilderTool$1 = connect(mapStateToProps$4, mapDispatchToProps$4)(FilterBuilderTool);
25747
25909
 
25748
- export { EditorSection$1 as EditorSection, FilterBuilderTool$1 as FilterBuilderTool, OBDTool$1 as OBDTool, reducer as editor, actions as editorActions };
25910
+ export { EditorSection$1 as EditorSection, FilterBuilderTool$1 as FilterBuilderTool, OBDTool$1 as OBDTool, computeConfigDelta, reducer as editor, actions as editorActions };
25749
25911
  //# sourceMappingURL=index.modern.js.map