You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/08/16 11:20:38 UTC

[incubator-streampipes] branch STREAMPIPES-577 updated: [STREAMPIPES-577] Show live preview for OPC-UA adapter

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

riemer pushed a commit to branch STREAMPIPES-577
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


The following commit(s) were added to refs/heads/STREAMPIPES-577 by this push:
     new 9b2f7b912 [STREAMPIPES-577] Show live preview for OPC-UA adapter
9b2f7b912 is described below

commit 9b2f7b912de1cb593361030c12da724e79c65f82
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Tue Aug 16 13:20:26 2022 +0200

    [STREAMPIPES-577] Show live preview for OPC-UA adapter
---
 .../connect/iiot/adapters/opcua/OpcUaAdapter.java  | 22 ++++---
 .../iiot/adapters/opcua/OpcUaNodeBrowser.java      | 10 ++++
 .../iiot/adapters/opcua/utils/OpcUaUtil.java       | 50 ++++++++++++++--
 .../streampipes/model/StreamPipesErrorMessage.java | 11 +++-
 .../model/connect/guess/FieldStatus.java           | 31 ++--------
 .../model/connect/guess/FieldStatusInfo.java       | 69 ++++++++++++++++++++++
 .../model/connect/guess/GuessSchema.java           | 30 ++++++++++
 .../model/connect/guess/GuessTypeInfo.java         | 47 ++++++++-------
 .../src/lib/model/gen/streampipes-model.ts         | 48 +++++++++++++--
 .../event-property-row.component.html              | 27 ++++++---
 .../event-property-row.component.scss              | 25 ++++++++
 .../event-property-row.component.ts                | 35 ++++++++---
 .../event-schema/event-schema.component.html       |  8 ++-
 .../event-schema/event-schema.component.ts         | 10 +++-
 14 files changed, 337 insertions(+), 86 deletions(-)

diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
index 76b3df7e2..9b00f84d5 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
@@ -31,6 +31,7 @@ import org.apache.streampipes.container.api.SupportsRuntimeConfig;
 import org.apache.streampipes.model.AdapterType;
 import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription;
 import org.apache.streampipes.model.staticproperty.StaticProperty;
 import org.apache.streampipes.sdk.StaticProperties;
 import org.apache.streampipes.sdk.builder.adapter.SpecificDataStreamAdapterBuilder;
