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

[incubator-streampipes] 01/01: [STREAMPIPES-514] Rework format selection in Connect

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

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

commit 3f3a9ca853dd4833c66faf728903cedcbed2b8b1
Author: Philipp Zehnder <ze...@fzi.de>
AuthorDate: Fri Mar 11 17:50:20 2022 +0100

    [STREAMPIPES-514] Rework format selection in Connect
---
 .../adapter/format/geojson/GeoJsonFormat.java      |  2 +
 .../adapter/format/json/AbstractJsonFormat.java    |  1 +
 .../adapter/format/json/arraykey/JsonFormat.java   |  3 +-
 .../format/json/arraynokey/JsonArrayFormat.java    |  3 +-
 .../format/json/object/JsonObjectFormat.java       |  5 +-
 .../model/connect/grounding/FormatDescription.java | 15 +++++-
 .../builder/adapter/FormatDescriptionBuilder.java  | 10 ++++
 .../src/lib/model/gen/streampipes-model-client.ts  |  2 +-
 .../src/lib/model/gen/streampipes-model.ts         | 14 +++---
 .../format-configuration.component.html            |  4 +-
 .../format-configuration.component.ts              | 12 +----
 .../format-item-json.component.html}               | 12 +++--
 .../format-item-json.component.scss                | 47 ++++++++++++++++++
 .../format-item-json/format-item-json.component.ts | 36 ++++++++++++++
 .../format-item/format-item.component.html         | 11 ++++-
 .../format-item/format-item.component.ts           | 10 ----
 .../format-list/format-list.component.html         | 32 +++++++++++--
 .../format-list/format-list.component.ts           | 56 +++++++++++++++++++---
 ui/src/app/connect/connect.module.ts               |  4 +-
 19 files changed, 227 insertions(+), 52 deletions(-)

diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/geojson/GeoJsonFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/geojson/GeoJsonFormat.java
index 40b4152..39465e1 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/geojson/GeoJsonFormat.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/geojson/GeoJsonFormat.java
@@ -18,6 +18,7 @@
 
 package org.apache.streampipes.connect.adapter.format.geojson;
 
