@cyprnet/node-red-contrib-uibuilder-formgen 0.5.12 → 0.5.13

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/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ All notable changes to this package will be documented in this file.
6
6
 
7
7
  - Schema Builder: added a **Convert multiline → arrays** helper in the Lookups editor to migrate older lookup lists (newline strings) into arrays-of-strings.
8
8
 
9
+ ## 0.5.13
10
+
11
+ - Schema Builder: Field editor now **stays open on validation errors** so dynamic Lookup/Auto-fill settings (e.g. Node-RED source requiring Lookup ID) don’t appear to “revert” after clicking OK.
12
+
9
13
  ## 0.5.11
10
14
 
11
15
  - Lookup / Auto-fill: lookup items can now store lists as **arrays** (e.g. <code>["a","b"]</code>) and the portal will format arrays for textarea/keyvalue targets. Builder Lookups editor now includes a **Simple list** mode (one item per line → JSON array).
@@ -942,16 +942,25 @@
942
942
  this.$bvModal.show('field-modal');
943
943
  },
944
944
 
945
- saveField() {
945
+ saveField(bvModalEvt) {
946
+ const preventClose = () => {
947
+ if (bvModalEvt && typeof bvModalEvt.preventDefault === 'function') {
948
+ bvModalEvt.preventDefault();
949
+ }
950
+ };
951
+ const fail = (msg) => {
952
+ preventClose();
953
+ this.showAlertMessage(msg, 'warning');
954
+ return false;
955
+ };
956
+
946
957
  if (!this.currentField.id || !this.currentField.label) {
947
- this.showAlertMessage('Field ID and Label are required', 'warning');
948
- return;
958
+ return fail('Field ID and Label are required');
949
959
  }
950
960
 
951
961
  // Validate field ID
952
962
  if (!/^[a-zA-Z0-9._-]+$/.test(this.currentField.id)) {
953
- this.showAlertMessage('Field ID must be alphanumeric with underscores or hyphens', 'warning');
954
- return;
963
+ return fail('Field ID must be alphanumeric with underscores or hyphens');
955
964
  }
956
965
 
957
966
  const { sectionIdx, fieldIdx } = this.editingFieldLocation;
@@ -961,8 +970,7 @@
961
970
  if (fieldIdx === null) {
962
971
  const exists = section.fields.some(f => f.id === this.currentField.id);
963
972
  if (exists) {
964
- this.showAlertMessage('Field ID already exists in this section', 'warning');
965
- return;
973
+ return fail('Field ID already exists in this section');
966
974
  }
967
975
  } else {
968
976
  // Check if ID changed and conflicts
@@ -970,8 +978,7 @@
970
978
  if (oldField.id !== this.currentField.id) {
971
979
  const exists = section.fields.some((f, idx) => idx !== fieldIdx && f.id === this.currentField.id);
972
980
  if (exists) {
973
- this.showAlertMessage('Field ID already exists in this section', 'warning');
974
- return;
981
+ return fail('Field ID already exists in this section');
975
982
  }
976
983
  }
977
984
  }
@@ -1022,8 +1029,7 @@
1022
1029
  delete field.options;
1023
1030
  } else if (this.currentField.type === 'select' || this.currentField.type === 'radio') {
1024
1031
  if (!this.currentField.options || this.currentField.options.length === 0) {
1025
- this.showAlertMessage(`${this.currentField.type} fields require at least one option`, 'warning');
1026
- return;
1032
+ return fail(`${this.currentField.type} fields require at least one option`);
1027
1033
  }
1028
1034
  // Filter out empty options and ensure both value and text exist
1029
1035
  const validOptions = this.currentField.options
@@ -1034,8 +1040,7 @@
1034
1040
  }));
1035
1041
 
1036
1042
  if (validOptions.length === 0) {
1037
- this.showAlertMessage(`${this.currentField.type} fields require at least one valid option`, 'warning');
1038
- return;
1043
+ return fail(`${this.currentField.type} fields require at least one valid option`);
1039
1044
  }
1040
1045
 
1041
1046
  field.options = validOptions;
@@ -1053,8 +1058,7 @@
1053
1058
 
1054
1059
  if (field.keyvalueMode === 'pairs') {
1055
1060
  if (!this.currentField.pairs || this.currentField.pairs.length === 0) {
1056
- this.showAlertMessage('Key-Value fields require at least one pair', 'warning');
1057
- return;
1061
+ return fail('Key-Value fields require at least one pair');
1058
1062
  }
1059
1063
  // Filter out empty pairs and ensure both key and value exist
1060
1064
  const validPairs = this.currentField.pairs
@@ -1065,16 +1069,14 @@
1065
1069
  }));
