@vitormnm/node-red-simple-opcua 1.5.0 → 1.6.3
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/client/lib/opcua-client-read-service.js +14 -2
- package/client/lib/opcua-client-subscription-service.js +8 -3
- package/client/opcua-client-utils.js +206 -12
- package/examples/flows_simple_opc.json +1 -2851
- package/package.json +1 -1
- package/server/lib/opcua-address-space-builder.js +203 -9
- package/server/lib/opcua-config.js +131 -8
- package/server/lib/opcua-constants.js +1 -0
- package/server/lib/opcua-server-methods.js +2 -0
- package/server/lib/opcua-server-runtime-child.js +148 -42
- package/server/lib/opcua-server-runtime.js +14 -5
- package/server/opcua-server-io.js +9 -0
- package/server/opcua-server.html +4 -1
- package/server/opcua-server.js +27 -2
- package/server/view/opcua-server.css +4 -0
- package/server/view/opcua-server.js +178 -28
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
(function () {
|
|
3
|
-
var editorState = { objects: [], folders: [], objectsTypes: [], nameSpaces: [] };
|
|
3
|
+
var editorState = { objects: [], folders: [], objectsTypes: [], enumerations: [], nameSpaces: [] };
|
|
4
4
|
var expansionState = {};
|
|
5
5
|
var selectedPath = "";
|
|
6
6
|
var pendingCreate = null;
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
function closeAuthModal() { $("#node-input-auth-modal").hide(); syncModalBodyClass(); }
|
|
22
22
|
|
|
23
23
|
function parseTree(rawValue, strict) {
|
|
24
|
-
if (!rawValue) return { objects: [], folders: [], objectsTypes: [], nameSpaces: [] };
|
|
24
|
+
if (!rawValue) return { objects: [], folders: [], objectsTypes: [], enumerations: [], nameSpaces: [] };
|
|
25
25
|
if (typeof rawValue === "object") return rawValue;
|
|
26
26
|
try { var parsed = JSON.parse(rawValue); if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed; }
|
|
27
27
|
catch (error) { if (strict) throw error; }
|
|
28
|
-
return { objects: [], folders: [], objectsTypes: [], nameSpaces: [] };
|
|
28
|
+
return { objects: [], folders: [], objectsTypes: [], enumerations: [], nameSpaces: [] };
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function parseCredentialArray(rawValue) {
|
|
@@ -74,9 +74,13 @@
|
|
|
74
74
|
|
|
75
75
|
function reconcileAuthGroupsFromUsers() {
|
|
76
76
|
authUsers.forEach(function (user) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
if (user && user.group) {
|
|
78
|
+
var groups = String(user.group).split(",").map(function (g) { return g.trim(); }).filter(Boolean);
|
|
79
|
+
groups.forEach(function (groupName) {
|
|
80
|
+
if (authGroups.indexOf(groupName) === -1) {
|
|
81
|
+
authGroups.push(groupName);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
80
84
|
}
|
|
81
85
|
});
|
|
82
86
|
}
|
|
@@ -221,6 +225,29 @@
|
|
|
221
225
|
};
|
|
222
226
|
}
|
|
223
227
|
|
|
228
|
+
function normalizeEnumerationState(state) {
|
|
229
|
+
state = state || {};
|
|
230
|
+
return {
|
|
231
|
+
value: state.value !== undefined ? Number(state.value) : 0,
|
|
232
|
+
displayName: state.displayName ? String(state.displayName) : ""
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function normalizeEnumeration(enumeration) {
|
|
237
|
+
enumeration = enumeration || {};
|
|
238
|
+
return {
|
|
239
|
+
name: enumeration.name ? String(enumeration.name) : "",
|
|
240
|
+
description: enumeration.description ? String(enumeration.description) : "",
|
|
241
|
+
displayName: enumeration.displayName ? String(enumeration.displayName) : "",
|
|
242
|
+
nodeId: enumeration.nodeId ? String(enumeration.nodeId) : "",
|
|
243
|
+
namespaceId: normalizeNamespaceId(enumeration.namespaceId),
|
|
244
|
+
accessPermission: normalizeAccessPermissionValues(enumeration.accessPermission || enumeration.accessPermissions),
|
|
245
|
+
enumeration: Array.isArray(enumeration.enumeration)
|
|
246
|
+
? enumeration.enumeration.map(normalizeEnumerationState)
|
|
247
|
+
: []
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
224
251
|
function normalizeBranch(branch) {
|
|
225
252
|
branch = branch || {};
|
|
226
253
|
return {
|
|
@@ -246,6 +273,7 @@
|
|
|
246
273
|
objects: Array.isArray(tree.objects) ? tree.objects.map(normalizeBranch) : [],
|
|
247
274
|
folders: Array.isArray(tree.folders) ? tree.folders.map(normalizeBranch) : [],
|
|
248
275
|
objectsTypes: Array.isArray(tree.objectsTypes) ? tree.objectsTypes.map(normalizeBranch) : (Array.isArray(tree.objectTypes) ? tree.objectTypes.map(normalizeBranch) : []),
|
|
276
|
+
enumerations: Array.isArray(tree.enumerations) ? tree.enumerations.map(normalizeEnumeration) : (Array.isArray(tree.enumeration) ? tree.enumeration.map(normalizeEnumeration) : []),
|
|
249
277
|
nameSpaces: Array.isArray(tree.nameSpaces) ? tree.nameSpaces.map(normalizeNamespaceDefinition) : (Array.isArray(tree.namespaces) ? tree.namespaces.map(normalizeNamespaceDefinition) : [])
|
|
250
278
|
});
|
|
251
279
|
}
|
|
@@ -300,6 +328,7 @@
|
|
|
300
328
|
if (collectionToken === "methods") return "Method";
|
|
301
329
|
if (collectionToken === "alarms") return "Alarm";
|
|
302
330
|
if (collectionToken === "objectsTypes" || collectionToken === "objectTypes") return "ObjectType";
|
|
331
|
+
if (collectionToken === "enumerations" || collectionToken === "enumeration") return "Enumeration";
|
|
303
332
|
if (collectionToken === "nameSpaces" || collectionToken === "namespaces") return "Namespace";
|
|
304
333
|
if (collectionToken === "folders") return "Folder";
|
|
305
334
|
return "Object";
|
|
@@ -332,6 +361,28 @@
|
|
|
332
361
|
return "<select id=\"" + id + "\">" + opts + "</select>";
|
|
333
362
|
}
|
|
334
363
|
|
|
364
|
+
function getDefinedEnumerationNames() {
|
|
365
|
+
var names = [];
|
|
366
|
+
(editorState.enumerations || []).forEach(function (e) {
|
|
367
|
+
if (e && e.name) names.push(String(e.name));
|
|
368
|
+
});
|
|
369
|
+
return names;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function buildEnumerationSelect(id, currentValue) {
|
|
373
|
+
var names = getDefinedEnumerationNames();
|
|
374
|
+
var cv = String(currentValue || "");
|
|
375
|
+
var opts = "";
|
|
376
|
+
var noneSelected = (cv === "") ? " selected" : "";
|
|
377
|
+
opts += "<option value=\"\"" + noneSelected + ">\u2014 none \u2014</option>";
|
|
378
|
+
names.forEach(function (n) {
|
|
379
|
+
var esc = n.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
380
|
+
var sel = (n === cv) ? " selected" : "";
|
|
381
|
+
opts += "<option value=\"" + esc + "\"" + sel + ">" + esc + "</option>";
|
|
382
|
+
});
|
|
383
|
+
return "<select id=\"" + id + "\">" + opts + "</select>";
|
|
384
|
+
}
|
|
385
|
+
|
|
335
386
|
function getAvailableAccessPermissionOptions() {
|
|
336
387
|
var values = ["public"].concat(authGroups || []);
|
|
337
388
|
return normalizeAccessPermissionValues(values);
|
|
@@ -493,6 +544,7 @@
|
|
|
493
544
|
(editorState.folders || []).forEach(function (_, i) { paths.push("folders." + i); });
|
|
494
545
|
(editorState.objects || []).forEach(function (_, i) { paths.push("objects." + i); });
|
|
495
546
|
(editorState.objectsTypes || []).forEach(function (_, i) { paths.push("objectsTypes." + i); });
|
|
547
|
+
(editorState.enumerations || []).forEach(function (_, i) { paths.push("enumerations." + i); });
|
|
496
548
|
(editorState.nameSpaces || []).forEach(function (_, i) { paths.push("nameSpaces." + i); });
|
|
497
549
|
return paths;
|
|
498
550
|
}
|
|
@@ -520,6 +572,7 @@
|
|
|
520
572
|
if (nodeClass === "Object") return "fa-cube";
|
|
521
573
|
if (nodeClass === "Variable") return "fa-tag";
|
|
522
574
|
if (nodeClass === "ObjectType") return "fa-cubes";
|
|
575
|
+
if (nodeClass === "Enumeration") return "fa-list-ol";
|
|
523
576
|
if (nodeClass === "Namespace") return "fa-sitemap";
|
|
524
577
|
if (nodeClass === "Alarm") return "fa-bell";
|
|
525
578
|
if (nodeClass === "Method") return "fa-cog";
|
|
@@ -626,9 +679,9 @@
|
|
|
626
679
|
pendingCreate = {
|
|
627
680
|
parentPath: path,
|
|
628
681
|
kind: kind,
|
|
629
|
-
name: kind === "variable" ? "newVariable" : kind === "folder" ? "newFolder" : kind === "objecttype" ? "newObjectType" : kind === "alarm" ? "newAlarm" : kind === "method" ? "newMethod" : "newObject",
|
|
682
|
+
name: kind === "variable" ? "newVariable" : kind === "enum-variable" ? "newEnumVariable" : kind === "folder" ? "newFolder" : kind === "objecttype" ? "newObjectType" : kind === "alarm" ? "newAlarm" : kind === "method" ? "newMethod" : "newObject",
|
|
630
683
|
displayName: "",
|
|
631
|
-
dataType: "Int32",
|
|
684
|
+
dataType: kind === "enum-variable" ? (getDefinedEnumerationNames()[0] || "") : "Int32",
|
|
632
685
|
value: "",
|
|
633
686
|
access: "readwrite",
|
|
634
687
|
accessPermission: ["public"],
|
|
@@ -654,7 +707,7 @@
|
|
|
654
707
|
if (!pendingCreate) return;
|
|
655
708
|
var parentPath = pendingCreate.parentPath;
|
|
656
709
|
var kind = pendingCreate.kind;
|
|
657
|
-
var branchTargetPath = kind === "variable"
|
|
710
|
+
var branchTargetPath = (kind === "variable" || kind === "enum-variable")
|
|
658
711
|
? (parentPath + ".variables")
|
|
659
712
|
: kind === "folder"
|
|
660
713
|
? (parentPath + ".folders")
|
|
@@ -667,7 +720,7 @@
|
|
|
667
720
|
: (parentPath + ".objects");
|
|
668
721
|
var target = getAtPath(editorState, branchTargetPath);
|
|
669
722
|
if (!Array.isArray(target)) return;
|
|
670
|
-
if (kind === "variable") {
|
|
723
|
+
if (kind === "variable" || kind === "enum-variable") {
|
|
671
724
|
target.push(normalizeVariable({
|
|
672
725
|
name: pendingCreate.name,
|
|
673
726
|
displayName: pendingCreate.displayName || "",
|
|
@@ -725,8 +778,10 @@
|
|
|
725
778
|
panel.append('<div class="form-row"><label>Name</label><input type="text" id="opcua-create-name"></div>');
|
|
726
779
|
panel.append('<div class="form-row"><label>displayName</label><input type="text" id="opcua-create-displayname" placeholder="Leave blank to use browseName"></div>');
|
|
727
780
|
panel.append('<div class="form-row"><label>accessPermission</label>' + buildAccessPermissionSelect("opcua-create-accesspermission", pendingCreate.accessPermission || ["public"]) + '</div>');
|
|
728
|
-
if (pendingCreate.kind === "variable") {
|
|
729
|
-
|
|
781
|
+
if (pendingCreate.kind === "variable" || pendingCreate.kind === "enum-variable") {
|
|
782
|
+
var isEnum = pendingCreate.kind === "enum-variable";
|
|
783
|
+
var typeHtml = isEnum ? buildEnumerationSelect("opcua-create-type", pendingCreate.dataType) : '<select id="opcua-create-type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Int64">Int64</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option></select>';
|
|
784
|
+
panel.append('<div class="form-row"><label>dataType</label>' + typeHtml + '</div>');
|
|
730
785
|
panel.append('<div class="form-row"><label>Value</label><input type="text" id="opcua-create-value"></div>');
|
|
731
786
|
panel.append('<div class="form-row"><label>Access</label><select id="opcua-create-access"><option value="readwrite">readwrite</option><option value="readonly">readonly</option></select></div>');
|
|
732
787
|
}
|
|
@@ -794,6 +849,37 @@
|
|
|
794
849
|
if (normalizeNamespaceId(item.id) === DEFAULT_NAMESPACE_ID) $("#opcua-detail-namespace-entry-id").prop("disabled", true);
|
|
795
850
|
return;
|
|
796
851
|
}
|
|
852
|
+
if (nodeClass === "Enumeration") {
|
|
853
|
+
panel.append('<div class="form-row"><label>browseName</label><input type="text" id="opcua-detail-name"></div>');
|
|
854
|
+
panel.append('<div class="form-row"><label>namespace</label><select id="opcua-detail-namespace"></select></div>');
|
|
855
|
+
panel.append('<div class="form-row"><label>Description</label><input type="text" id="opcua-detail-description"></div>');
|
|
856
|
+
panel.append('<div class="form-row"><label>displayName</label><input type="text" id="opcua-detail-displayname" placeholder="Leave blank to use browseName"></div>');
|
|
857
|
+
panel.append('<hr style="margin:8px 0; border-color:#e3e3e3;">');
|
|
858
|
+
panel.append('<div style="font-size:11px;font-weight:700;text-transform:uppercase;color:#666;margin-bottom:4px;">States</div>');
|
|
859
|
+
var statesDiv = $('<div id="opcua-detail-states"></div>').appendTo(panel);
|
|
860
|
+
(item.enumeration || []).forEach(function (state, idx) {
|
|
861
|
+
var statePath = selectedPath + ".enumeration." + idx;
|
|
862
|
+
var stateBlock = $('<div style="border:1px solid #e3e3e3;border-radius:4px;padding:6px;margin-bottom:4px;"></div>');
|
|
863
|
+
stateBlock.append('<div class="form-row"><label>value</label><input type="number" class="opcua-enum-state-bind" data-state-path="' + statePath + '" data-field="value"></div>');
|
|
864
|
+
stateBlock.append('<div class="form-row"><label>displayName</label><input type="text" class="opcua-enum-state-bind" data-state-path="' + statePath + '" data-field="displayName"></div>');
|
|
865
|
+
stateBlock.append('<div class="form-row"><label></label><a href="#" class="editor-button editor-button-small opcua-enum-state-remove" data-state-path="' + statePath + '"><i class="fa fa-trash"></i> Remove</a></div>');
|
|
866
|
+
stateBlock.find('[data-field="value"]').val(state.value !== undefined ? state.value : 0);
|
|
867
|
+
stateBlock.find('[data-field="displayName"]').val(state.displayName || "");
|
|
868
|
+
statesDiv.append(stateBlock);
|
|
869
|
+
});
|
|
870
|
+
panel.append('<div class="form-row"><label></label><a href="#" class="editor-button editor-button-small" id="opcua-enum-add-state"><i class="fa fa-plus"></i> Add state</a></div>');
|
|
871
|
+
panel.append('<div class="form-row"><label style="width:90px;">Actions</label><div><a href="#" id="opcua-detail-edit" class="editor-button editor-button-small"><i class="fa fa-pencil"></i> Edit</a> <a href="#" id="opcua-detail-remove" class="editor-button editor-button-small"><i class="fa fa-trash"></i> Remove</a></div></div>');
|
|
872
|
+
|
|
873
|
+
$("#opcua-detail-name").val(item.name || "");
|
|
874
|
+
$("#opcua-detail-description").val(item.description || "");
|
|
875
|
+
namespaceOptions.forEach(function (option) {
|
|
876
|
+
$("#opcua-detail-namespace").append($("<option></option>").val(option.id).text(getNamespaceLabel(option.id)));
|
|
877
|
+
});
|
|
878
|
+
$("#opcua-detail-namespace").val(String(namespaceId));
|
|
879
|
+
$("#opcua-detail-displayname").val(item.displayName || "");
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
797
883
|
panel.append('<div class="form-row"><label>browseName</label><input type="text" id="opcua-detail-name"></div>');
|
|
798
884
|
panel.append('<div class="form-row"><label>nodeClass</label><input type="text" id="opcua-detail-class" readonly></div>');
|
|
799
885
|
panel.append('<div class="form-row"><label>namespace</label><select id="opcua-detail-namespace"></select></div>');
|
|
@@ -805,7 +891,12 @@
|
|
|
805
891
|
panel.append('<div class="form-row"><label>objectsType</label>' + buildObjectTypeSelect("opcua-detail-objectstype", item.objectsType || "") + '</div>');
|
|
806
892
|
}
|
|
807
893
|
if (nodeClass === "Variable") {
|
|
808
|
-
|
|
894
|
+
var enumNames = getDefinedEnumerationNames();
|
|
895
|
+
if (enumNames.indexOf(item.type) !== -1) {
|
|
896
|
+
panel.append('<div class="form-row"><label>dataType</label>' + buildEnumerationSelect("opcua-detail-type", item.type) + '</div>');
|
|
897
|
+
} else {
|
|
898
|
+
panel.append('<div class="form-row"><label>dataType</label><select id="opcua-detail-type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Int64">Int64</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option><option value="ByteString">ByteString</option></select></div>');
|
|
899
|
+
}
|
|
809
900
|
panel.append('<div class="form-row"><label>Value</label><input type="text" id="opcua-detail-value"></div>');
|
|
810
901
|
panel.append('<div class="form-row"><label>Access</label><select id="opcua-detail-access"><option value="readwrite">readwrite</option><option value="readonly">readonly</option></select></div>');
|
|
811
902
|
}
|
|
@@ -817,7 +908,7 @@
|
|
|
817
908
|
var argPath = selectedPath + ".inputs." + idx;
|
|
818
909
|
var argBlock = $('<div style="border:1px solid #e3e3e3;border-radius:4px;padding:6px;margin-bottom:4px;"></div>');
|
|
819
910
|
argBlock.append('<div class="form-row"><label>name</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="name"></div>');
|
|
820
|
-
argBlock.append('<div class="form-row"><label>type</label><select class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option></select></div>');
|
|
911
|
+
argBlock.append('<div class="form-row"><label>type</label><select class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Int64">Int64</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option></select></div>');
|
|
821
912
|
argBlock.append('<div class="form-row"><label>displayName</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="displayName"></div>');
|
|
822
913
|
argBlock.append('<div class="form-row"><label>description</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="description"></div>');
|
|
823
914
|
argBlock.append('<div class="form-row"><label></label><a href="#" class="editor-button editor-button-small opcua-method-arg-remove" data-arg-path="' + argPath + '"><i class="fa fa-trash"></i> Remove</a></div>');
|
|
@@ -835,7 +926,7 @@
|
|
|
835
926
|
var argPath = selectedPath + ".outputs." + idx;
|
|
836
927
|
var argBlock = $('<div style="border:1px solid #e3e3e3;border-radius:4px;padding:6px;margin-bottom:4px;"></div>');
|
|
837
928
|
argBlock.append('<div class="form-row"><label>name</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="name"></div>');
|
|
838
|
-
argBlock.append('<div class="form-row"><label>type</label><select class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option></select></div>');
|
|
929
|
+
argBlock.append('<div class="form-row"><label>type</label><select class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="type"><option value="Int16">Int16</option><option value="Int32">Int32</option><option value="Int64">Int64</option><option value="Float">Float</option><option value="Boolean">Boolean</option><option value="String">String</option></select></div>');
|
|
839
930
|
argBlock.append('<div class="form-row"><label>displayName</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="displayName"></div>');
|
|
840
931
|
argBlock.append('<div class="form-row"><label>description</label><input type="text" class="opcua-method-arg-bind" data-arg-path="' + argPath + '" data-field="description"></div>');
|
|
841
932
|
argBlock.append('<div class="form-row"><label></label><a href="#" class="editor-button editor-button-small opcua-method-arg-remove" data-arg-path="' + argPath + '"><i class="fa fa-trash"></i> Remove</a></div>');
|
|
@@ -968,7 +1059,11 @@
|
|
|
968
1059
|
|
|
969
1060
|
function removeAuthGroup(index) {
|
|
970
1061
|
var groupName = authGroups[index];
|
|
971
|
-
var inUse = authUsers.some(function (user) {
|
|
1062
|
+
var inUse = authUsers.some(function (user) {
|
|
1063
|
+
if (!user.group) return false;
|
|
1064
|
+
var groups = String(user.group).split(",").map(function (g) { return g.trim(); });
|
|
1065
|
+
return groups.indexOf(groupName) !== -1;
|
|
1066
|
+
});
|
|
972
1067
|
if (inUse) {
|
|
973
1068
|
RED.notify("Reassign users before removing this group.", "warning");
|
|
974
1069
|
return;
|
|
@@ -1009,16 +1104,35 @@
|
|
|
1009
1104
|
return;
|
|
1010
1105
|
}
|
|
1011
1106
|
|
|
1107
|
+
var groupOptions = authGroups.map(function (groupName) {
|
|
1108
|
+
return { value: groupName, label: groupName };
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1012
1111
|
authUsers.forEach(function (user, index) {
|
|
1013
1112
|
var card = $('<div class="opcua-auth-card"></div>');
|
|
1014
1113
|
card.append('<div class="form-row"><label>Username</label><input type="text" class="opcua-auth-user-username" data-index="' + index + '"></div>');
|
|
1015
1114
|
card.append('<div class="form-row"><label>Password</label><input type="password" class="opcua-auth-user-password" data-index="' + index + '" autocomplete="new-password"></div>');
|
|
1016
|
-
card.append('<div class="form-row"><label>Group</label><
|
|
1115
|
+
card.append('<div class="form-row"><label>Group</label><input type="text" class="opcua-auth-user-group" id="opcua-auth-user-group-' + index + '" data-index="' + index + '"></div>');
|
|
1017
1116
|
card.append('<div class="form-row"><label></label><a href="#" class="editor-button editor-button-small opcua-auth-user-remove" data-index="' + index + '"><i class="fa fa-trash"></i> Remove</a></div>');
|
|
1018
1117
|
card.find(".opcua-auth-user-username").val(user.username || "");
|
|
1019
1118
|
card.find(".opcua-auth-user-password").val(user.password || "");
|
|
1020
|
-
card.find(".opcua-auth-user-group").val(user.group || "");
|
|
1021
1119
|
container.append(card);
|
|
1120
|
+
|
|
1121
|
+
$("#opcua-auth-user-group-" + index).typedInput({
|
|
1122
|
+
types: [
|
|
1123
|
+
{
|
|
1124
|
+
value: "groups",
|
|
1125
|
+
multiple: "true",
|
|
1126
|
+
options: groupOptions
|
|
1127
|
+
}
|
|
1128
|
+
]
|
|
1129
|
+
});
|
|
1130
|
+
$("#opcua-auth-user-group-" + index).typedInput("value", user.group || "");
|
|
1131
|
+
$("#opcua-auth-user-group-" + index).on("change", function () {
|
|
1132
|
+
var idx = Number($(this).attr("data-index"));
|
|
1133
|
+
authUsers[idx].group = $(this).typedInput("value");
|
|
1134
|
+
syncAuthCredentialFields();
|
|
1135
|
+
});
|
|
1022
1136
|
});
|
|
1023
1137
|
}
|
|
1024
1138
|
|
|
@@ -1087,8 +1201,12 @@
|
|
|
1087
1201
|
function addItem(parentPath, kind) {
|
|
1088
1202
|
var target = getAtPath(editorState, parentPath);
|
|
1089
1203
|
if (!Array.isArray(target)) return;
|
|
1090
|
-
if (kind === "object" || kind === "folder" || kind === "objectTypeDefinition") {
|
|
1091
|
-
|
|
1204
|
+
if (kind === "object" || kind === "folder" || kind === "objectTypeDefinition" || kind === "enumeration") {
|
|
1205
|
+
if (kind === "enumeration") {
|
|
1206
|
+
target.push(normalizeEnumeration({ name: "newEnumeration", enumeration: [{ value: 0, displayName: "State0" }] }));
|
|
1207
|
+
} else {
|
|
1208
|
+
target.push(normalizeBranch());
|
|
1209
|
+
}
|
|
1092
1210
|
if (kind === "objectTypeDefinition") {
|
|
1093
1211
|
target[target.length - 1].nodeId = buildGeneratedNodeIdForPath(parentPath + "." + (target.length - 1));
|
|
1094
1212
|
}
|
|
@@ -1140,6 +1258,8 @@
|
|
|
1140
1258
|
if (action === "add-object") addNode(selectedPath, "object");
|
|
1141
1259
|
if (action === "add-variable") addNode(selectedPath, "variable");
|
|
1142
1260
|
if (action === "add-objecttype") addNode(selectedPath, "objecttype");
|
|
1261
|
+
if (action === "add-enumeration") { addItem("enumerations", "enumeration"); syncStateToJson(true); renderVisualEditor(); }
|
|
1262
|
+
if (action === "add-enum-variable") addNode(selectedPath, "enum-variable");
|
|
1143
1263
|
if (action === "add-alarm") addNode(selectedPath, "alarm");
|
|
1144
1264
|
if (action === "add-method") addNode(selectedPath, "method");
|
|
1145
1265
|
if (action === "add-method") addNode(selectedPath, "method");
|
|
@@ -1186,6 +1306,36 @@
|
|
|
1186
1306
|
renderDetails();
|
|
1187
1307
|
});
|
|
1188
1308
|
|
|
1309
|
+
$(document).on("input change", ".opcua-enum-state-bind", function () {
|
|
1310
|
+
var el = $(this);
|
|
1311
|
+
var statePath = el.attr("data-state-path");
|
|
1312
|
+
var field = el.attr("data-field");
|
|
1313
|
+
var state = getAtPath(editorState, statePath);
|
|
1314
|
+
if (!state) return;
|
|
1315
|
+
state[field] = field === "value" ? Number(el.val()) : el.val();
|
|
1316
|
+
syncStateToJson(false);
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
$(document).on("click", ".opcua-enum-state-remove", function (e) {
|
|
1320
|
+
e.preventDefault();
|
|
1321
|
+
var statePath = $(this).attr("data-state-path");
|
|
1322
|
+
removeAtPath(editorState, statePath);
|
|
1323
|
+
syncStateToJson(false);
|
|
1324
|
+
renderDetails();
|
|
1325
|
+
});
|
|
1326
|
+
|
|
1327
|
+
$(document).on("click", "#opcua-enum-add-state", function (e) {
|
|
1328
|
+
e.preventDefault();
|
|
1329
|
+
var item = getAtPath(editorState, selectedPath);
|
|
1330
|
+
if (!item) return;
|
|
1331
|
+
if (!Array.isArray(item.enumeration)) item.enumeration = [];
|
|
1332
|
+
var maxValue = -1;
|
|
1333
|
+
item.enumeration.forEach(function (s) { if (s.value > maxValue) maxValue = s.value; });
|
|
1334
|
+
item.enumeration.push(normalizeEnumerationState({ value: maxValue + 1, displayName: "State" + (maxValue + 1) }));
|
|
1335
|
+
syncStateToJson(false);
|
|
1336
|
+
renderDetails();
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1189
1339
|
$(document).on("input", "#opcua-detail-displayname", function () { updateNode(selectedPath, { displayName: $(this).val() }); });
|
|
1190
1340
|
|
|
1191
1341
|
$(document).on("input", "#opcua-detail-name", function () { updateNode(selectedPath, { name: $(this).val() }); });
|
|
@@ -1285,8 +1435,12 @@
|
|
|
1285
1435
|
var nextGroup = String(input.val() || "").trim();
|
|
1286
1436
|
authGroups[index] = nextGroup;
|
|
1287
1437
|
authUsers.forEach(function (user) {
|
|
1288
|
-
if (user.group
|
|
1289
|
-
user.group
|
|
1438
|
+
if (user.group) {
|
|
1439
|
+
var groups = String(user.group).split(",").map(function (g) { return g.trim(); });
|
|
1440
|
+
var updated = groups.map(function (g) {
|
|
1441
|
+
return g === previousGroup ? nextGroup : g;
|
|
1442
|
+
});
|
|
1443
|
+
user.group = updated.join(",");
|
|
1290
1444
|
}
|
|
1291
1445
|
});
|
|
1292
1446
|
input.attr("data-previous", nextGroup);
|
|
@@ -1310,12 +1464,7 @@
|
|
|
1310
1464
|
authUsers[index].passwordHash = "";
|
|
1311
1465
|
syncAuthCredentialFields();
|
|
1312
1466
|
});
|
|
1313
|
-
|
|
1314
|
-
var index = Number($(this).attr("data-index"));
|
|
1315
|
-
authUsers[index].group = $(this).val();
|
|
1316
|
-
syncAuthCredentialFields();
|
|
1317
|
-
|
|
1318
|
-
});
|
|
1467
|
+
// The change handler is now dynamically bound inside renderAuthUsers, so we do not need a global listener for it here.
|
|
1319
1468
|
$(document).on("click", ".opcua-auth-user-remove", function (event) {
|
|
1320
1469
|
event.preventDefault();
|
|
1321
1470
|
removeAuthUser(Number($(this).attr("data-index")));
|
|
@@ -1403,6 +1552,7 @@
|
|
|
1403
1552
|
$("#node-input-add-object").off("click").on("click", function (event) { event.preventDefault(); addItem("objects", "object"); syncStateToJson(true); renderVisualEditor(); });
|
|
1404
1553
|
$("#node-input-add-folder").off("click").on("click", function (event) { event.preventDefault(); addItem("folders", "folder"); syncStateToJson(true); renderVisualEditor(); });
|
|
1405
1554
|
$("#node-input-add-object-type").off("click").on("click", function (event) { event.preventDefault(); addItem("objectsTypes", "objectTypeDefinition"); syncStateToJson(true); renderVisualEditor(); });
|
|
1555
|
+
$("#node-input-add-enumeration").off("click").on("click", function (event) { event.preventDefault(); addItem("enumerations", "enumeration"); syncStateToJson(true); renderVisualEditor(); });
|
|
1406
1556
|
$("#node-input-add-namespace").off("click").on("click", function (event) { event.preventDefault(); addItem("nameSpaces", "namespace"); syncStateToJson(true); renderVisualEditor(); });
|
|
1407
1557
|
$("#node-input-expand-all").off("click").on("click", function (event) {
|
|
1408
1558
|
event.preventDefault();
|