@@ -47,14 +48,10 @@ import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
+import java.util.*;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 public class OpcUaAdapter extends PullAdapter implements SupportsRuntimeConfig {
 
@@ -91,11 +88,18 @@ public class OpcUaAdapter extends PullAdapter implements SupportsRuntimeConfig {
     protected void before() throws AdapterException {
 
         this.allNodeIds = new ArrayList<>();
+        List<String> deleteKeys = this.adapterDescription
+          .getSchemaRules()
+          .stream()
+          .filter(rule -> rule instanceof DeleteRuleDescription)
+          .map(rule -> ((DeleteRuleDescription) rule).getRuntimeKey())
+          .collect(Collectors.toList());
+
         try {
             this.spOpcUaClient.connect();
             OpcUaNodeBrowser browserClient =
                     new OpcUaNodeBrowser(this.spOpcUaClient.getClient(), this.spOpcUaClient.getSpOpcConfig());
-            this.allNodes = browserClient.findNodes();
+            this.allNodes = browserClient.findNodes(deleteKeys);
 
 
             for (OpcNode node : this.allNodes) {
@@ -141,8 +145,8 @@ public class OpcUaAdapter extends PullAdapter implements SupportsRuntimeConfig {
 
     @Override
     protected void pullData() {
-        CompletableFuture<List<DataValue>> response =
-                this.spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, this.allNodeIds);
+        var response =
+          this.spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, this.allNodeIds);
         boolean badStatusCodeReceived = false;
         boolean emptyValueReceived = false;
         try {
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java
index 2e8e3dbc5..c1cbc202e 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaNodeBrowser.java
@@ -37,6 +37,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 public class OpcUaNodeBrowser {
@@ -61,6 +62,15 @@ public class OpcUaNodeBrowser {
     return opcNodes;
   }
 
+  public List<OpcNode> findNodes(List<String> runtimeNameFilters) throws UaException {
+    return findNodes()
+      .stream()
+      .filter(node -> runtimeNameFilters
+        .stream()
+        .noneMatch(f -> f.equals(node.getLabel())))
+      .collect(Collectors.toList());
+  }
+
   public List<TreeInputNode> buildNodeTreeFromOrigin() throws UaException, ExecutionException, InterruptedException {
     NodeId origin = spOpcConfig.getOriginNodeId();
 
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
index d9f95872f..766433a24 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
@@ -26,7 +26,9 @@ import org.apache.streampipes.connect.iiot.adapters.opcua.OpcUaNodeBrowser;
 import org.apache.streampipes.connect.iiot.adapters.opcua.SpOpcUaClient;
 import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfigBuilder;
 import org.apache.streampipes.model.connect.adapter.SpecificAdapterStreamDescription;
+import org.apache.streampipes.model.connect.guess.FieldStatusInfo;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.connect.guess.GuessTypeInfo;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.staticproperty.RuntimeResolvableTreeInputStaticProperty;
@@ -34,14 +36,20 @@ import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
 import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
 import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
 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.NodeId;
+import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
 import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
+import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
 
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
 
 /***
  * Collection of several utility functions in context of OPC UA
@@ -73,6 +81,8 @@ public class OpcUaUtil {
     throws AdapterException, ParseException {
     GuessSchema guessSchema = new GuessSchema();
     EventSchema eventSchema = new EventSchema();
+    List<Map<String, GuessTypeInfo>> eventPreview = new ArrayList<>();
+    Map<String, FieldStatusInfo> fieldStatusInfos = new HashMap<>();
     List<EventProperty> allProperties = new ArrayList<>();
 
     SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(adapterStreamDescription));
@@ -97,22 +107,53 @@ public class OpcUaUtil {
               .label(opcNode.getLabel())
               .build());
           }
-
         }
       }
 
-      spOpcUaClient.disconnect();
+      var nodeIds = selectedNodes.stream().map(OpcNode::getNodeId).collect(Collectors.toList());
+      var response = spOpcUaClient.getClient().readValues(0, TimestampsToReturn.Both, nodeIds);
+
+      var returnValues = response.get();
+
+      makeEventPreview(selectedNodes, eventPreview, fieldStatusInfos, returnValues);
+
 
     } catch (Exception e) {
-      throw new AdapterException("Could not guess schema for opc node:  " + e.getMessage(), e.getCause());
+      throw new AdapterException("Could not guess schema for opc node:  " + e.getMessage(), e);
+    } finally {
+      spOpcUaClient.disconnect();
     }
 
     eventSchema.setEventProperties(allProperties);
     guessSchema.setEventSchema(eventSchema);
+    guessSchema.setEventPreview(eventPreview);
+    guessSchema.setFieldStatusInfo(fieldStatusInfos);
 
     return guessSchema;
   }
 
+  private static void makeEventPreview(List<OpcNode> selectedNodes,
+                                       List<Map<String, GuessTypeInfo>> eventPreview,
+                                       Map<String, FieldStatusInfo> fieldStatusInfos,
+                                       List<DataValue> dataValues) {
+    var singlePreview = new HashMap<String, GuessTypeInfo>();
+
+    for (int i = 0; i < dataValues.size(); i++) {
+      var dv = dataValues.get(i);
+      String label = selectedNodes.get(i).getLabel();
+      if (StatusCode.GOOD.equals(dv.getStatusCode())) {
+        var value = dv.getValue().getValue();
+        singlePreview.put(label, new GuessTypeInfo(value.getClass().getCanonicalName(), value));
+        fieldStatusInfos.put(label, FieldStatusInfo.good());
+      } else {
+        String additionalInfo = dv.getStatusCode() != null ? dv.getStatusCode().toString() : "Status code is null";
+        fieldStatusInfos.put(label, FieldStatusInfo.bad(additionalInfo, false));
+      }
+    }
+
+    eventPreview.add(singlePreview);
+  }
+
 
   /***
    * OPC UA specific implementation of {@link
@@ -142,13 +183,14 @@ public class OpcUaUtil {
       OpcUaNodeBrowser nodeBrowser =
         new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig());
       config.setNodes(nodeBrowser.buildNodeTreeFromOrigin());
-      spOpcUaClient.disconnect();
 
       return config;
     } catch (UaException e) {
       throw new SpConfigurationException(ExceptionMessageExtractor.getDescription(e), e);
     } catch (ExecutionException | InterruptedException | URISyntaxException e) {
       throw new SpConfigurationException("Could not connect to the OPC UA server with the provided settings", e);
+    } finally {
+      spOpcUaClient.disconnect();
     }
   }
 
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
index d2d964090..c6bf711a6 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
@@ -31,9 +31,6 @@ public class StreamPipesErrorMessage {
   private String cause;
   private String fullStackTrace;
 
-  public StreamPipesErrorMessage() {
-  }
-
   public static StreamPipesErrorMessage from(Exception exception) {
     String cause = exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage();
     return new StreamPipesErrorMessage(
@@ -44,6 +41,14 @@ public class StreamPipesErrorMessage {
       cause);
   }
 
+  public StreamPipesErrorMessage(String level,
+                                 String title,
+                                 String detail) {
+    this.level = level;
+    this.title = title;
+    this.detail = detail;
+  }
+
   public StreamPipesErrorMessage(String level,
                                  String title,
                                  String detail,
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java
similarity index 56%
copy from ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
copy to streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java
index aa6f60f17..eec688b79 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatus.java
@@ -16,31 +16,10 @@
  *
  */
 
+package org.apache.streampipes.model.connect.guess;
 
-::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background {
-    background-color: var(--color-accent) !important;
+public enum FieldStatus {
+  GOOD,
+  BAD,
+  ATTENTION
 }
-
-::ng-deep .mat-checkbox:not(.mat-checkbox-disabled).mat-accent .mat-checkbox-ripple .mat-ripple-element {
-    background-color: var(--color-accent) !important;
-}
-
-.checkbox-selected {
-    opacity: 1 !important;
-}
-
-.timestamp-property {
-    margin-left: 15px;
-    border-radius: 10px;
-    background: var(--color-processor);
-    padding: 0px 10px;
-    font-size: 12px;
-    color: #FFFFFF;
-}
-
-.timestamp-icon {
-    font-size: 12px;
-}
-
-
-
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java
new file mode 100644
index 000000000..a66b83ddb
--- /dev/null
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/FieldStatusInfo.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.streampipes.model.connect.guess;
+
+public class FieldStatusInfo {
+
+  private FieldStatus fieldStatus;
+  private String additionalInfo;
+  private boolean changesRequired;
+
+  public static FieldStatusInfo good() {
+    var info = new FieldStatusInfo();
+    info.setFieldStatus(FieldStatus.GOOD);
+    return info;
+  }
+
+  public static FieldStatusInfo bad(String additionalInfo,
+                                    boolean changesRequired) {
+    var info = new FieldStatusInfo();
+    info.setFieldStatus(FieldStatus.BAD);
+    info.setAdditionalInfo(additionalInfo);
+    info.setChangesRequired(changesRequired);
+
+    return info;
+  }
+
+  public FieldStatusInfo() {
+  }
+
+  public FieldStatus getFieldStatus() {
+    return fieldStatus;
+  }
+
+  public void setFieldStatus(FieldStatus fieldStatus) {
+    this.fieldStatus = fieldStatus;
+  }
+
+  public String getAdditionalInfo() {
+    return additionalInfo;
+  }
+
+  public void setAdditionalInfo(String additionalInfo) {
+    this.additionalInfo = additionalInfo;
+  }
+
+  public boolean isChangesRequired() {
+    return changesRequired;
+  }
+
+  public void setChangesRequired(boolean changesRequired) {
+    this.changesRequired = changesRequired;
+  }
+}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java
index 4bda9da85..ba39f8925 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessSchema.java
@@ -22,18 +22,31 @@ import org.apache.streampipes.model.base.UnnamedStreamPipesEntity;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 @TsModel
 public class GuessSchema extends UnnamedStreamPipesEntity {
 
     public EventSchema eventSchema;
 
+    public List<Map<String, GuessTypeInfo>> eventPreview;
+
+    public Map<String, FieldStatusInfo> fieldStatusInfo;
+
     public GuessSchema() {
         super();
+        this.eventPreview = new ArrayList<>();
+        this.fieldStatusInfo = new HashMap<>();
     }
 
     public GuessSchema(GuessSchema other) {
         super(other);
         this.eventSchema = other.getEventSchema() != null ? new EventSchema(other.getEventSchema()) : null;
+        this.eventPreview = other.getEventPreview();
+        this.fieldStatusInfo = other.getFieldStatusInfo();
     }
     public EventSchema getEventSchema() {
         return eventSchema;
@@ -43,4 +56,21 @@ public class GuessSchema extends UnnamedStreamPipesEntity {
         this.eventSchema = eventSchema;
     }
 
+    public List<Map<String, GuessTypeInfo>> getEventPreview() {
+        return eventPreview;
+    }
+
+    public void setEventPreview(List<Map<String, GuessTypeInfo>> eventPreview) {
+        this.eventPreview = eventPreview;
+    }
+
+    public Map<String, FieldStatusInfo> getFieldStatusInfo() {
+        return fieldStatusInfo;
+    }
+
+    public void setFieldStatusInfo(Map<String, FieldStatusInfo> fieldStatusInfo) {
+        this.fieldStatusInfo = fieldStatusInfo;
+    }
+
+
 }
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java
similarity index 56%
copy from ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
copy to streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java
index aa6f60f17..7404451d6 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/GuessTypeInfo.java
@@ -16,31 +16,38 @@
  *
  */
 
+package org.apache.streampipes.model.connect.guess;
 
-::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background {
-    background-color: var(--color-accent) !important;
-}
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-::ng-deep .mat-checkbox:not(.mat-checkbox-disabled).mat-accent .mat-checkbox-ripple .mat-ripple-element {
-    background-color: var(--color-accent) !important;
-}
+public class GuessTypeInfo {
 
-.checkbox-selected {
-    opacity: 1 !important;
-}
+  private String type;
 
-.timestamp-property {
-    margin-left: 15px;
-    border-radius: 10px;
-    background: var(--color-processor);
-    padding: 0px 10px;
-    font-size: 12px;
-    color: #FFFFFF;
-}
+  @JsonTypeInfo(use = JsonTypeInfo.Id.NONE, property = "type")
+  private Object value;
 
-.timestamp-icon {
-    font-size: 12px;
-}
+  public GuessTypeInfo() {
+  }
+
+  public GuessTypeInfo(String type, Object value) {
+    this.type = type;
+    this.value = value;
+  }
 
+  public String getType() {
+    return type;
+  }
 
+  public void setType(String type) {
+    this.type = type;
+  }
 
+  public Object getValue() {
+    return value;
+  }
+
+  public void setValue(Object value) {
+    this.value = value;
+  }
+}
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 24ebb69e4..7d282d6de 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -18,7 +18,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2022-08-14 22:39:25.
+// Generated using typescript-generator version 2.27.744 on 2022-08-16 11:39:37.
 
 export class AbstractStreamPipesEntity {
     "@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStre [...]
@@ -192,9 +192,9 @@ export class AdapterDescription extends NamedStreamPipesEntity {
         instance.selectedEndpointUrl = data.selectedEndpointUrl;
         instance.correspondingServiceGroup = data.correspondingServiceGroup;
         instance.correspondingDataStreamElementId = data.correspondingDataStreamElementId;
+        instance.valueRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.valueRules);
         instance.streamRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.streamRules);
         instance.schemaRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.schemaRules);
-        instance.valueRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.valueRules);
         return instance;
     }
 
@@ -1592,6 +1592,23 @@ export class ExportItem {
     }
 }
 
+export class FieldStatusInfo {
+    additionalInfo: string;
+    changesRequired: boolean;
+    fieldStatus: FieldStatus;
+
+    static fromData(data: FieldStatusInfo, target?: FieldStatusInfo): FieldStatusInfo {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new FieldStatusInfo();
+        instance.fieldStatus = data.fieldStatus;
+        instance.additionalInfo = data.additionalInfo;
+        instance.changesRequired = data.changesRequired;
+        return instance;
+    }
+}
+
 export class FileMetadata {
     createdAt: number;
     createdByUser: string;
@@ -1736,8 +1753,8 @@ export class GenericAdapterSetDescription extends AdapterSetDescription implemen
         const instance = target || new GenericAdapterSetDescription();
         super.fromData(data, instance);
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
-        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         return instance;
     }
 }
@@ -1755,15 +1772,17 @@ export class GenericAdapterStreamDescription extends AdapterStreamDescription im
         const instance = target || new GenericAdapterStreamDescription();
         super.fromData(data, instance);
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
-        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+        instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         return instance;
     }
 }
 
 export class GuessSchema extends UnnamedStreamPipesEntity {
     "@class": "org.apache.streampipes.model.connect.guess.GuessSchema";
+    eventPreview: { [index: string]: GuessTypeInfo }[];
     eventSchema: EventSchema;
+    fieldStatusInfo: { [index: string]: FieldStatusInfo };
 
     static fromData(data: GuessSchema, target?: GuessSchema): GuessSchema {
         if (!data) {
@@ -1772,6 +1791,23 @@ export class GuessSchema extends UnnamedStreamPipesEntity {
         const instance = target || new GuessSchema();
         super.fromData(data, instance);
         instance.eventSchema = EventSchema.fromData(data.eventSchema);
+        instance.eventPreview = __getCopyArrayFn(__getCopyObjectFn(GuessTypeInfo.fromData))(data.eventPreview);
+        instance.fieldStatusInfo = __getCopyObjectFn(FieldStatusInfo.fromData)(data.fieldStatusInfo);
+        return instance;
+    }
+}
+
+export class GuessTypeInfo {
+    type: string;
+    value: any;
+
+    static fromData(data: GuessTypeInfo, target?: GuessTypeInfo): GuessTypeInfo {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new GuessTypeInfo();
+        instance.type = data.type;
+        instance.value = data.value;
         return instance;
     }
 }
@@ -2567,8 +2603,8 @@ export class PipelineTemplateDescription extends NamedStreamPipesEntity {
         const instance = target || new PipelineTemplateDescription();
         super.fromData(data, instance);
         instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)(data.boundTo);
-        instance.pipelineTemplateId = data.pipelineTemplateId;
         instance.pipelineTemplateName = data.pipelineTemplateName;
+        instance.pipelineTemplateId = data.pipelineTemplateId;
         instance.pipelineTemplateDescription = data.pipelineTemplateDescription;
         return instance;
     }
@@ -3384,6 +3420,8 @@ export type EventPropertyUnion = EventPropertyList | EventPropertyNested | Event
 
 export type EventStreamQualityDefinitionUnion = Frequency | Latency;
 
+export type FieldStatus = "GOOD" | "BAD" | "ATTENTION";
+
 export type MappingPropertyUnion = MappingPropertyNary | MappingPropertyUnary;
 
 export type MeasurementPropertyUnion = EventPropertyQualityDefinition | EventStreamQualityDefinition;
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html
index 47ac53898..be87eb7e2 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.html
@@ -16,8 +16,8 @@
   ~
   -->
 
-<div fxLayout="row">
-    <div fxFlex="1 1 auto" fxLayout="row" fxLayoutAlign="start center">
+<div fxLayout="row" fxFlex="100" fxLayoutGap="10px">
+    <div fxFlex fxLayout="row" fxLayoutAlign="start center">
         <b>
             {{ label }}
         </b>
@@ -29,8 +29,20 @@
         </div>
         <p style="margin: 0px 10px 10px;" *ngIf="isList">[List]</p>
     </div>
+    <div fxFlex="15" fxLayoutAlign="start center" *ngIf="runtimeType">
+        <span class="runtime-type-info">{{runtimeType}}</span>
+    </div>
+    <div fxFlex="15" fxLayoutAlign="start center">
+        <span *ngIf="showEventPreview">{{eventPreview[0][node.data.runtimeName].value || 'n/a'}}</span>
+    </div>
+    <div fxFlex="15" fxLayoutAlign="start center">
+        <span *ngIf="showFieldStatus"
+              [ngClass]="'status status-' +fieldStatusInfo[node.data.runtimeName].fieldStatus.toLowerCase()"
+        [matTooltip]="fieldStatusInfo[node.data.runtimeName].additionalInfo">{{fieldStatusInfo[node.data.runtimeName].fieldStatus}}</span>
+    </div>
 
-    <div fxFlex="15" *ngIf="isPrimitive" fxLayoutAlign="center center">
+    <div fxLayout="row" fxLayoutAlign="end center">
+    <div fxFlex="15" *ngIf="isPrimitive" fxLayoutAlign="end center">
         <mat-form-field class="small-select" color="accent">
         <mat-select [(ngModel)]="node.data.propertyScope" panelClass="small-select"
                     [attr.data-cy]="'property-scope-' + label">
@@ -41,14 +53,14 @@
         </mat-form-field>
     </div>
 
-    <div fxFlex="0 1 auto" fxLayoutAlign="center center"
+    <div fxLayoutAlign="end center"
          *ngIf="isNested">
         <button [disabled]="!isEditable" color="accent" mat-button (click)=addNestedProperty(node.data)>
             <mat-icon matTooltip="Add a Nested Property">queue</mat-icon>
         </button>
     </div>
-    <div fxFlex="0 1 auto"
-         fxLayoutAlign="center center"
+    <div
+         fxLayoutAlign="end center"
          class="ml-5 mr-5"
          *ngIf="isNested || isPrimitive || isList">
         <button [disabled]="!isEditable" color="accent" mat-button
@@ -57,7 +69,7 @@
             <mat-icon>edit</mat-icon>&nbsp;Edit field
         </button>
     </div>
-    <div fxFlex="0 1 auto" fxLayoutAlign="center center">
+    <div fxLayoutAlign="end center">
         <mat-checkbox
                 *ngIf="isNested || isPrimitive || isList"
                 (click)="selectProperty(node.data.id, undefined)"
@@ -67,4 +79,5 @@
                 [attr.data-cy]="'delete-property-' + label.toLowerCase()">
         </mat-checkbox>
     </div>
+    </div>
 </div>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
index aa6f60f17..c20307e9b 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.scss
@@ -42,5 +42,30 @@
     font-size: 12px;
 }
 
+.status-good {
+    background: #75c575;
+    color: white;
+}
+
+.status-bad {
+    background: #d2a169;
+    color: white;
+}
+
+.status {
+    width: 60px;
+    text-align: center;
+    padding: 5px;
+    border-radius: 3px;
+}
+
+.runtime-type-info {
+    padding: 5px;
+    border-radius: 3px;
+    background: var(--color-bg-3);
+    color: var(--color-default-text);
+    width: 70px;
+    text-align: center;
+}
 
 
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts
index c4fb32923..f2be21368 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-property-row/event-property-row.component.ts
@@ -21,15 +21,18 @@ import { UUID } from 'angular2-uuid';
 import { TreeNode } from '@circlon/angular-tree-component';
 import { MatDialog } from '@angular/material/dialog';
 import {
-    EventProperty,
-    EventPropertyList,
-    EventPropertyNested,
-    EventPropertyPrimitive,
-    EventPropertyUnion,
-    EventSchema
+  EventProperty,
+  EventPropertyList,
+  EventPropertyNested,
+  EventPropertyPrimitive,
+  EventPropertyUnion,
+  EventSchema,
+  FieldStatusInfo,
+
 } from '@streampipes/platform-services';
 import { EditEventPropertyComponent } from '../../../../dialog/edit-event-property/edit-event-property.component';
 import { DialogService, PanelType } from '@streampipes/shared-ui';
+import { GuessTypeInfo } from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
 
 @Component({
   selector: 'event-property-row',
@@ -42,6 +45,8 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
   @Input() isEditable = true;
   @Input() eventSchema: EventSchema = new EventSchema();
   @Input() countSelected: number;
+  @Input() eventPreview: Record<string, GuessTypeInfo>[];
+  @Input() fieldStatusInfo: Record<string, FieldStatusInfo>;
 
   @Output() isEditableChange = new EventEmitter<boolean>();
   @Output() eventSchemaChange = new EventEmitter<EventSchema>();
@@ -53,6 +58,10 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
   isNested = false;
   isList = false;
   timestampProperty = false;
+  showEventPreview = false;
+  showFieldStatus = false;
+
+  runtimeType: string;
 
   constructor(private dialog: MatDialog,
               private dialogService: DialogService) {
@@ -60,12 +69,18 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
   }
 
   ngOnInit() {
+    this.showFieldStatus = this.fieldStatusInfo && this.fieldStatusInfo[this.node.data.runtimeName] !== undefined;
+    this.showEventPreview = this.eventPreview && this.eventPreview.length > 0 && this.eventPreview[0][this.node.data.runtimeName] !== undefined;
     this.label = this.getLabel(this.node.data);
     this.isPrimitive = this.isEventPropertyPrimitive(this.node.data);
     this.isList = this.isEventPropertyList(this.node.data);
     this.isNested = this.isEventPropertyNested(this.node.data);
     this.timestampProperty = this.isTimestampProperty(this.node.data);
 
+    if (this.isPrimitive) {
+      this.runtimeType = this.parseType(this.node.data.runtimeType);
+    }
+
     if (!this.node.data.propertyScope) {
       this.node.data.propertyScope = 'MEASUREMENT_PROPERTY';
     }
@@ -74,6 +89,10 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
   ngOnChanges(changes: SimpleChanges): void {
   }
 
+  private parseType(runtimeType: string) {
+    return runtimeType.split('#')[1].toUpperCase();
+  }
+
   private isEventPropertyPrimitive(instance: EventProperty): boolean {
     return instance instanceof EventPropertyPrimitive;
   }
@@ -122,8 +141,8 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
     });
 
     dialogRef.afterClosed().subscribe(refresh => {
-        this.timestampProperty = this.isTimestampProperty(this.node.data);
-        this.refreshTreeEmitter.emit();
+      this.timestampProperty = this.isTimestampProperty(this.node.data);
+      this.refreshTreeEmitter.emit();
     });
   }
 
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
index 6e85d424f..8344671e5 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
@@ -18,7 +18,7 @@
 
 
 <div fxLayout="row" fxLayoutAlign="center" class="mt-20">
-    <div fxFlex="80" fxLayout="column">
+    <div fxFlex="90" fxLayout="column">
         <div fxLayout="column"
              fxFlex="100"
              fxLayoutAlign="start center"
@@ -73,10 +73,10 @@
 
                 <sp-error-message
                         [errorMessage]="errorMessage"
-                        *ngIf="isError">
+                        *ngIf="isError && !isLoading">
                 </sp-error-message>
 
-                <div *ngIf="!isError && !isLoading"
+                <div *ngIf="!isError && !isLoading && eventSchema"
                      fxLayout="column"
                      fxLayoutAlign="space-evenly stretched"
                      class="drag-drop-tree"
@@ -90,6 +90,8 @@
                                     [node]="node"
                                     [(isEditable)]="isEditable"
                                     [(eventSchema)]="eventSchema"
+                                    [eventPreview]="eventPreview"
+                                    [fieldStatusInfo]="fieldStatusInfo"
                                     (refreshTreeEmitter)="refreshTree()"
                                     [(countSelected)]="countSelected"></event-property-row>
                         </ng-template>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
index 5ca2b4e58..d70a53048 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
@@ -32,7 +32,10 @@ import {
 } from '@streampipes/platform-services';
 import { MatStepper } from '@angular/material/stepper';
 import { UserErrorMessage } from '../../../../../core-model/base/UserErrorMessage';
-import { StreamPipesErrorMessage } from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
+import {
+  FieldStatusInfo, GuessTypeInfo,
+  StreamPipesErrorMessage
+} from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
 
 @Component({
   selector: 'sp-event-schema',
@@ -79,6 +82,9 @@ export class EventSchemaComponent implements OnChanges {
   validEventSchema = false;
   schemaErrorHints: UserErrorMessage[] = [];
 
+  eventPreview: Record<string, GuessTypeInfo>[];
+  fieldStatusInfo: Record<string, FieldStatusInfo>;
+
   options: ITreeOptions = {
     childrenField: 'eventProperties',
     allowDrag: () => {
@@ -99,6 +105,8 @@ export class EventSchemaComponent implements OnChanges {
     this.isLoading = true;
     this.isError = false;
     this.restService.getGuessSchema(this.adapterDescription).subscribe(guessSchema => {
+        this.eventPreview = guessSchema.eventPreview;
+        this.fieldStatusInfo = guessSchema.fieldStatusInfo;
         this.eventSchema = guessSchema.eventSchema;
         this.eventSchema.eventProperties.sort((a, b) => {
           return a.runtimeName < b.runtimeName ? -1 : 1;