1066
1070
 
1067
1071
  if (validPairs.length === 0) {
1068
- this.showAlertMessage('Key-Value fields require at least one valid pair with a key', 'warning');
1069
- return;
1072
+ return fail('Key-Value fields require at least one valid pair with a key');
1070
1073
  }
1071
1074
 
1072
1075
  field.pairs = validPairs;
1073
1076
  } else {
1074
1077
  // Delimiter mode - no pairs needed, but validate delimiter
1075
1078
  if (!field.keyvalueDelimiter || field.keyvalueDelimiter.trim() === '') {
1076
- this.showAlertMessage('Delimiter is required for delimiter mode', 'warning');
1077
- return;
1079
+ return fail('Delimiter is required for delimiter mode');
1078
1080
  }
1079
1081
  }
1080
1082
 
@@ -1120,31 +1122,26 @@
1120
1122
  .filter(m => m.targetField && m.valueKey);
1121
1123
 
1122
1124
  if (!fromField) {
1123
- this.showAlertMessage('Lookup/Auto-fill: "From field" is required when enabled', 'warning');
1124
- return;
1125
+ return fail('Lookup/Auto-fill: "From field" is required when enabled');
1125
1126
  }
1126
1127
  if (!matchKey) {
1127
- this.showAlertMessage('Lookup/Auto-fill: "Match key" is required when enabled', 'warning');
1128
- return;
1128
+ return fail('Lookup/Auto-fill: "Match key" is required when enabled');
1129
1129
  }
1130
1130
  if (cleanedMappings.length === 0) {
1131
- this.showAlertMessage('Lookup/Auto-fill: add at least one mapping (target field + value key)', 'warning');
1132
- return;
1131
+ return fail('Lookup/Auto-fill: add at least one mapping (target field + value key)');
1133
1132
  }
1134
1133
 
1135
1134
  let source = null;
1136
1135
  if (sourceType === 'uibuilder') {
1137
1136
  const lookupId = String(af.lookupId || '').trim();
1138
1137
  if (!lookupId) {
1139
- this.showAlertMessage('Lookup/Auto-fill: "Lookup ID" is required for Node-RED (dynamic) source', 'warning');
1140
- return;
1138
+ return fail('Lookup/Auto-fill: "Lookup ID" is required for Node-RED (dynamic) source');
1141
1139
  }
1142
1140
  source = { type: 'uibuilder', lookupId };
1143
1141
  } else {
1144
1142
  const listName = String(af.schemaListName || '').trim();
1145
1143
  if (!listName) {
1146
- this.showAlertMessage('Lookup/Auto-fill: "List name" is required for Schema (static) source', 'warning');
1147
- return;
1144
+ return fail('Lookup/Auto-fill: "List name" is required for Schema (static) source');
1148
1145
  }
1149
1146
  source = { type: 'schema', path: `lookups.${listName}` };
1150
1147
 
@@ -1156,8 +1153,7 @@
1156
1153
  if (!this.schema.lookups) this.$set(this.schema, 'lookups', {});
1157
1154
  this.$set(this.schema.lookups, listName, parsed);
1158
1155
  } catch (e) {
1159
- this.showAlertMessage('Lookup/Auto-fill: schema list JSON is invalid', 'warning');
1160
- return;
1156
+ return fail('Lookup/Auto-fill: schema list JSON is invalid');
1161
1157
  }
1162
1158
  }
1163
1159
  }
@@ -455,7 +455,7 @@ module.exports = function(RED) {
455
455
  await fs.writeJson(targetSchema, schema, { spaces: 2 });
456
456
 
457
457
  const runtimeData = {
458
- generatorVersion: "0.5.12",
458
+ generatorVersion: "0.5.13",
459
459
  generatorNode: "uibuilder-formgen-v3",
460
460
  timestamp: new Date().toISOString(),
461
461
  instanceName: instanceName,
@@ -484,7 +484,7 @@ module.exports = function(RED) {
484
484
 
485
485
  // Write runtime metadata
486
486
  const runtimeData = {
487
- generatorVersion: "0.5.12",
487
+ generatorVersion: "0.5.13",
488
488
  timestamp: new Date().toISOString(),
489
489
  instanceName: instanceName,
490
490
  storageMode: storageMode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyprnet/node-red-contrib-uibuilder-formgen",
3
- "version": "0.5.12",
3
+ "version": "0.5.13",
4
4
  "description": "PortalSmith: Generate schema-driven uibuilder form portals from JSON",
5
5
  "keywords": [
6
6
  "node-red",