+import org.apache.streampipes.connect.adapter.format.json.AbstractJsonFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.streampipes.commons.exceptions.SpRuntimeException;
@@ -40,6 +41,7 @@ public class GeoJsonFormat implements IFormat {
     public FormatDescription declareModel() {
 
         return FormatDescriptionBuilder.create(ID, "GeoJSON", "Reads GeoJson")
+                .addFormatType(AbstractJsonFormat.JSON_FORMAT_TYPE)
                 .build();
 
     }
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java
index eaf48a9..a7116ae 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/AbstractJsonFormat.java
@@ -26,6 +26,7 @@ import org.apache.streampipes.model.schema.EventSchema;
 import java.util.Map;
 
 public abstract class AbstractJsonFormat implements IFormat {
+  public static String JSON_FORMAT_TYPE = "json";
 
   @Override
   public Map<String, Object> parse(byte[] object) throws ParseException {
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraykey/JsonFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraykey/JsonFormat.java
index f226c06..fe53165 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraykey/JsonFormat.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraykey/JsonFormat.java
@@ -38,7 +38,8 @@ public class JsonFormat extends AbstractJsonFormat {
     @Override
     public FormatDescription declareModel() {
 
-        return FormatDescriptionBuilder.create(ID, "Json Array Key", "Transforms objects within an array into events")
+        return FormatDescriptionBuilder.create(ID, "Array Field", "Use one property of the json object that is an array, e.g. {'arrayKey': [{'value': 1}, {'value': 2}]}")
+                .addFormatType(JSON_FORMAT_TYPE)
                 .requiredTextParameter(Labels.from("key","Key",
                         "Key of the array within the Json object"))
                 .build();
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraynokey/JsonArrayFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraynokey/JsonArrayFormat.java
index a956832..79b573a 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraynokey/JsonArrayFormat.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/arraynokey/JsonArrayFormat.java
@@ -35,7 +35,8 @@ public class JsonArrayFormat extends AbstractJsonFormat {
 
     @Override
     public FormatDescription declareModel() {
-        return FormatDescriptionBuilder.create(ID, "Json Array No Key", "Transforms all objects within array to events")
+        return FormatDescriptionBuilder.create(ID, "Array", "Each event consists of only one array of json objects, e.g. [{'value': 1}, {'value': 2}]")
+                .addFormatType(JSON_FORMAT_TYPE)
                 .build();
     }
 
diff --git a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectFormat.java b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectFormat.java
index 9eeb69b..f5306bb 100644
--- a/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectFormat.java
+++ b/streampipes-connect/src/main/java/org/apache/streampipes/connect/adapter/format/json/object/JsonObjectFormat.java
@@ -34,8 +34,9 @@ public class JsonObjectFormat extends AbstractJsonFormat {
 
   @Override
   public FormatDescription declareModel() {
-    return FormatDescriptionBuilder.create(ID, "Json Object", "Requires an enclosing Json Object")
-                .build();
+    return FormatDescriptionBuilder.create(ID, "Single Object", "Each event is a single json object (e.g. {'value': 1})")
+            .addFormatType(JSON_FORMAT_TYPE)
+            .build();
   }
 
   @Override
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/grounding/FormatDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/grounding/FormatDescription.java
index cac5f91..ba6bb40 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/grounding/FormatDescription.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/grounding/FormatDescription.java
@@ -30,6 +30,8 @@ public class FormatDescription extends NamedStreamPipesEntity {
 
     private List<StaticProperty> config;
 
+    private String formatType = "";
+
     public FormatDescription() {
         super();
         this.config = new ArrayList<>();
@@ -40,14 +42,16 @@ public class FormatDescription extends NamedStreamPipesEntity {
         this.config = new ArrayList<>();
     }
 
-    public FormatDescription(String uri, String name, String description, List<StaticProperty> config) {
+    public FormatDescription(String uri, String name, String description, List<StaticProperty> config, String formatType) {
         super(uri, name, description);
         this.config = config;
+        this.formatType = formatType;
     }
 
     public FormatDescription(FormatDescription other) {
         super(other);
         this.config = new Cloner().staticProperties(other.getConfig());
+        this.formatType = other.getFormatType();
     }
 
     public void addConfig(StaticProperty sp) {
@@ -62,9 +66,18 @@ public class FormatDescription extends NamedStreamPipesEntity {
         this.config = config;
     }
 
+    public String getFormatType() {
+        return formatType;
+    }
+
+    public void setFormatType(String formatType) {
+        this.formatType = formatType;
+    }
+
     @Override
     public String toString() {
         return "FormatDescription{" +
+                "formatType=" + formatType +
                 "config=" + config +
                 '}';
     }
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/FormatDescriptionBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/FormatDescriptionBuilder.java
index c7d3ff0..cfa5706 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/FormatDescriptionBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/FormatDescriptionBuilder.java
@@ -38,6 +38,16 @@ public class FormatDescriptionBuilder extends
     return new FormatDescriptionBuilder(id, label, description);
   }
 
+  /**
+   * Add a format type to the format description, e.g. json
+   * @param formatType
+   * @return
+   */
+  public FormatDescriptionBuilder addFormatType(String formatType) {
+    this.elementDescription.setFormatType(formatType);
+    return me();
+  }
+
   @Override
   protected FormatDescriptionBuilder me() {
     return this;
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
index b572c42..2793222 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
@@ -18,7 +18,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2022-02-02 13:46:18.
+// Generated using typescript-generator version 2.27.744 on 2022-03-11 16:37:33.
 
 export class ExtensionsServiceEndpointItem {
     appId: string;
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 a68c527..18a5649 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-02-05 22:40:52.
+// Generated using typescript-generator version 2.27.744 on 2022-03-11 16:37:20.
 
 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,8 +192,8 @@ export class AdapterDescription extends NamedStreamPipesEntity {
         instance.selectedEndpointUrl = data.selectedEndpointUrl;
         instance.correspondingServiceGroup = data.correspondingServiceGroup;
         instance.correspondingDataStreamElementId = data.correspondingDataStreamElementId;
-        instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules);
         instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules);
+        instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules);
         instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
         return instance;
     }
@@ -1589,6 +1589,7 @@ export class FixedOutputStrategy extends OutputStrategy {
 export class FormatDescription extends NamedStreamPipesEntity {
     "@class": "org.apache.streampipes.model.connect.grounding.FormatDescription";
     config: StaticPropertyUnion[];
+    formatType: string;
 
     static fromData(data: FormatDescription, target?: FormatDescription): FormatDescription {
         if (!data) {
@@ -1597,6 +1598,7 @@ export class FormatDescription extends NamedStreamPipesEntity {
         const instance = target || new FormatDescription();
         super.fromData(data, instance);
         instance.config = __getCopyArrayFn(StaticProperty.fromDataUnion)(data.config);
+        instance.formatType = data.formatType;
         return instance;
     }
 }
@@ -1666,9 +1668,9 @@ 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.eventSchema = EventSchema.fromData(data.eventSchema);
         return instance;
     }
 }
@@ -1685,9 +1687,9 @@ 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.eventSchema = EventSchema.fromData(data.eventSchema);
         return instance;
     }
 }
@@ -2498,8 +2500,8 @@ export class PipelineTemplateDescription extends NamedStreamPipesEntity {
         const instance = target || new PipelineTemplateDescription();
         super.fromData(data, instance);
         instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)(data.boundTo);
-        instance.pipelineTemplateName = data.pipelineTemplateName;
         instance.pipelineTemplateDescription = data.pipelineTemplateDescription;
+        instance.pipelineTemplateName = data.pipelineTemplateName;
         instance.pipelineTemplateId = data.pipelineTemplateId;
         return instance;
     }
@@ -2901,8 +2903,8 @@ export class SpDataSet extends SpDataStream {
         instance.datasetInvocationId = data.datasetInvocationId;
         instance.correspondingPipeline = data.correspondingPipeline;
         instance.selectedEndpointUrl = data.selectedEndpointUrl;
-        instance.brokerHostname = data.brokerHostname;
         instance.actualTopicName = data.actualTopicName;
+        instance.brokerHostname = data.brokerHostname;
         return instance;
     }
 }
diff --git a/ui/src/app/connect/components/format-configuration/format-configuration.component.html b/ui/src/app/connect/components/format-configuration/format-configuration.component.html
index a1ac028..13da938 100644
--- a/ui/src/app/connect/components/format-configuration/format-configuration.component.html
+++ b/ui/src/app/connect/components/format-configuration/format-configuration.component.html
@@ -23,13 +23,13 @@
     </div>
     <div class="sp-blue-border padding">
         <sp-format-list fxFlex="100"
-                        [allFormats]="allFormats"
                         (selectedFormatEmitter)="formatSelected($event)"
                         [selectedFormat]="selectedFormat">
         </sp-format-list>
     </div>
 
-    <div class="assemblyOptions sp-blue-bg">
+    <div class="assemblyOptions sp-blue-bg"
+         *ngIf="selectedFormat">
         <h4>Configure format</h4>
     </div>
 
diff --git a/ui/src/app/connect/components/format-configuration/format-configuration.component.ts b/ui/src/app/connect/components/format-configuration/format-configuration.component.ts
index 1ef937f..87a8c7c 100644
--- a/ui/src/app/connect/components/format-configuration/format-configuration.component.ts
+++ b/ui/src/app/connect/components/format-configuration/format-configuration.component.ts
@@ -59,11 +59,6 @@ export class FormatConfigurationComponent implements OnInit {
   selectedFormat: FormatDescription;
 
   /**
-   * Contains all the available formats that a user can select from
-   */
-  allFormats: FormatDescription[] = [];
-
-  /**
    * The form group to validate the configuration for the format
    */
   formatForm: FormGroup;
@@ -75,11 +70,6 @@ export class FormatConfigurationComponent implements OnInit {
 
   ngOnInit(): void {
 
-    // fetch all available formats from backend
-    this.restService.getFormats().subscribe(res => {
-      this.allFormats = res;
-    });
-
     // initialize form for validation
     this.formatForm = this._formBuilder.group({});
     this.formatForm.statusChanges.subscribe((status) => {
@@ -101,6 +91,8 @@ export class FormatConfigurationComponent implements OnInit {
         this.formatConfigurationValid = this.formatForm.valid;
       }
     }
+
+    this.formatConfigurationValid = false;
   }
 
   formatSelected(selectedFormat) {
diff --git a/ui/src/app/connect/components/format-item/format-item.component.html b/ui/src/app/connect/components/format-item-json/format-item-json.component.html
similarity index 74%
copy from ui/src/app/connect/components/format-item/format-item.component.html
copy to ui/src/app/connect/components/format-item-json/format-item-json.component.html
index 0edf190..5c36b30 100644
--- a/ui/src/app/connect/components/format-item/format-item.component.html
+++ b/ui/src/app/connect/components/format-item-json/format-item-json.component.html
@@ -16,6 +16,12 @@
   ~
   -->
 
-<div [attr.data-cy]="format.name.split(' ').join('_').toLowerCase()" *ngIf="!$any(format).edit || !hasConfig" class="format-box" (click)="formatEditable()" [ngClass]="{selectedItem: isSelected()}" fxFlex="100" fxLayout="column">
-    <div class="format-label"> {{format.name}} </div>
-</div>
\ No newline at end of file
+<div fxFlex="100"
+     fxLayout="column"
+     matTooltip="Select one of the supported json formats"
+     data-cy="connect-select-json-formats"
+     class="format-box"
+     [ngClass]="{selectedItem: isSelected}" >
+    <div class="format-label">Json</div>
+</div>
+
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.scss b/ui/src/app/connect/components/format-item-json/format-item-json.component.scss
new file mode 100644
index 0000000..30123c0
--- /dev/null
+++ b/ui/src/app/connect/components/format-item-json/format-item-json.component.scss
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ */
+
+
+.format-label {
+  line-height:50px;
+  margin: auto;
+  text-align: center;
+  font-weight: bold;
+  font-size: 1.3em;
+}
+
+.format-box {
+  min-height: 50px;
+  box-shadow: 1px 1px 2px #555;
+  border: 1px solid gray;
+  cursor: pointer;
+  padding: 10px;
+  opacity: 0.7;
+  margin: 10px;
+  background: #ffffff;
+}
+
+.format-box:hover {
+  opacity: 1;
+}
+
+.selectedItem {
+  opacity: 1;
+  background-color: grey;
+}
+
diff --git a/ui/src/app/connect/components/format-item-json/format-item-json.component.ts b/ui/src/app/connect/components/format-item-json/format-item-json.component.ts
new file mode 100644
index 0000000..cfc24c5
--- /dev/null
+++ b/ui/src/app/connect/components/format-item-json/format-item-json.component.ts
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ */
+
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'sp-format-item-json',
+  templateUrl: './format-item-json.component.html',
+  styleUrls: ['./format-item-json.component.scss']
+})
+export class FormatItemJsonComponent implements OnInit {
+
+  @Input()
+  isSelected: boolean;
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/ui/src/app/connect/components/format-item/format-item.component.html b/ui/src/app/connect/components/format-item/format-item.component.html
index 0edf190..db77998 100644
--- a/ui/src/app/connect/components/format-item/format-item.component.html
+++ b/ui/src/app/connect/components/format-item/format-item.component.html
@@ -16,6 +16,13 @@
   ~
   -->
 
-<div [attr.data-cy]="format.name.split(' ').join('_').toLowerCase()" *ngIf="!$any(format).edit || !hasConfig" class="format-box" (click)="formatEditable()" [ngClass]="{selectedItem: isSelected()}" fxFlex="100" fxLayout="column">
+<div fxFlex="100"
+     fxLayout="column"
+     matTooltip="{{format.description}}"
+     [attr.data-cy]="format.name.split(' ').join('_').toLowerCase()"
+     *ngIf="!$any(format).edit || !hasConfig"
+     class="format-box"
+     (click)="formatEditable()"
+     [ngClass]="{selectedItem: isSelected()}" >
     <div class="format-label"> {{format.name}} </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/connect/components/format-item/format-item.component.ts b/ui/src/app/connect/components/format-item/format-item.component.ts
index 779a93e..6d7db60 100644
--- a/ui/src/app/connect/components/format-item/format-item.component.ts
+++ b/ui/src/app/connect/components/format-item/format-item.component.ts
@@ -51,16 +51,6 @@ export class FormatItemComponent {
 
   }
 
-  validateText(textValid) {
-    if (textValid && (this.format as any).edit) {
-      this.validateEmitter.emit(true);
-      this.selectedFormat = this.format;
-      this.selectedFormatEmitter.emit(this.selectedFormat);
-    } else {
-      this.validateEmitter.emit(false);
-      this.selectedFormat = null;
-    }
-  }
   isSelected(): boolean {
     if (!this.selectedFormat || !this.format) {
       return false;
diff --git a/ui/src/app/connect/components/format-list/format-list.component.html b/ui/src/app/connect/components/format-list/format-list.component.html
index d1e731d..59d46c2 100644
--- a/ui/src/app/connect/components/format-list/format-list.component.html
+++ b/ui/src/app/connect/components/format-list/format-list.component.html
@@ -17,11 +17,33 @@
   -->
 
 <div fxLayout="row wrap" fxLayoutAlign="start stretch">
-    <div fxFlex="33" *ngFor="let format of allFormats">
+
+    <div fxFlex="25">
+        <sp-format-item-json
+                [isSelected]="selectJsonFormats"
+                (click)="selectJsonFormat()"></sp-format-item-json>
+    </div>
+    <div fxFlex="25"
+         *ngFor="let format of allFormats">
+        <sp-format-item [format]="format" (validateEmitter)="validateAll($event)"
+                        (editableEmitter)="formatEditable($event)"
+                        [selectedFormat]="selectedFormat"
+                        (selectedFormatEmitter)="formatSelected($event)">
+        </sp-format-item>
+    </div>
+
+    <div fxFlex="100"
+         class="assemblyOptions sp-blue-bg"
+         *ngIf="selectJsonFormats">
+        <h4>Select json format</h4>
+    </div>
+
+    <div fxFlex="25"
+         *ngFor="let format of showJsonFormats">
         <sp-format-item [format]="format" (validateEmitter)="validateAll($event)"
-        (editableEmitter)="formatEditable($event)"
-        [selectedFormat]="selectedFormat"
-        (selectedFormatEmitter)="formatSelected($event)">
+                        (editableEmitter)="formatEditable($event)"
+                        [selectedFormat]="selectedFormat"
+                        (selectedFormatEmitter)="formatSelected($event)">
         </sp-format-item>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/connect/components/format-list/format-list.component.ts b/ui/src/app/connect/components/format-list/format-list.component.ts
index e9c2493..bcc1afd 100644
--- a/ui/src/app/connect/components/format-list/format-list.component.ts
+++ b/ui/src/app/connect/components/format-list/format-list.component.ts
@@ -16,8 +16,9 @@
  *
  */
 
-import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 import { FormatDescription } from '@streampipes/platform-services';
+import { RestService } from '../../services/rest.service';
 
 @Component({
     selector: 'sp-format-list',
@@ -25,15 +26,42 @@ import { FormatDescription } from '@streampipes/platform-services';
     styleUrls: ['./format-list.component.scss']
   })
 
-export class FormatListComponent {
+export class FormatListComponent implements OnInit {
 
     @Input() public selectedFormat: FormatDescription;
-    @Input() allFormats: FormatDescription[];
 
     @Output() validateEmitter = new EventEmitter();
     @Output() public selectedFormatEmitter = new EventEmitter<FormatDescription>();
 
-    constructor() {
+    /**
+     * Contains all the available formats that a user can select from
+     */
+    allFormats: FormatDescription[] = [];
+
+    allJsonFormats: FormatDescription[] = [];
+    showJsonFormats: FormatDescription[] = [];
+
+    jsonFormatDescription = new FormatDescription();
+    selectJsonFormats = false;
+
+    constructor(private restService: RestService) {
+        this.jsonFormatDescription.name = 'Json';
+    }
+
+    ngOnInit(): void {
+        // fetch all available formats from backend
+        this.restService.getFormats().subscribe(res => {
+            // this.allFormats.push(jsonFormatDescription);
+            // split resulting formats up to only show one button for Json Formats
+            res.forEach(format => {
+                if (format.formatType !== 'json') {
+                    this.allFormats.push(format);
+                } else {
+                    this.allJsonFormats.push(format);
+                }
+            });
+        });
+
     }
 
     formatEditable(selectedFormat) {
@@ -44,9 +72,23 @@ export class FormatListComponent {
       });
     }
 
-    formatSelected(selectedFormat) {
-      this.selectedFormat = selectedFormat;
-      this.selectedFormatEmitter.emit(this.selectedFormat);
+    formatSelected(selectedFormat: FormatDescription) {
+        if (selectedFormat.formatType !== 'json') {
+            this.showJsonFormats = [];
+            this.selectJsonFormats = false;
+        }
+
+        this.selectedFormat = selectedFormat;
+        this.selectedFormatEmitter.emit(this.selectedFormat);
+
+    }
+
+    selectJsonFormat() {
+        this.showJsonFormats = this.allJsonFormats;
+        this.selectJsonFormats = true;
+
+        this.selectedFormat = this.allJsonFormats[2];
+        this.selectedFormatEmitter.emit(this.selectedFormat);
 
     }
 
diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts
index fa1a258..0e5e9ea 100644
--- a/ui/src/app/connect/connect.module.ts
+++ b/ui/src/app/connect/connect.module.ts
@@ -80,6 +80,7 @@ import { SchemaEditorHeaderComponent } from './components/schema-editor/schema-e
 import { StartAdapterConfigurationComponent } from './components/start-adapter-configuration/start-adapter-configuration.component';
 import { DeleteAdapterDialogComponent } from './dialog/delete-adapter-dialog/delete-adapter-dialog.component';
 import { PlatformServicesModule } from '@streampipes/platform-services';
+import { FormatItemJsonComponent } from './components/format-item-json/format-item-json.component';
 
 @NgModule({
   imports: [
@@ -134,7 +135,8 @@ import { PlatformServicesModule } from '@streampipes/platform-services';
     ErrorMessageComponent,
     LoadingMessageComponent,
     SchemaEditorHeaderComponent,
-    StartAdapterConfigurationComponent
+    StartAdapterConfigurationComponent,
+    FormatItemJsonComponent
   ],
   providers: [
     RestService,