This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new 62dadee43d fix: Support abstract data types in OPC-UA adapter (#4178)
62dadee43d is described below
commit 62dadee43d9cb03110aa3ae0bc991c48fe114aa3
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Feb 17 12:41:23 2026 +0100
fix: Support abstract data types in OPC-UA adapter (#4178)
---
.../connectors/opcua/adapter/OpcUaAdapter.java | 2 +-
.../connectors/opcua/adapter/OpcUaNodeBrowser.java | 10 +--
.../opcua/adapter/OpcUaNodeMetadataExtractor.java | 27 ++++++-
.../opcua/adapter/OpcUaSchemaProvider.java | 21 +-----
.../connectors/opcua/model/OpcUaNodeFactory.java | 87 ++++++++++++++++++++--
.../opcua/model/node/ExtensionObjectOpcUaNode.java | 34 +--------
.../connectors/opcua/model/node/OpcUaNode.java | 5 --
.../opcua/model/node/PrimitiveOpcUaNode.java | 22 +-----
.../adapter/OpcUaNodeMetadataExtractorTest.java | 10 +--
.../opcua/opcAdapterConfiguration.smoke.spec.ts | 2 +-
.../adapter-event-preview.component.html | 2 +-
.../adapter-event-preview.component.scss | 3 -
.../adapter-sample-preview.component.html | 20 ++---
.../show-field-status-infos.component.html | 53 +++++--------
.../show-field-status-infos.component.scss | 63 ----------------
.../show-field-status-infos.component.ts | 17 +++--
...ic-runtime-resolvable-tree-input.component.scss | 1 -
.../static-tree-input-node-details.component.html | 9 ++-
.../static-tree-input-node-details.component.ts | 4 +-
19 files changed, 171 insertions(+), 221 deletions(-)
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
index 79a76aee34..c3969a4063 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
@@ -99,7 +99,7 @@ public class OpcUaAdapter implements StreamPipesAdapter,
IPullAdapter, SupportsR
this.connectedClient = clientProvider.getClient(this.opcUaAdapterConfig);
OpcUaNodeBrowser browserClient =
new OpcUaNodeBrowser(this.connectedClient.getClient(),
this.opcUaAdapterConfig);
- this.nodeProvider = browserClient.makeNodeProvider(List.of());
+ this.nodeProvider = browserClient.makeNodeProvider();
this.allNodes = nodeProvider.getNodes();
if (opcUaAdapterConfig.inPullMode()) {
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeBrowser.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeBrowser.java
index df520031e6..63740d924e 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeBrowser.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeBrowser.java
@@ -60,10 +60,10 @@ public class OpcUaNodeBrowser {
this.spOpcConfig = spOpcUaClientConfig;
}
- public OpcUaNodeProvider makeNodeProvider(List<String> runtimeNameFilters)
throws UaException {
+ public OpcUaNodeProvider makeNodeProvider() throws UaException {
var opcNodes = new ArrayList<OpcUaNode>();
for (String selectedNodeName : this.spOpcConfig.getSelectedNodeNames()) {
- opcNodes.add(toOpcNode(selectedNodeName, runtimeNameFilters));
+ opcNodes.add(toOpcNode(selectedNodeName));
}
return new OpcUaNodeProvider(opcNodes);
@@ -79,8 +79,7 @@ public class OpcUaNodeBrowser {
return findChildren(client, currentNodeId);
}
- private OpcUaNode toOpcNode(String nodeName,
- List<String> runtimeNamesToDelete) throws
UaException {
+ private OpcUaNode toOpcNode(String nodeName) throws UaException {
AddressSpace addressSpace = getAddressSpace();
NodeId nodeId;
@@ -109,8 +108,9 @@ public class OpcUaNodeBrowser {
);
if (node instanceof VariableNode) {
+ var dataValue = ((VariableNode) node).getValue();
var nodeInfo = new BasicVariableNodeInfo((VariableNode) node,
spOpcConfig.getNamingStrategy());
- return OpcUaNodeFactory.createOpcUaNode(nodeInfo, runtimeNamesToDelete);
+ return OpcUaNodeFactory.createOpcUaNode(nodeInfo, dataValue);
}
LOG.warn("Node {} not of type VariableNode", node.getDisplayName());
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractor.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractor.java
index bcaf11a476..7ade7783b0 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractor.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractor.java
@@ -25,6 +25,7 @@ import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
+import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import java.util.HashMap;
@@ -57,10 +58,12 @@ public class OpcUaNodeMetadataExtractor {
var dataTypeNode = client.getAddressSpace().getNode(dataTypeNodeId);
var value = client.readValue(0, TimestampsToReturn.Both,
node.getNodeId()).get();
+ extractNodeId((UaVariableNode) node);
extractSourceTime(value);
extractServerTime(value);
extractStatusCode(value);
extractDataType(dataTypeNode);
+ extractDataTypeNodeId(dataTypeNodeId);
} catch (UaException | ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
@@ -69,12 +72,28 @@ public class OpcUaNodeMetadataExtractor {
return metadata;
}
+ public void extractNodeId(UaVariableNode node) {
+ if (node != null && node.getNodeId() != null) {
+ add("Node ID", node.getNodeId().toParseableString());
+ } else {
+ add("Node ID", "N/A");
+ }
+ }
+
+ public void extractDataTypeNodeId(NodeId dataTypeNodeId) {
+ if (dataTypeNodeId != null) {
+ add("Data Type Node ID", dataTypeNodeId.toParseableString());
+ } else {
+ add("Data Type Node ID", "N/A");
+ }
+ }
+
public void extractDescription() {
if (node.getDescription() != null) {
add("Description", node.getDescription().getText());
} else {
- add("Description", "");
+ add("Description", "N/A");
}
}
@@ -82,7 +101,7 @@ public class OpcUaNodeMetadataExtractor {
if (node.getNodeId() != null) {
add("NamespaceIndex", node.getNodeId().getNamespaceIndex().toString());
} else {
- add("NamespaceIndex", "");
+ add("NamespaceIndex", "N/A");
}
}
@@ -98,7 +117,7 @@ public class OpcUaNodeMetadataExtractor {
if (node.getBrowseName() != null) {
add("BrowseName", node.getBrowseName().getName());
} else {
- add("BrowseName", "");
+ add("BrowseName", "N/A");
}
}
@@ -106,7 +125,7 @@ public class OpcUaNodeMetadataExtractor {
if (node.getDisplayName() != null) {
add("DisplayName", node.getDisplayName().getText());
} else {
- add("DisplayName", "");
+ add("DisplayName", "N/A");
}
}
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaSchemaProvider.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaSchemaProvider.java
index 049951e4ab..57a245eca7 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaSchemaProvider.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaSchemaProvider.java
@@ -27,9 +27,6 @@ import
org.apache.streampipes.extensions.connectors.opcua.config.SpOpcUaConfigEx
import org.apache.streampipes.extensions.connectors.opcua.model.node.OpcUaNode;
import org.apache.streampipes.model.connect.guess.FieldStatusInfo;
import org.apache.streampipes.model.connect.guess.SampleData;
-import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.model.schema.EventSchema;
-import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
import org.apache.streampipes.sdk.builder.adapter.SampleDataBuilder;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
@@ -37,7 +34,6 @@ import
org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,11 +52,8 @@ public class OpcUaSchemaProvider {
IAdapterParameterExtractor extractor,
IStreamPipesClient streamPipesClient)
throws AdapterException, ParseException {
- var builder = GuessSchemaBuilder.create();
- EventSchema eventSchema = new EventSchema();
Map<String, Object> eventPreview = new HashMap<>();
Map<String, FieldStatusInfo> fieldStatusInfos = new HashMap<>();
- List<EventProperty> allProperties = new ArrayList<>();
var opcUaConfig = SpOpcUaConfigExtractor.extractAdapterConfig(
extractor.getStaticPropertyExtractor(),
@@ -70,15 +63,9 @@ public class OpcUaSchemaProvider {
var connectedClient = clientProvider.getClient(opcUaConfig);
OpcUaNodeBrowser nodeBrowser =
new OpcUaNodeBrowser(connectedClient.getClient(), opcUaConfig);
- var nodeProvider = nodeBrowser.makeNodeProvider(List.of());
+ var nodeProvider = nodeBrowser.makeNodeProvider();
var selectedNodes = nodeProvider.getNodes();
- if (!selectedNodes.isEmpty()) {
- for (OpcUaNode opcNode : selectedNodes) {
- opcNode.addToSchema(connectedClient.getClient(), allProperties);
- }
- }
-
var nodeIds = selectedNodes.stream()
.map(node -> node.nodeInfo().getNodeId())
.collect(Collectors.toList());
@@ -96,12 +83,10 @@ public class OpcUaSchemaProvider {
clientProvider.releaseClient(opcUaConfig);
}
- var sampleData = SampleDataBuilder.create()
+ return SampleDataBuilder.create()
.sample(eventPreview)
+ .fieldStatusInfos(fieldStatusInfos)
.build();
-
-
- return sampleData;
}
private static void makeEventPreview(
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/OpcUaNodeFactory.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/OpcUaNodeFactory.java
index 812aa66b7e..eef29fcd05 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/OpcUaNodeFactory.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/OpcUaNodeFactory.java
@@ -22,18 +22,89 @@ import
org.apache.streampipes.extensions.connectors.opcua.model.node.BasicVariab
import
org.apache.streampipes.extensions.connectors.opcua.model.node.ExtensionObjectOpcUaNode;
import org.apache.streampipes.extensions.connectors.opcua.model.node.OpcUaNode;
import
org.apache.streampipes.extensions.connectors.opcua.model.node.PrimitiveOpcUaNode;
-import org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaTypes;
-import java.util.List;
+import org.eclipse.milo.opcua.stack.core.BuiltinDataType;
+import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
+import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
+import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
+import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
+
+import java.lang.reflect.Array;
+import java.util.Objects;
public class OpcUaNodeFactory {
- public static OpcUaNode createOpcUaNode(BasicVariableNodeInfo nodeInfo,
- List<String> runtimeNamesToDelete) {
- if (OpcUaTypes.isExtensionOrCustom(nodeInfo.getNode())) {
- return new ExtensionObjectOpcUaNode(nodeInfo, runtimeNamesToDelete);
- } else {
- return new PrimitiveOpcUaNode(nodeInfo, runtimeNamesToDelete);
+ public static OpcUaNode createOpcUaNode(
+ BasicVariableNodeInfo nodeInfo,
+ DataValue dataValue
+ ) {
+ var hasVariant = hasVariant(dataValue);
+ if (hasVariant) {
+ var byValue = isExtensionByValue(dataValue);
+ return byValue
+ ? new ExtensionObjectOpcUaNode(nodeInfo)
+ : new PrimitiveOpcUaNode(nodeInfo);
+ }
+
+ return isExtensionByDataType(nodeInfo)
+ ? new ExtensionObjectOpcUaNode(nodeInfo)
+ : new PrimitiveOpcUaNode(nodeInfo);
+ }
+
+ private static boolean hasVariant(DataValue dataValue) {
+ if (dataValue == null) {
+ return false;
}
+
+ StatusCode sc = dataValue.getStatusCode();
+ if (sc == null || !sc.isGood()) {
+ return false;
+ }
+
+ return dataValue.getValue() != null;
+ }
+
+ /**
+ * @return TRUE -> value is (or contains) ExtensionObject
+ * FALSE -> value is present and not ExtensionObject
+ */
+ private static boolean isExtensionByValue(DataValue dv) {
+ Object v = dv.getValue().getValue();
+ if (v == null) {
+ return false;
+ }
+
+ if (v instanceof ExtensionObject) {
+ return true;
+ }
+
+ // Handle arrays of any kind (Object[] or primitive arrays)
+ Class<?> c = v.getClass();
+ if (c.isArray()) {
+ int len = Array.getLength(v);
+ for (int i = 0; i < len; i++) {
+ Object el = Array.get(v, i);
+ if (el instanceof ExtensionObject) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ * Conservative fallback based on declared DataType only.
+ * Treat only ExtensionObject itself as "extension" here.
+ *
+ * Why so conservative? Because abstract standard types like Integer/Number
+ * are NOT builtins but are still "primitive-ish" and should not be treated
+ * as custom/extension.
+ */
+ private static boolean isExtensionByDataType(BasicVariableNodeInfo nodeInfo)
{
+ NodeId dt = nodeInfo.getNode().getDataType();
+ return Objects.equals(dt, BuiltinDataType.ExtensionObject.getNodeId());
}
}
+
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/ExtensionObjectOpcUaNode.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/ExtensionObjectOpcUaNode.java
index b16cb4f434..0e8c428b09 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/ExtensionObjectOpcUaNode.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/ExtensionObjectOpcUaNode.java
@@ -19,29 +19,22 @@
package org.apache.streampipes.extensions.connectors.opcua.model.node;
import org.apache.streampipes.commons.exceptions.SpRuntimeException;
-import org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaTypes;
import org.apache.streampipes.model.connect.guess.FieldStatus;
import org.apache.streampipes.model.connect.guess.FieldStatusInfo;
-import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
import org.eclipse.milo.opcua.binaryschema.Struct;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
-import java.util.List;
import java.util.Map;
public class ExtensionObjectOpcUaNode implements OpcUaNode {
private final BasicVariableNodeInfo nodeInfo;
- private final List<String> runtimeNamesToDelete;
- public ExtensionObjectOpcUaNode(BasicVariableNodeInfo nodeInfo,
- List<String> runtimeNamesToDelete) {
+ public ExtensionObjectOpcUaNode(BasicVariableNodeInfo nodeInfo) {
this.nodeInfo = nodeInfo;
- this.runtimeNamesToDelete = runtimeNamesToDelete;
}
@Override
@@ -52,26 +45,7 @@ public class ExtensionObjectOpcUaNode implements OpcUaNode {
@Override
public int getNumberOfEventProperties(OpcUaClient client) {
var struct = extractStruct(client,
nodeInfo.getNode().getValue().getValue());
- return (int) struct.getMembers().entrySet().stream()
- .filter(entry -> {
- var nodeName = nodeInfo.getDesiredName(entry.getKey());
- return !runtimeNamesToDelete.contains(nodeName);
- })
- .count();
- }
-
- @Override
- public void addToSchema(OpcUaClient client,
- List<EventProperty> eventProperties) {
- var struct = extractStruct(client,
nodeInfo.getNode().getValue().getValue());
- struct.getMembers().forEach((key, member) -> {
- var nodeName = nodeInfo.getDesiredName(key);
- eventProperties.add(
-
PrimitivePropertyBuilder.create(OpcUaTypes.getTypeFromValue(member.getValue()),
nodeName)
- .label(nodeName)
- .build()
- );
- });
+ return struct.getMembers().size();
}
@Override
@@ -82,9 +56,7 @@ public class ExtensionObjectOpcUaNode implements OpcUaNode {
struct.getMembers().forEach((key, member) -> {
var nodeName = nodeInfo.getDesiredName(key);
- if (!runtimeNamesToDelete.contains(nodeName)) {
- event.put(nodeName, member.getValue());
- }
+ event.put(nodeName, member.getValue());
});
}
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/OpcUaNode.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/OpcUaNode.java
index 6e2963904c..83b2073ed1 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/OpcUaNode.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/OpcUaNode.java
@@ -19,12 +19,10 @@
package org.apache.streampipes.extensions.connectors.opcua.model.node;
import org.apache.streampipes.model.connect.guess.FieldStatusInfo;
-import org.apache.streampipes.model.schema.EventProperty;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
-import java.util.List;
import java.util.Map;
public interface OpcUaNode {
@@ -33,9 +31,6 @@ public interface OpcUaNode {
int getNumberOfEventProperties(OpcUaClient client);
- void addToSchema(OpcUaClient client,
- List<EventProperty> eventProperties);
-
void addToEvent(OpcUaClient client,
Map<String, Object> event,
Variant variant);
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/PrimitiveOpcUaNode.java
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/PrimitiveOpcUaNode.java
index a05ab85185..ab86d8bd37 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/PrimitiveOpcUaNode.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/model/node/PrimitiveOpcUaNode.java
@@ -21,8 +21,6 @@ package
org.apache.streampipes.extensions.connectors.opcua.model.node;
import org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaTypes;
import org.apache.streampipes.model.connect.guess.FieldStatus;
import org.apache.streampipes.model.connect.guess.FieldStatusInfo;
-import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
import org.apache.streampipes.sdk.utils.Datatypes;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
@@ -32,18 +30,14 @@ import
org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import java.util.Base64;
-import java.util.List;
import java.util.Map;
public class PrimitiveOpcUaNode implements OpcUaNode {
private final BasicVariableNodeInfo nodeInfo;
- private final List<String> runtimeNamesToDelete;
- public PrimitiveOpcUaNode(BasicVariableNodeInfo nodeInfo,
- List<String> runtimeNamesToDelete) {
+ public PrimitiveOpcUaNode(BasicVariableNodeInfo nodeInfo) {
this.nodeInfo = nodeInfo;
- this.runtimeNamesToDelete = runtimeNamesToDelete;
}
@Override
@@ -56,24 +50,12 @@ public class PrimitiveOpcUaNode implements OpcUaNode {
return 1;
}
- @Override
- public void addToSchema(OpcUaClient client,
- List<EventProperty> eventProperties) {
- var nodeName = nodeInfo().getBaseNodeName();
- eventProperties.add(PrimitivePropertyBuilder
- .create(getType(), nodeName)
- .label(nodeName)
- .build());
- }
-
@Override
public void addToEvent(OpcUaClient client,
Map<String, Object> event,
Variant variant) {
var nodeName = nodeInfo.getDesiredName("");
- if (!runtimeNamesToDelete.contains(nodeName)) {
- event.put(nodeName, extractValue(variant));
- }
+ event.put(nodeName, extractValue(variant));
}
@Override
diff --git
a/streampipes-extensions/streampipes-connectors-opcua/src/test/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractorTest.java
b/streampipes-extensions/streampipes-connectors-opcua/src/test/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractorTest.java
index 4a5360563f..a928800251 100644
---
a/streampipes-extensions/streampipes-connectors-opcua/src/test/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractorTest.java
+++
b/streampipes-extensions/streampipes-connectors-opcua/src/test/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaNodeMetadataExtractorTest.java
@@ -60,7 +60,7 @@ public class OpcUaNodeMetadataExtractorTest {
var metadata = extractor.getMetadata();
assertTrue(metadata.containsKey("Description"));
- assertEquals("", metadata.get("Description"));
+ assertEquals("N/A", metadata.get("Description"));
}
@Test
@@ -86,7 +86,7 @@ public class OpcUaNodeMetadataExtractorTest {
var metadata = extractor.getMetadata();
assertTrue(metadata.containsKey("NamespaceIndex"));
- assertEquals("", metadata.get("NamespaceIndex"));
+ assertEquals("N/A", metadata.get("NamespaceIndex"));
}
@Test
@@ -139,7 +139,7 @@ public class OpcUaNodeMetadataExtractorTest {
var metadata = extractor.getMetadata();
assertTrue(metadata.containsKey("BrowseName"));
- assertEquals("", metadata.get("BrowseName"));
+ assertEquals("N/A", metadata.get("BrowseName"));
}
@Test
@@ -166,7 +166,7 @@ public class OpcUaNodeMetadataExtractorTest {
var metadata = extractor.getMetadata();
assertTrue(metadata.containsKey("DisplayName"));
- assertEquals("", metadata.get("DisplayName"));
+ assertEquals("N/A", metadata.get("DisplayName"));
}
@Test
@@ -255,4 +255,4 @@ public class OpcUaNodeMetadataExtractorTest {
private OpcUaNodeMetadataExtractor getExtractor() {
return new OpcUaNodeMetadataExtractor(null, null);
}
-}
\ No newline at end of file
+}
diff --git
a/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.smoke.spec.ts
b/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.smoke.spec.ts
index a77ccdec45..d7ce37e1ba 100644
--- a/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.smoke.spec.ts
+++ b/ui/cypress/tests/connect/opcua/opcAdapterConfiguration.smoke.spec.ts
@@ -62,7 +62,7 @@ describe('Test OPC-UA Adapter Configuration', () => {
TreeStaticPropertyUtils.validateAmountOfShownNodeDetailsMetaDataRows(0);
TreeStaticPropertyUtils.showNodeDetails('StepUp');
TreeStaticPropertyUtils.validateAmountOfShownNodeDetailsMetaDataRows(
- 10,
+ 12,
);
TreeStaticPropertyUtils.hideNodeDetails('StepUp');
TreeStaticPropertyUtils.validateAmountOfShownNodeDetailsMetaDataRows(0);
diff --git
a/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.html
b/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.html
index 18570f8d16..dc5ea2ad86 100644
---
a/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.html
+++
b/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.html
@@ -16,7 +16,7 @@
~
-->
-<section class="jv">
+<section class="jv p-sm">
<div class="jv__content" [class.is-empty]="!hasValue()">
@if (hasValue()) {
<ng-container [ngSwitch]="mode">
diff --git
a/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.scss
b/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.scss
index 8fb07d9f1a..4c290eba6b 100644
---
a/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.scss
+++
b/ui/src/app/connect/components/adapter-configuration/adapter-event-preview/adapter-event-preview.component.scss
@@ -25,13 +25,11 @@
}
.jv__content {
- padding: 10px 12px 14px 12px;
background: var(--color-bg-0);
}
.raw {
margin: 0;
- padding: 12px;
background: var(--color-bg-0);
color: var(--text);
overflow: auto;
@@ -45,7 +43,6 @@
.tree {
background: var(--color-bg-0);
- padding: 10px;
max-height: 520px;
overflow: auto;
}
diff --git
a/ui/src/app/connect/components/adapter-configuration/configure-schema/sample-preview/adapter-sample-preview.component.html
b/ui/src/app/connect/components/adapter-configuration/configure-schema/sample-preview/adapter-sample-preview.component.html
index d84955832c..e3945675cb 100644
---
a/ui/src/app/connect/components/adapter-configuration/configure-schema/sample-preview/adapter-sample-preview.component.html
+++
b/ui/src/app/connect/components/adapter-configuration/configure-schema/sample-preview/adapter-sample-preview.component.html
@@ -18,7 +18,7 @@
<sp-basic-inner-panel
innerPadding="0"
[showTitle]="true"
- [panelTitle]="'Original (Parsed)' | translate"
+ [panelTitle]="'Source' | translate"
>
<div header fxLayoutAlign="end center" fxFlex="100">
<button
@@ -69,14 +69,16 @@
[showDetails]="true"
></sp-exception-message>
} @else {
- <sp-show-field-status-infos
- [fieldStatusInfos]="fieldStatusInfos()"
- ></sp-show-field-status-infos>
- <sp-adapter-event-preview
- dataCy="configure-schema-event-preview-original"
- [mode]="sourceViewMode()"
- [value]="input()"
- ></sp-adapter-event-preview>
+ <div fxLayout="column" class="w-100 p-sm">
+ <sp-show-field-status-infos
+ [fieldStatusInfos]="fieldStatusInfos()"
+ ></sp-show-field-status-infos>
+ <sp-adapter-event-preview
+ dataCy="configure-schema-event-preview-original"
+ [mode]="sourceViewMode()"
+ [value]="input()"
+ ></sp-adapter-event-preview>
+ </div>
}
}
</sp-basic-inner-panel>
diff --git
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.html
b/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.html
index 9e9e2682df..acb2a3f389 100644
---
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.html
+++
b/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.html
@@ -17,42 +17,29 @@
-->
<div fxFlex="100" fxLayout="column">
@if (hasBadFieldStatusInfos()) {
- <div class="fs-alert fs-alert-header">
- <div class="fs-alert-icon">
- <mat-icon>error</mat-icon>
- </div>
- <div class="fs-alert-content" fxLayout="column" fxFlex="100">
- <div class="fs-alert-title">
- Problems reading the following nodes
- </div>
- <div class="fs-alert-description">
- Please change the adapter configuration to fix them.
- </div>
- </div>
- </div>
- <div fxFlex="100" fxLayout="column" fxLayoutGap="8px">
- @for (entry of badFieldStatusInfos(); track entry[0]) {
- @let runtimeName = entry[0];
- @let info = entry[1];
-
- <div class="fs-alert">
- <div
- class="fs-alert-content"
- fxLayout="column"
- fxFlex="100"
- >
- <div class="fs-alert-title">{{ runtimeName }}</div>
+ <sp-alert-banner
+ type="warning"
+ [title]="'Problems reading the following nodes' | translate"
+ [description]="
+ 'Please change the adapter configuration to fix them.'
+ | translate
+ "
+ >
+ <div class="mt-md">
+ @for (entry of badFieldStatusInfos(); track entry[0]) {
+ @let runtimeName = entry[0];
+ @let info = entry[1];
+ <div fxLayout="column">
+ <div class="font-bold text-sm">{{ runtimeName }}</div>
@if (info.additionalInfo) {
- <div class="fs-alert-description">
- <span class="fs-additional">{{
- info.additionalInfo
- }}</span>
- </div>
+ <span class="text-sm">{{
+ info.additionalInfo
+ }}</span>
}
</div>
- </div>
- }
- </div>
+ }
+ </div>
+ </sp-alert-banner>
}
</div>
diff --git
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.scss
b/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.scss
deleted file mode 100644
index 392bd952df..0000000000
---
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-.fs-alert {
- padding: 0.75rem;
- border-radius: 0.5rem;
- display: flex;
- align-items: flex-start;
- gap: 0.75rem;
- margin: 0.5rem 0;
- background-color: var(--color-info-bg);
- color: var(--color-info);
-}
-
-.fs-alert-icon {
- flex-shrink: 0;
- width: 1.5rem;
- height: 1.5rem;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.fs-alert-title {
- font-weight: 700;
- font-size: var(--font-size-sm);
- line-height: 1.2;
- word-break: break-word;
-}
-
-.fs-alert-description {
- margin-top: 0.25rem;
- font-size: var(--font-size-sm);
- line-height: 1.4;
- opacity: 0.9;
- display: flex;
- gap: 0.5rem;
- flex-wrap: wrap;
- align-items: center;
-}
-
-.fs-status {
- font-weight: 600;
-}
-
-.fs-additional {
- opacity: 0.9;
-}
diff --git
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.ts
b/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.ts
index f871d4219e..23fae3613f 100644
---
a/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.ts
+++
b/ui/src/app/connect/components/adapter-configuration/configure-schema/show-field-status-infos/show-field-status-infos.component.ts
@@ -18,18 +18,19 @@
import { Component, computed, input } from '@angular/core';
import { FieldStatusInfo } from '@streampipes/platform-services';
-import {
- FlexDirective,
- LayoutDirective,
- LayoutGapDirective,
-} from '@ngbracket/ngx-layout/flex';
-import { MatIcon } from '@angular/material/icon';
+import { FlexDirective, LayoutDirective } from '@ngbracket/ngx-layout/flex';
+import { SpAlertBannerComponent } from '@streampipes/shared-ui';
+import { TranslatePipe } from '@ngx-translate/core';
@Component({
selector: 'sp-show-field-status-infos',
templateUrl: './show-field-status-infos.component.html',
- styleUrl: './show-field-status-infos.component.scss',
- imports: [FlexDirective, LayoutDirective, MatIcon, LayoutGapDirective],
+ imports: [
+ FlexDirective,
+ LayoutDirective,
+ SpAlertBannerComponent,
+ TranslatePipe,
+ ],
})
export class ShowFieldStatusInfosComponent {
fieldStatusInfos = input<{ [index: string]: FieldStatusInfo }>({});
diff --git
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.scss
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.scss
index 2ca1376a8d..460ecc8c94 100644
---
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.scss
+++
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.scss
@@ -69,7 +69,6 @@
.node-metadata {
border-bottom: 1px solid var(--color-bg-3);
color: var(--color-default-text);
- padding: 10px;
}
.node-name {
diff --git
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.html
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.html
index e5e97d892a..debf1a9698 100644
---
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.html
+++
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.html
@@ -20,11 +20,14 @@
</div>
@for (metadata of nodeMetadata | keyvalue; track metadata) {
<div
- class="node-metadata"
+ class="node-metadata p-xs"
fxLayout="row"
+ fxLayoutGap="5px"
[attr.data-cy]="'node-details-metadata-row-' + metadata.key"
>
- <div fxFlex="30">{{ metadata.key }}</div>
- <div fxFlex="70">{{ metadata.value }}</div>
+ <span class="text-sm" style="color: var(--fg-muted)">{{
+ metadata.key
+ }}</span>
+ <span class="text-sm font-emphasized">{{ metadata.value }}</span>
</div>
}
diff --git
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.ts
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.ts
index 5a54071193..398fb874db 100644
---
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.ts
+++
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input-node-details/static-tree-input-node-details.component.ts
@@ -18,12 +18,12 @@
import { Component, Input } from '@angular/core';
import {
- FlexDirective,
LayoutAlignDirective,
LayoutDirective,
} from '@ngbracket/ngx-layout/flex';
import { KeyValuePipe } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
+import { LayoutGapDirective } from '@ngbracket/ngx-layout';
@Component({
selector: 'sp-static-tree-input-node-details',
@@ -32,9 +32,9 @@ import { TranslatePipe } from '@ngx-translate/core';
imports: [
LayoutAlignDirective,
LayoutDirective,
- FlexDirective,
KeyValuePipe,
TranslatePipe,
+ LayoutGapDirective,
],
})
export class StaticTreeInputNodeDetailsComponent {