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 19:59:27 UTC
[incubator-streampipes] branch STREAMPIPES-577 updated: [STREAMPIPES-577] Add event preview to schema editor
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 c6be99b1e [STREAMPIPES-577] Add event preview to schema editor
c6be99b1e is described below
commit c6be99b1e6bfce65687cdb5c548a60c05fddf69a
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Tue Aug 16 21:58:21 2022 +0200
[STREAMPIPES-577] Add event preview to schema editor
---
.../master/management/GuessManagement.java | 7 +
.../streampipes/connect/adapter/Adapter.java | 112 +--------------
.../connect/adapter/AdapterPipelineGenerator.java | 159 +++++++++++++++++++++
.../pipeline/AdapterEventPreviewPipeline.java | 81 +++++++++++
.../model/connect/guess/AdapterEventPreview.java | 40 ++++--
.../rest/impl/connect/GuessResource.java | 11 ++
.../src/lib/model/gen/streampipes-model.ts | 25 +++-
.../event-property-row.component.html | 117 ++++++++-------
.../event-property-row.component.scss | 61 ++++----
.../event-property-row.component.ts | 24 +++-
.../event-schema-preview.component.html | 24 +++-
.../event-schema-preview.component.scss | 11 ++
.../event-schema-preview.component.ts | 43 +++++-
.../event-schema/event-schema.component.html | 23 +--
.../event-schema/event-schema.component.ts | 36 ++++-
.../schema-editor-header.component.ts | 6 +-
ui/src/app/connect/connect.module.ts | 2 +
.../json-pretty-print.pipe.ts} | 15 ++
ui/src/app/connect/services/rest.service.ts | 18 ++-
19 files changed, 575 insertions(+), 240 deletions(-)
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
index e54ade7a4..ce380864c 100644
--- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
+++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
@@ -26,17 +26,21 @@ import org.apache.http.client.fluent.Response;
import org.apache.http.entity.ContentType;
import org.apache.http.util.EntityUtils;
import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException;
+import org.apache.streampipes.connect.adapter.model.pipeline.AdapterEventPreviewPipeline;
import org.apache.streampipes.connect.api.exception.ParseException;
import org.apache.streampipes.connect.api.exception.WorkerAdapterException;
import org.apache.streampipes.connect.container.master.util.WorkerPaths;
import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.connect.guess.AdapterEventPreview;
import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.connect.guess.GuessTypeInfo;
import org.apache.streampipes.model.message.ErrorMessage;
import org.apache.streampipes.serializers.json.JacksonSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.Map;
public class GuessManagement {
@@ -74,4 +78,7 @@ public class GuessManagement {
}
}
+ public Map<String, GuessTypeInfo> performAdapterEventPreview(AdapterEventPreview previewRequest) {
+ return new AdapterEventPreviewPipeline(previewRequest).makePreview();
+ }
}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java
index 52344b1bc..86fcf9bec 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/Adapter.java
@@ -18,32 +18,18 @@
package org.apache.streampipes.connect.adapter;
-import org.apache.streampipes.config.backend.BackendConfig;
-import org.apache.streampipes.config.backend.SpProtocol;
import org.apache.streampipes.connect.adapter.model.pipeline.AdapterPipeline;
-import org.apache.streampipes.connect.adapter.preprocessing.transform.stream.DuplicateFilterPipelineElement;
-import org.apache.streampipes.connect.api.IAdapterPipelineElement;
-import org.apache.streampipes.connect.adapter.preprocessing.elements.*;
+import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToJmsAdapterSink;
+import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToKafkaAdapterSink;
+import org.apache.streampipes.connect.adapter.preprocessing.elements.SendToMqttAdapterSink;
import org.apache.streampipes.connect.api.IAdapter;
import org.apache.streampipes.model.connect.adapter.AdapterDescription;
-import org.apache.streampipes.model.connect.rules.TransformationRuleDescription;
-import org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription;
-import org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription;
-import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription;
-import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
-import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
import org.apache.streampipes.model.grounding.JmsTransportProtocol;
import org.apache.streampipes.model.grounding.KafkaTransportProtocol;
import org.apache.streampipes.model.grounding.MqttTransportProtocol;
import org.apache.streampipes.model.grounding.TransportProtocol;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.List;
public abstract class Adapter<T extends AdapterDescription> implements IAdapter<T> {
- Logger logger = LoggerFactory.getLogger(Adapter.class);
private boolean debug;
@@ -99,97 +85,7 @@ public abstract class Adapter<T extends AdapterDescription> implements IAdapter<
}
private AdapterPipeline getAdapterPipeline(T adapterDescription) {
-
- List<IAdapterPipelineElement> pipelineElements = new ArrayList<>();
-
- // Must be before the schema transformations to ensure that user can move this event property
- AddTimestampRuleDescription timestampTransformationRuleDescription = getTimestampRule(adapterDescription);
- if (timestampTransformationRuleDescription != null) {
- pipelineElements.add(new AddTimestampPipelineElement(
- timestampTransformationRuleDescription.getRuntimeKey()));
- }
-
- AddValueTransformationRuleDescription valueTransformationRuleDescription = getAddValueRule(adapterDescription);
- if (valueTransformationRuleDescription != null) {
- pipelineElements.add(new AddValuePipelineElement(
- valueTransformationRuleDescription.getRuntimeKey(),
- valueTransformationRuleDescription.getStaticValue()));
- }
-
-
- // first transform schema before transforming vales
- // value rules should use unique keys for of new schema
- pipelineElements.add(new TransformSchemaAdapterPipelineElement(adapterDescription.getSchemaRules()));
- pipelineElements.add(new TransformValueAdapterPipelineElement(adapterDescription.getValueRules()));
-
-
- RemoveDuplicatesTransformationRuleDescription duplicatesTransformationRuleDescription = getRemoveDuplicateRule(adapterDescription);
- if (duplicatesTransformationRuleDescription != null) {
- pipelineElements.add(new DuplicateFilterPipelineElement(duplicatesTransformationRuleDescription.getFilterTimeWindow()));
- }
-
- TransformStreamAdapterElement transformStreamAdapterElement = new TransformStreamAdapterElement();
- EventRateTransformationRuleDescription eventRateTransformationRuleDescription = getEventRateTransformationRule(adapterDescription);
- if (eventRateTransformationRuleDescription != null) {
- transformStreamAdapterElement.addStreamTransformationRuleDescription(eventRateTransformationRuleDescription);
- }
- pipelineElements.add(transformStreamAdapterElement);
-
- // Needed when adapter is (
- if (adapterDescription.getEventGrounding() != null && adapterDescription.getEventGrounding().getTransportProtocol() != null
- && adapterDescription.getEventGrounding().getTransportProtocol().getBrokerHostname() != null) {
- return new AdapterPipeline(pipelineElements, getAdapterSink(adapterDescription));
- }
-
- return new AdapterPipeline(pipelineElements);
- }
-
- private SendToBrokerAdapterSink<?> getAdapterSink(AdapterDescription adapterDescription) {
- SpProtocol prioritizedProtocol =
- BackendConfig.INSTANCE.getMessagingSettings().getPrioritizedProtocols().get(0);
-
- if (GroundingService.isPrioritized(prioritizedProtocol, JmsTransportProtocol.class)) {
- return new SendToJmsAdapterSink(adapterDescription);
- }
- else if (GroundingService.isPrioritized(prioritizedProtocol, KafkaTransportProtocol.class)) {
- return new SendToKafkaAdapterSink(adapterDescription);
- }
- else {
- return new SendToMqttAdapterSink(adapterDescription);
- }
- }
-
- private RemoveDuplicatesTransformationRuleDescription getRemoveDuplicateRule(T adapterDescription) {
- return getRule(adapterDescription, RemoveDuplicatesTransformationRuleDescription.class);
- }
-
- private EventRateTransformationRuleDescription getEventRateTransformationRule(T adapterDescription) {
- return getRule(adapterDescription, EventRateTransformationRuleDescription.class);
- }
-
- private AddTimestampRuleDescription getTimestampRule(T adapterDescription) {
- return getRule(adapterDescription, AddTimestampRuleDescription.class);
- }
-
- private AddValueTransformationRuleDescription getAddValueRule(T adapterDescription) {
- return getRule(adapterDescription, AddValueTransformationRuleDescription.class);
- }
-
- private CorrectionValueTransformationRuleDescription getCorrectionValueRule(T adapterDescription) {
- return getRule(adapterDescription, CorrectionValueTransformationRuleDescription.class);
- }
-
- private <G extends TransformationRuleDescription> G getRule(T adapterDescription, Class<G> type) {
-
- if (adapterDescription != null) {
- for (TransformationRuleDescription tr : adapterDescription.getRules()) {
- if (type.isInstance(tr)) {
- return type.cast(tr);
- }
- }
- }
-
- return null;
+ return new AdapterPipelineGenerator().generatePipeline(adapterDescription);
}
@Override
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java
new file mode 100644
index 000000000..31ce0e9a1
--- /dev/null
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/AdapterPipelineGenerator.java
@@ -0,0 +1,159 @@
+/*
+ * 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.connect.adapter;
+
+import org.apache.streampipes.config.backend.BackendConfig;
+import org.apache.streampipes.config.backend.SpProtocol;
+import org.apache.streampipes.connect.adapter.model.pipeline.AdapterPipeline;
+import org.apache.streampipes.connect.adapter.preprocessing.elements.*;
+import org.apache.streampipes.connect.adapter.preprocessing.transform.stream.DuplicateFilterPipelineElement;
+import org.apache.streampipes.connect.api.IAdapterPipelineElement;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.connect.rules.TransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.schema.SchemaTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.stream.EventRateTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.ValueTransformationRuleDescription;
+import org.apache.streampipes.model.grounding.JmsTransportProtocol;
+import org.apache.streampipes.model.grounding.KafkaTransportProtocol;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AdapterPipelineGenerator {
+
+ // TODO improve this code
+ public AdapterPipeline generatePipeline(AdapterDescription adapterDescription) {
+
+ var pipelineElements = makeAdapterPipelineElements(adapterDescription.getRules());
+
+ RemoveDuplicatesTransformationRuleDescription duplicatesTransformationRuleDescription = getRemoveDuplicateRule(adapterDescription.getRules());
+ if (duplicatesTransformationRuleDescription != null) {
+ pipelineElements.add(new DuplicateFilterPipelineElement(duplicatesTransformationRuleDescription.getFilterTimeWindow()));
+ }
+
+ TransformStreamAdapterElement transformStreamAdapterElement = new TransformStreamAdapterElement();
+ EventRateTransformationRuleDescription eventRateTransformationRuleDescription = getEventRateTransformationRule(adapterDescription.getRules());
+ if (eventRateTransformationRuleDescription != null) {
+ transformStreamAdapterElement.addStreamTransformationRuleDescription(eventRateTransformationRuleDescription);
+ }
+ pipelineElements.add(transformStreamAdapterElement);
+
+ // TODO decide what was meant with this comment
+ // Needed when adapter is (
+ if (adapterDescription.getEventGrounding() != null && adapterDescription.getEventGrounding().getTransportProtocol() != null
+ && adapterDescription.getEventGrounding().getTransportProtocol().getBrokerHostname() != null) {
+ return new AdapterPipeline(pipelineElements, getAdapterSink(adapterDescription));
+ }
+
+ return new AdapterPipeline(pipelineElements);
+ }
+
+ public List<IAdapterPipelineElement> makeAdapterPipelineElements(List<TransformationRuleDescription> rules) {
+ List<IAdapterPipelineElement> pipelineElements = new ArrayList<>();
+
+ // Must be before the schema transformations to ensure that user can move this event property
+ AddTimestampRuleDescription timestampTransformationRuleDescription = getTimestampRule(rules);
+ if (timestampTransformationRuleDescription != null) {
+ pipelineElements.add(new AddTimestampPipelineElement(
+ timestampTransformationRuleDescription.getRuntimeKey()));
+ }
+
+ AddValueTransformationRuleDescription valueTransformationRuleDescription = getAddValueRule(rules);
+ if (valueTransformationRuleDescription != null) {
+ pipelineElements.add(new AddValuePipelineElement(
+ valueTransformationRuleDescription.getRuntimeKey(),
+ valueTransformationRuleDescription.getStaticValue()));
+ }
+
+ // first transform schema before transforming vales
+ // value rules should use unique keys for of new schema
+ pipelineElements.add(new TransformSchemaAdapterPipelineElement(getSchemaRules(rules)));
+ pipelineElements.add(new TransformValueAdapterPipelineElement(getValueRules(rules)));
+
+ return pipelineElements;
+ }
+
+ private SendToBrokerAdapterSink<?> getAdapterSink(AdapterDescription adapterDescription) {
+ SpProtocol prioritizedProtocol =
+ BackendConfig.INSTANCE.getMessagingSettings().getPrioritizedProtocols().get(0);
+
+ if (GroundingService.isPrioritized(prioritizedProtocol, JmsTransportProtocol.class)) {
+ return new SendToJmsAdapterSink(adapterDescription);
+ }
+ else if (GroundingService.isPrioritized(prioritizedProtocol, KafkaTransportProtocol.class)) {
+ return new SendToKafkaAdapterSink(adapterDescription);
+ }
+ else {
+ return new SendToMqttAdapterSink(adapterDescription);
+ }
+ }
+
+ private RemoveDuplicatesTransformationRuleDescription getRemoveDuplicateRule(List<TransformationRuleDescription> rules) {
+ return getRule(rules, RemoveDuplicatesTransformationRuleDescription.class);
+ }
+
+ private EventRateTransformationRuleDescription getEventRateTransformationRule(List<TransformationRuleDescription> rules) {
+ return getRule(rules, EventRateTransformationRuleDescription.class);
+ }
+
+ private AddTimestampRuleDescription getTimestampRule(List<TransformationRuleDescription> rules) {
+ return getRule(rules, AddTimestampRuleDescription.class);
+ }
+
+ private AddValueTransformationRuleDescription getAddValueRule(List<TransformationRuleDescription> rules) {
+ return getRule(rules, AddValueTransformationRuleDescription.class);
+ }
+
+ private CorrectionValueTransformationRuleDescription getCorrectionValueRule(List<TransformationRuleDescription> rules) {
+ return getRule(rules, CorrectionValueTransformationRuleDescription.class);
+ }
+
+ private <G extends TransformationRuleDescription> G getRule(List<TransformationRuleDescription> rules,
+ Class<G> type) {
+
+ if (rules != null) {
+ for (TransformationRuleDescription tr : rules) {
+ if (type.isInstance(tr)) {
+ return type.cast(tr);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private List<TransformationRuleDescription> getValueRules(List<TransformationRuleDescription> rules) {
+ return rules
+ .stream()
+ .filter(r -> r instanceof ValueTransformationRuleDescription && !(r instanceof AddTimestampRuleDescription))
+ .collect(Collectors.toList());
+ }
+
+ private List<TransformationRuleDescription> getSchemaRules(List<TransformationRuleDescription> rules) {
+ return rules
+ .stream()
+ .filter(r -> r instanceof SchemaTransformationRuleDescription)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java
new file mode 100644
index 000000000..3e36ad5b4
--- /dev/null
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/model/pipeline/AdapterEventPreviewPipeline.java
@@ -0,0 +1,81 @@
+/*
+ * 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.connect.adapter.model.pipeline;
+
+import org.apache.streampipes.connect.adapter.AdapterPipelineGenerator;
+import org.apache.streampipes.connect.api.IAdapterPipeline;
+import org.apache.streampipes.connect.api.IAdapterPipelineElement;
+import org.apache.streampipes.model.connect.guess.AdapterEventPreview;
+import org.apache.streampipes.model.connect.guess.GuessTypeInfo;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class AdapterEventPreviewPipeline implements IAdapterPipeline {
+
+ private List<IAdapterPipelineElement> pipelineElements;
+ private Map<String, GuessTypeInfo> event;
+
+ public AdapterEventPreviewPipeline(AdapterEventPreview previewRequest) {
+ this.pipelineElements = new AdapterPipelineGenerator().makeAdapterPipelineElements(previewRequest.getRules());
+ this.event = previewRequest.getInputData();
+ }
+
+ @Override
+ public void process(Map<String, Object> event) {
+ for (IAdapterPipelineElement pe : this.pipelineElements) {
+ event = pe.process(event);
+ }
+ }
+
+ @Override
+ public List<IAdapterPipelineElement> getPipelineElements() {
+ return null;
+ }
+
+ @Override
+ public void setPipelineElements(List<IAdapterPipelineElement> pipelineElements) {
+
+ }
+
+ @Override
+ public void changePipelineSink(IAdapterPipelineElement pipelineSink) {
+
+ }
+
+ @Override
+ public IAdapterPipelineElement getPipelineSink() {
+ return null;
+ }
+
+ public Map<String, GuessTypeInfo> makePreview() {
+ Map<String, Object> ev = this.event
+ .entrySet()
+ .stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue()));
+ this.process(ev);
+
+ return ev
+ .entrySet()
+ .stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, e-> new GuessTypeInfo(e.getValue().getClass().getCanonicalName(), e.getValue())));
+ }
+}
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java
similarity index 51%
copy from ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
copy to streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java
index f80de67d9..d70af4f3f 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/guess/AdapterEventPreview.java
@@ -16,14 +16,34 @@
*
*/
-import { Component, Input } from '@angular/core';
-import { EventSchema } from '@streampipes/platform-services';
-
-@Component({
- selector: 'sp-event-schema-preview',
- templateUrl: './event-schema-preview.component.html',
- styleUrls: ['./event-schema-preview.component.scss']
-})
-export class EventSchemaPreviewComponent {
- @Input() eventSchema: EventSchema;
+package org.apache.streampipes.model.connect.guess;
+
+import org.apache.streampipes.model.connect.rules.TransformationRuleDescription;
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+import java.util.List;
+import java.util.Map;
+
+@TsModel
+public class AdapterEventPreview {
+
+ private List<TransformationRuleDescription> rules;
+
+ private Map<String, GuessTypeInfo> inputData;
+
+ public List<TransformationRuleDescription> getRules() {
+ return rules;
+ }
+
+ public void setRules(List<TransformationRuleDescription> rules) {
+ this.rules = rules;
+ }
+
+ public Map<String, GuessTypeInfo> getInputData() {
+ return inputData;
+ }
+
+ public void setInputData(Map<String, GuessTypeInfo> inputData) {
+ this.inputData = inputData;
+ }
}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
index 7cdd81281..b678b9eab 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
@@ -24,11 +24,13 @@ import org.apache.streampipes.connect.api.exception.WorkerAdapterException;
import org.apache.streampipes.connect.container.master.management.GuessManagement;
import org.apache.streampipes.model.StreamPipesErrorMessage;
import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.connect.guess.AdapterEventPreview;
import org.apache.streampipes.model.connect.guess.GuessSchema;
import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@@ -66,5 +68,14 @@ public class GuessResource extends AbstractAdapterResource<GuessManagement> {
return serverError(StreamPipesErrorMessage.from(e));
}
}
+
+ @POST
+ @JacksonSerialized
+ @Path("/schema/preview")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getAdapterEventPreview(AdapterEventPreview previewRequest) {
+ return ok(managementService.performAdapterEventPreview(previewRequest));
+ }
}
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 7d282d6de..d2712a990 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-16 11:39:37.
+// Generated using typescript-generator version 2.27.744 on 2022-08-16 16:51:03.
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.streamRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.streamRules);
+ instance.valueRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.valueRules);
return instance;
}
@@ -215,6 +215,21 @@ export class AdapterDescription extends NamedStreamPipesEntity {
}
}
+export class AdapterEventPreview {
+ inputData: { [index: string]: GuessTypeInfo };
+ rules: TransformationRuleDescriptionUnion[];
+
+ static fromData(data: AdapterEventPreview, target?: AdapterEventPreview): AdapterEventPreview {
+ if (!data) {
+ return data;
+ }
+ const instance = target || new AdapterEventPreview();
+ instance.rules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.rules);
+ instance.inputData = __getCopyObjectFn(GuessTypeInfo.fromData)(data.inputData);
+ return instance;
+ }
+}
+
export class AdapterSetDescription extends AdapterDescription {
"@class": "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription";
dataSet: SpDataSet;
@@ -1753,8 +1768,8 @@ export class GenericAdapterSetDescription extends AdapterSetDescription implemen
const instance = target || new GenericAdapterSetDescription();
super.fromData(data, instance);
instance.eventSchema = EventSchema.fromData(data.eventSchema);
- instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+ instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
return instance;
}
}
@@ -1772,8 +1787,8 @@ export class GenericAdapterStreamDescription extends AdapterStreamDescription im
const instance = target || new GenericAdapterStreamDescription();
super.fromData(data, instance);
instance.eventSchema = EventSchema.fromData(data.eventSchema);
- instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
instance.formatDescription = FormatDescription.fromData(data.formatDescription);
+ instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
return instance;
}
}
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 be87eb7e2..88a49c3e4 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
@@ -17,67 +17,78 @@
-->
<div fxLayout="row" fxFlex="100" fxLayoutGap="10px">
- <div fxFlex fxLayout="row" fxLayoutAlign="start center">
- <b>
+ <div fxLayout="row" fxLayoutAlign="start center">
+ <div>
+ <b style="white-space: nowrap">
{{ label }}
</b>
- <div class="timestamp-property" *ngIf="timestampProperty" fxLayoutAlign="start center" fxLayout="row">
+ </div>
+ <div fxLayoutAlign="start center" *ngIf="originalRuntimeName" class="ml-5">
+ <span class="runtime-info">{{originalRuntimeName}}</span>
+ <span fxLayoutAlign="center center"
+ *ngIf="originalRuntimeName !== node.data.runtimeName">
+ <i class="material-icons">arrow_right</i>
+ </span>
+ <span class="runtime-info"
+ *ngIf="originalRuntimeName !== node.data.runtimeName">{{node.data.runtimeName}}
+ </span>
+ </div>
+ <p style="margin: 0px 10px 10px;" *ngIf="isList">[List]</p>
+ </div>
+
+ <div fxLayout="row" fxLayoutAlign="end center" fxFlex="100" fxLayoutGap="20px">
+ <div class="timestamp-property" *ngIf="timestampProperty" fxLayoutAlign="end center" fxLayout="row">
<mat-icon *ngIf="timestampProperty" class="timestamp-icon" fxLayout="row" fxLayoutAlign="start center">
access_time
</mat-icon>
<span style="margin-left: -5px;">marked as timestamp</span>
</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">
+ <div fxLayoutAlign="end center" *ngIf="runtimeType" class="runtime-type-info-outer">
+ <span class="runtime-info runtime-type-info">{{originalRuntimeType}}</span>
+ <span fxLayoutAlign="center center"><i class="material-icons">arrow_right</i></span>
+ <span class="runtime-info runtime-type-info">{{runtimeType}}</span>
+ </div>
+ <div fxLayoutAlign="end 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 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">
- <mat-option value="MEASUREMENT_PROPERTY">Measurement</mat-option>
- <mat-option value="DIMENSION_PROPERTY">Dimension</mat-option>
- <mat-option value="HEADER_PROPERTY">Header</mat-option>
- </mat-select>
- </mat-form-field>
- </div>
+ [ngClass]="'status status-' +fieldStatusInfo[originalRuntimeName].fieldStatus.toLowerCase()"
+ [matTooltip]="fieldStatusInfo[originalRuntimeName].additionalInfo">{{fieldStatusInfo[originalRuntimeName].fieldStatus}}</span>
+ </div>
+ <div *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">
+ <mat-option value="MEASUREMENT_PROPERTY">Measurement</mat-option>
+ <mat-option value="DIMENSION_PROPERTY">Dimension</mat-option>
+ <mat-option value="HEADER_PROPERTY">Header</mat-option>
+ </mat-select>
+ </mat-form-field>
+ </div>
- <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
- fxLayoutAlign="end center"
- class="ml-5 mr-5"
- *ngIf="isNested || isPrimitive || isList">
- <button [disabled]="!isEditable" color="accent" mat-button
- (click)="openEditDialog(node.data)"
- [attr.data-cy]="'edit-' + label.toLowerCase()">
- <mat-icon>edit</mat-icon> Edit field
- </button>
- </div>
- <div fxLayoutAlign="end center">
- <mat-checkbox
- *ngIf="isNested || isPrimitive || isList"
- (click)="selectProperty(node.data.id, undefined)"
- [disabled]="!isEditable"
- [class.checkbox-selected]="node.data.selected"
- [checked]="node.data.selected"
- [attr.data-cy]="'delete-property-' + label.toLowerCase()">
- </mat-checkbox>
- </div>
+ <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
+ fxLayoutAlign="end center"
+ class="ml-5 mr-5"
+ *ngIf="isNested || isPrimitive || isList">
+ <button [disabled]="!isEditable" color="accent" mat-button
+ (click)="openEditDialog(node.data)"
+ [attr.data-cy]="'edit-' + label.toLowerCase()">
+ <mat-icon>edit</mat-icon> Edit field
+ </button>
+ </div>
+ <div fxLayoutAlign="end center">
+ <mat-checkbox
+ *ngIf="isNested || isPrimitive || isList"
+ (click)="selectProperty(node.data.id, undefined)"
+ [disabled]="!isEditable"
+ [class.checkbox-selected]="node.data.selected"
+ [checked]="node.data.selected"
+ [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 c20307e9b..9e4191930 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
@@ -18,54 +18,67 @@
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background {
- background-color: var(--color-accent) !important;
+ background-color: var(--color-accent) !important;
}
::ng-deep .mat-checkbox:not(.mat-checkbox-disabled).mat-accent .mat-checkbox-ripple .mat-ripple-element {
- background-color: var(--color-accent) !important;
+ background-color: var(--color-accent) !important;
}
.checkbox-selected {
- opacity: 1 !important;
+ opacity: 1 !important;
}
.timestamp-property {
- margin-left: 15px;
- border-radius: 10px;
- background: var(--color-processor);
- padding: 0px 10px;
- font-size: 12px;
- color: #FFFFFF;
+ margin-left: 15px;
+ border-radius: 10px;
+ background: var(--color-processor);
+ padding: 0px 10px;
+ font-size: 12px;
+ color: #FFFFFF;
}
.timestamp-icon {
- font-size: 12px;
+ font-size: 12px;
}
.status-good {
- background: #75c575;
- color: white;
+ background: #75c575;
+ color: white;
}
.status-bad {
- background: #d2a169;
- color: white;
+ background: #d2a169;
+ color: white;
}
.status {
- width: 60px;
- text-align: center;
- padding: 5px;
- border-radius: 3px;
+ width: 70px;
+ min-width: 70px;
+ text-align: center;
+ padding: 5px;
+ border-radius: 5px;
+}
+
+.runtime-info {
+ border-radius: 5px;
+ color: var(--color-default-text);
+ font-size: 10pt;
+ text-align: center;
}
.runtime-type-info {
- padding: 5px;
- border-radius: 3px;
- background: var(--color-bg-3);
- color: var(--color-default-text);
- width: 70px;
- text-align: center;
+ border-radius: 5px;
+ color: var(--color-default-text);
+ width: 60px;
+ font-size: 10pt;
+ text-align: center;
+}
+
+.runtime-type-info-outer {
+ padding: 3px;
+ border-radius: 5px;
+ background: var(--color-bg-3);
}
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 f2be21368..393066c93 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
@@ -28,28 +28,30 @@ import {
EventPropertyUnion,
EventSchema,
FieldStatusInfo,
+ GuessTypeInfo
} 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',
templateUrl: './event-property-row.component.html',
styleUrls: ['./event-property-row.component.scss']
})
-export class EventPropertyRowComponent implements OnInit, OnChanges {
+export class EventPropertyRowComponent implements OnInit {
@Input() node: TreeNode;
@Input() isEditable = true;
@Input() eventSchema: EventSchema = new EventSchema();
+ @Input() originalEventSchema: EventSchema;
@Input() countSelected: number;
@Input() eventPreview: Record<string, GuessTypeInfo>[];
@Input() fieldStatusInfo: Record<string, FieldStatusInfo>;
@Output() isEditableChange = new EventEmitter<boolean>();
@Output() eventSchemaChange = new EventEmitter<EventSchema>();
+ @Output() originalEventSchemaChange = new EventEmitter<EventSchema>();
@Output() refreshTreeEmitter = new EventEmitter<void>();
@Output() countSelectedChange = new EventEmitter<number>();
@@ -62,6 +64,8 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
showFieldStatus = false;
runtimeType: string;
+ originalRuntimeType: string;
+ originalRuntimeName: string;
constructor(private dialog: MatDialog,
private dialogService: DialogService) {
@@ -69,16 +73,20 @@ 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 instanceof EventProperty) {
+ this.originalRuntimeName = this.findOriginalProperty().runtimeName;
+ this.showFieldStatus = this.fieldStatusInfo && this.fieldStatusInfo[this.originalRuntimeName] !== undefined;
+ this.showEventPreview = this.eventPreview && this.eventPreview.length > 0 && this.eventPreview[0][this.originalRuntimeName] !== undefined;
+ if (this.isPrimitive) {
+ this.originalRuntimeType = this.parseType(this.findOriginalProperty().runtimeType);
+ this.runtimeType = this.parseType((this.node.data as EventPropertyPrimitive).runtimeType);
+ }
}
if (!this.node.data.propertyScope) {
@@ -86,7 +94,9 @@ export class EventPropertyRowComponent implements OnInit, OnChanges {
}
}
- ngOnChanges(changes: SimpleChanges): void {
+ private findOriginalProperty(): any {
+ return this.originalEventSchema.eventProperties
+ .find(ep => ep.elementId === this.node.data.elementId);
}
private parseType(runtimeType: string) {
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html
index 79bf5a41d..d3cad53f6 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.html
@@ -16,4 +16,26 @@
~
-->
-<pre>{{ eventSchema | json }}</pre>
\ No newline at end of file
+<div fxFlex="100" fxLayout="row" fxLayoutGap="15px">
+ <div fxFlex="50" fxLayout="column">
+ <sp-basic-inner-panel [showTitle]="true" panelTitle="Original (Parsed)">
+ <pre [innerHTML]="originalField | jsonpretty" class="preview-text"></pre>
+ </sp-basic-inner-panel>
+ </div>
+
+ <div fxFlex="50" fxLayout="column">
+ <sp-basic-inner-panel [showTitle]="true" panelTitle="Result" fxFlex="100">
+ <div header fxLayoutAlign="end center" fxFlex="100">
+ <button color="accent"
+ mat-button
+ data-cy="connect-schema-update-preview-btn"
+ matTooltip="Update event preview"
+ (click)="updateEventPreview()">
+ <mat-icon>refresh</mat-icon>
+ <span> Update result preview</span>
+ </button>
+ </div>
+ <pre [innerHTML]="desiredField | jsonpretty" class="preview-text"></pre>
+ </sp-basic-inner-panel>
+ </div>
+</div>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
index 58ba04bdd..eddad5e07 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
@@ -16,3 +16,14 @@
*
*/
+.preview-text {
+ background-color: black;
+ font: 9pt Inconsolata, monospace;
+ text-shadow: 0 0 5px #C8C8C8;
+ color: white;
+ padding: 10px;
+ max-width: 100%;
+ max-height: 300px;
+ overflow-y: scroll;
+ white-space: pre-wrap;
+}
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
index f80de67d9..11823a586 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.ts
@@ -16,14 +16,43 @@
*
*/
-import { Component, Input } from '@angular/core';
-import { EventSchema } from '@streampipes/platform-services';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { EventSchema, GuessTypeInfo } from '@streampipes/platform-services';
@Component({
- selector: 'sp-event-schema-preview',
- templateUrl: './event-schema-preview.component.html',
- styleUrls: ['./event-schema-preview.component.scss']
+ selector: 'sp-event-schema-preview',
+ templateUrl: './event-schema-preview.component.html',
+ styleUrls: ['./event-schema-preview.component.scss']
})
-export class EventSchemaPreviewComponent {
- @Input() eventSchema: EventSchema;
+export class EventSchemaPreviewComponent implements OnInit {
+
+ @Input() originalEventSchema: EventSchema;
+ @Input() desiredEventSchema: EventSchema;
+
+ @Input() originalPreview: Record<string, GuessTypeInfo>;
+ @Input() desiredPreview: Record<string, GuessTypeInfo>;
+
+ @Output() updatePreviewEmitter = new EventEmitter();
+
+ originalField: Record<string, any>;
+ desiredField: Record<string, any>;
+
+ ngOnInit(): void {
+ this.originalField = this.toSimpleMap(this.originalPreview);
+ this.desiredField = this.toSimpleMap(this.desiredPreview);
+ }
+
+ toSimpleMap(event: Record<string, GuessTypeInfo>): Record<string, any> {
+ const result = {};
+ for (const key in event) {
+ result[key] = event[key].value;
+ }
+
+
+ return result;
+ }
+
+ public updateEventPreview() {
+ this.updatePreviewEmitter.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 f7474a0e7..6709dad75 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
@@ -17,12 +17,13 @@
-->
-<div fxLayout="row" fxLayoutAlign="center" class="mt-20">
+<div fxLayout="column" fxLayoutAlign="center" class="mt-20">
<div fxFlex="90" fxLayout="column">
<div fxLayout="column"
fxFlex="100"
fxLayoutAlign="start center"
- *ngIf="!isLoading && !isError && schemaErrorHints.length === 0" class="schema-validation schema-validation-ok">
+ *ngIf="!isLoading && !isError && schemaErrorHints.length === 0"
+ class="schema-validation schema-validation-ok">
<div fxFlex="100"
fxLayout="row"
fxLayoutAlign="start center"
@@ -36,7 +37,8 @@
fxLayout="column"
[ngClass]="schemaErrorHint.level === 'error' ? 'schema-validation schema-validation-error' : 'schema-validation schema-validation-warning'"
fxLayoutAlign="start center" *ngFor="let schemaErrorHint of schemaErrorHints">
- <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start" [ngClass]="schemaErrorHint.level === 'error' ? 'schema-validation-text-error' : 'schema-validation-text-warning'">
+ <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start"
+ [ngClass]="schemaErrorHint.level === 'error' ? 'schema-validation-text-error' : 'schema-validation-text-warning'">
<i class="material-icons">warning</i>
<b>{{schemaErrorHint.title}}</b>
</div>
@@ -53,7 +55,7 @@
(addStaticValuePropertyEmitter)="addStaticValueProperty()"
(addTimestampPropertyEmitter)="addTimestampProperty()"
(guessSchemaEmitter)="guessSchema()"
- (togglePreviewEmitter)="togglePreview()"
+ (updatePreviewEmitter)="updatePreview()"
(removeSelectedPropertiesEmitter)="removeSelectedProperties()">
</sp-schema-editor-header>
</div>
@@ -78,7 +80,7 @@
*ngIf="isError && !isLoading">
</sp-error-message>
- <div *ngIf="!isError && !isLoading && eventSchema"
+ <div *ngIf="!isError && !isLoading && eventSchema && oldEventSchema && nodes"
fxLayout="column"
fxLayoutAlign="space-evenly stretched"
class="drag-drop-tree"
@@ -92,6 +94,7 @@
[node]="node"
[(isEditable)]="isEditable"
[(eventSchema)]="eventSchema"
+ [(originalEventSchema)]="oldEventSchema"
[eventPreview]="eventPreview"
[fieldStatusInfo]="fieldStatusInfo"
(refreshTreeEmitter)="refreshTree()"
@@ -102,13 +105,17 @@
</div>
</sp-basic-inner-panel>
</div>
- <div fxFlex="0 1 50%" *ngIf="isPreviewEnabled">
- <sp-event-schema-preview [eventSchema]="eventSchema"></sp-event-schema-preview>
+ <div fxFlex="100" *ngIf="desiredPreview && isPreviewEnabled && !isLoading && !isError">
+ <sp-event-schema-preview [originalEventSchema]="oldEventSchema"
+ [desiredEventSchema]="eventSchema"
+ [originalPreview]="eventPreview[0]"
+ [desiredPreview]="desiredPreview"
+ (updatePreviewEmitter)="updatePreview()"></sp-event-schema-preview>
</div>
</div>
-<div fxLayoutAlign="end">
+<div fxLayoutAlign="end" class="mt-10">
<button class="mat-basic" mat-raised-button (click)="removeSelection()">Cancel</button>
<button class="mat-basic stepper-button" mat-raised-button (click)="goBack()">Back</button>
<button class="stepper-button"
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 d6e19e214..e7867d91f 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
@@ -36,6 +36,7 @@ import {
FieldStatusInfo, GuessTypeInfo,
StreamPipesErrorMessage
} from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
+import { TransformationRuleService } from '../../../../services/transformation-rule.service';
@Component({
selector: 'sp-event-schema',
@@ -44,7 +45,9 @@ import {
})
export class EventSchemaComponent implements OnChanges {
- constructor(private restService: RestService, private dataTypesService: DataTypesService) {
+ constructor(private restService: RestService,
+ private dataTypesService: DataTypesService,
+ private transformationRuleService: TransformationRuleService ) {
}
@Input() adapterDescription: AdapterDescription;
@@ -83,6 +86,7 @@ export class EventSchemaComponent implements OnChanges {
schemaErrorHints: UserErrorMessage[] = [];
eventPreview: Record<string, GuessTypeInfo>[];
+ desiredPreview: Record<string, GuessTypeInfo>;
fieldStatusInfo: Record<string, FieldStatusInfo>;
options: ITreeOptions = {
@@ -124,6 +128,10 @@ export class EventSchemaComponent implements OnChanges {
this.isEditable = true;
this.isEditableChange.emit(true);
this.isLoading = false;
+
+ if (guessSchema.eventPreview) {
+ this.updatePreview();
+ }
},
errorMessage => {
this.errorMessage = errorMessage.error;
@@ -138,7 +146,6 @@ export class EventSchemaComponent implements OnChanges {
this.nodes = new Array<EventProperty>();
this.nodes.push(this.eventSchema as unknown as EventProperty);
this.validEventSchema = this.checkIfValid(this.eventSchema);
- // this.tree.treeModel.update();
}
public addNestedProperty(eventProperty?: EventPropertyNested): void {
@@ -201,8 +208,15 @@ export class EventSchemaComponent implements OnChanges {
this.refreshTree();
}
- public togglePreview(): void {
- this.isPreviewEnabled = !this.isPreviewEnabled;
+ public updatePreview(): void {
+ this.isPreviewEnabled = false;
+ this.transformationRuleService.setOldEventSchema(this.oldEventSchema);
+ this.transformationRuleService.setNewEventSchema(this.eventSchema);
+ const ruleDescriptions = this.transformationRuleService.getTransformationRuleDescriptions();
+ this.restService.getAdapterEventPreview({rules: ruleDescriptions, inputData: this.eventPreview[0]}).subscribe(preview => {
+ this.desiredPreview = preview;
+ this.isPreviewEnabled = true;
+ });
}
ngOnChanges(changes: SimpleChanges) {
@@ -238,9 +252,17 @@ export class EventSchemaComponent implements OnChanges {
this.schemaErrorHints.push(new UserErrorMessage('Missing Timestamp', 'The timestamp must be a UNIX timestamp in milliseconds. Edit the timestamp field or add an ingestion timestamp.'));
}
- const badFields = eventSchema.eventProperties.map(ep => this.fieldStatusInfo[ep.runtimeName]).find(field => field.fieldStatus !== 'GOOD');
- if (badFields !== undefined) {
- this.schemaErrorHints.push(new UserErrorMessage('Bad reading', 'At least one field could not be properly read. If this is a permanent problem, consider removing it - keeping this field might cause the adapter to fail or to omit sending events.', 'warning'));
+ if (this.fieldStatusInfo) {
+ const badFields = eventSchema.eventProperties
+ .filter(ep => this.fieldStatusInfo[ep.runtimeName] !== undefined)
+ .map(ep => this.fieldStatusInfo[ep.runtimeName])
+ .find(field => field.fieldStatus !== 'GOOD');
+ if (badFields !== undefined) {
+ this.schemaErrorHints.push(new UserErrorMessage(
+ 'Bad reading',
+ 'At least one field could not be properly read. If this is a permanent problem, consider removing it - keeping this field might cause the adapter to fail or to omit sending events.',
+ 'warning'));
+ }
}
return hasTimestamp;
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts
index 27db921bc..7bcd8cc3c 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/schema-editor-header/schema-editor-header.component.ts
@@ -33,7 +33,7 @@ export class SchemaEditorHeaderComponent implements OnInit {
@Output() addStaticValuePropertyEmitter = new EventEmitter();
@Output() addTimestampPropertyEmitter = new EventEmitter();
@Output() guessSchemaEmitter = new EventEmitter();
- @Output() togglePreviewEmitter = new EventEmitter();
+ @Output() updatePreviewEmitter = new EventEmitter();
@Output() removeSelectedPropertiesEmitter = new EventEmitter();
constructor() { }
@@ -57,10 +57,6 @@ export class SchemaEditorHeaderComponent implements OnInit {
this.guessSchemaEmitter.emit();
}
- public togglePreview() {
- this.togglePreviewEmitter.emit();
- }
-
public removeSelectedProperties() {
this.removeSelectedPropertiesEmitter.emit();
}
diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts
index 1b23c969c..1bd77b851 100644
--- a/ui/src/app/connect/connect.module.ts
+++ b/ui/src/app/connect/connect.module.ts
@@ -84,6 +84,7 @@ import { EditValueTransformationComponent } from './dialog/edit-event-property/c
import { SpEpSettingsSectionComponent } from './dialog/edit-event-property/components/ep-settings-section/ep-settings-section.component';
import { SpAdapterOptionsPanelComponent } from './components/new-adapter/start-adapter-configuration/adapter-options-panel/adapter-options-panel.component';
import { SpAdapterTemplateDialogComponent } from './dialog/adapter-template/adapter-template-dialog.component';
+import { JsonPrettyPrintPipe } from './filter/json-pretty-print.pipe';
@NgModule({
imports: [
@@ -146,6 +147,7 @@ import { SpAdapterTemplateDialogComponent } from './dialog/adapter-template/adap
AdapterFilterPipe,
FormatItemComponent,
FormatListComponent,
+ JsonPrettyPrintPipe,
NewAdapterComponent,
SpAdapterTemplateDialogComponent,
PipelineElementRuntimeInfoComponent,
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss b/ui/src/app/connect/filter/json-pretty-print.pipe.ts
similarity index 70%
copy from ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
copy to ui/src/app/connect/filter/json-pretty-print.pipe.ts
index 58ba04bdd..5383916e4 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema-preview/event-schema-preview.component.scss
+++ b/ui/src/app/connect/filter/json-pretty-print.pipe.ts
@@ -16,3 +16,18 @@
*
*/
+import { Injectable, Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'jsonpretty'
+})
+@Injectable({providedIn: 'root'})
+export class JsonPrettyPrintPipe implements PipeTransform {
+
+ transform(json) {
+ return JSON.stringify(json, undefined, 4)
+ .replace(/ /g, ' ')
+ .replace(/\n/g, '<br/>');
+ }
+
+}
diff --git a/ui/src/app/connect/services/rest.service.ts b/ui/src/app/connect/services/rest.service.ts
index 5d33cdc3c..17459d539 100644
--- a/ui/src/app/connect/services/rest.service.ts
+++ b/ui/src/app/connect/services/rest.service.ts
@@ -23,16 +23,20 @@ import { HttpClient } from '@angular/common/http';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { UnitDescription } from '../model/UnitDescription';
-import { AdapterDescription, FormatDescription, GuessSchema, Message, SpDataStream, PlatformServicesCommons } from '@streampipes/platform-services';
+import {
+ AdapterDescription, FormatDescription, GuessSchema, Message, SpDataStream, PlatformServicesCommons,
+ AdapterEventPreview,
+ GuessTypeInfo
+} from '@streampipes/platform-services';
import { AuthService } from '../../services/auth.service';
@Injectable()
export class RestService {
constructor(
- private http: HttpClient,
- private platformServicesCommons: PlatformServicesCommons,
- private authService: AuthService) {
+ private http: HttpClient,
+ private platformServicesCommons: PlatformServicesCommons,
+ private authService: AuthService) {
}
get connectPath() {
@@ -66,7 +70,11 @@ export class RestService {
.pipe(map(response => {
return GuessSchema.fromData(response as GuessSchema);
}));
+ }
+ getAdapterEventPreview(adapterEventPreview: AdapterEventPreview): Observable<Record<string, GuessTypeInfo>> {
+ return this.http.post(`${this.connectPath}/master/guess/schema/preview`, adapterEventPreview)
+ .pipe(map(response => response as Record<string, GuessTypeInfo>));
}
getSourceDetails(sourceElementId): Observable<SpDataStream> {
@@ -78,7 +86,7 @@ export class RestService {
getRuntimeInfo(sourceDescription): Observable<any> {
return this.http.post(`${this.platformServicesCommons.apiBasePath}/pipeline-element/runtime`, sourceDescription, {
- headers: { ignoreLoadingBar: '' }
+ headers: {ignoreLoadingBar: ''}
});
}