This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch fix-opcua-abstract-types
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit c46cb7337f76f762b8d8e3b50d796d9e3dbc2739
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Feb 16 16:48:17 2026 +0100

    fix: Support abstract data types in OPC-UA adapter
---
 .../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   | 86 ++++++++++++++++++++--
 .../opcua/model/node/ExtensionObjectOpcUaNode.java | 34 +--------
 .../connectors/opcua/model/node/OpcUaNode.java     |  5 --
 .../opcua/model/node/PrimitiveOpcUaNode.java       | 22 +-----
 .../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 +-
 17 files changed, 165 insertions(+), 214 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..c1432809ce 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 dv = ((VariableNode) node).getValue();
       var nodeInfo = new BasicVariableNodeInfo((VariableNode) node, 
spOpcConfig.getNamingStrategy());
-      return OpcUaNodeFactory.createOpcUaNode(nodeInfo, runtimeNamesToDelete);
+      return OpcUaNodeFactory.createOpcUaNode(nodeInfo, dv);
     }
 
     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..d5f290ae97 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,90 @@ 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 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.List;
+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
+  ) {
+    Boolean byValue = isExtensionByValue(dataValue);
+    if (byValue != null) {
+      return byValue
+          ? new ExtensionObjectOpcUaNode(nodeInfo)
+          : new PrimitiveOpcUaNode(nodeInfo);
     }
+
+    return isExtensionByDataType(nodeInfo)
+        ? new ExtensionObjectOpcUaNode(nodeInfo)
+        : new PrimitiveOpcUaNode(nodeInfo);
+  }
+
+  /**
+   * @return TRUE  -> value is (or contains) ExtensionObject
+   *         FALSE -> value is present and not ExtensionObject
+   *         NULL  -> cannot decide from value (null DataValue, bad 
StatusCode, no Variant, etc.)
+   */
+  public static Boolean isExtensionByValue(DataValue dv) {
+    if (dv == null) {
+      return null;
+    }
+
+    StatusCode sc = dv.getStatusCode();
+    if (sc == null || !sc.isGood()) {
+      return null;
+    }
+
+    if (dv.getValue() == null) {
+      return null;
+    }
+
+    Object v = dv.getValue().getValue();
+    if (v == null) {
+      return Boolean.FALSE;
+    }
+
+    if (v instanceof ExtensionObject) {
+      return Boolean.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); // works for primitive arrays too (boxed)
+        if (el instanceof ExtensionObject) {
+          return Boolean.TRUE;
+        }
+      }
+      return Boolean.FALSE;
+    }
+
+    return Boolean.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/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 {


Reply via email to