You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by bo...@apache.org on 2023/01/20 21:11:10 UTC

[streampipes] 01/01: [#877] apply formatting and linting to editor module

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

bossenti pushed a commit to branch chore/formatting-inting-editor
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit ee7bb5adfa16aa423b280176a1e5e681085716e1
Author: bossenti <bo...@posteo.de>
AuthorDate: Fri Jan 20 22:10:34 2023 +0100

    [#877] apply formatting and linting to editor module
---
 ui/.eslintignore                                   |    1 -
 ui/.prettierignore                                 |    1 -
 .../output-strategy/base/BaseOutputStrategy.ts     |   26 +-
 .../custom-output-strategy.component.html          |   86 +-
 .../custom-output-strategy.component.scss          |    1 -
 .../custom-output-strategy.component.ts            |  101 +-
 .../output-strategy/output-strategy.component.html |   44 +-
 .../output-strategy/output-strategy.component.scss |   10 +-
 .../output-strategy/output-strategy.component.ts   |   43 +-
 .../property-selection.component.html              |   37 +-
 .../property-selection.component.scss              |    4 +-
 .../property-selection.component.ts                |   90 +-
 .../user-defined-output.component.html             |   85 +-
 .../user-defined-output.component.scss             |    1 -
 .../user-defined-output.component.ts               |  137 +--
 .../pipeline-assembly.component.html               |  154 ++-
 .../pipeline-assembly.component.scss               |   11 +-
 .../pipeline-assembly.component.ts                 |  226 ++--
 .../pipeline-element-documentation.component.html  |    8 +-
 .../pipeline-element-documentation.component.scss  |    2 +-
 .../pipeline-element-documentation.component.ts    |   52 +-
 .../pipeline-element-icon-stand-row.component.html |   58 +-
 .../pipeline-element-icon-stand-row.component.scss |   84 +-
 .../pipeline-element-icon-stand-row.component.ts   |   59 +-
 .../pipeline-element-icon-stand.component.html     |  244 +++--
 .../pipeline-element-icon-stand.component.scss     |   89 +-
 .../pipeline-element-icon-stand.component.ts       |  306 +++---
 .../pipeline-element-options.component.html        |  142 ++-
 .../pipeline-element-options.component.ts          |  338 +++---
 .../pipeline-element-preview.component.html        |   17 +-
 .../pipeline-element-preview.component.scss        |   32 +-
 .../pipeline-element-preview.component.ts          |   76 +-
 .../pipeline-element-recommendation.component.html |   35 +-
 .../pipeline-element-recommendation.component.ts   |  290 ++---
 .../pipeline-element.component.html                |    9 +-
 .../pipeline-element/pipeline-element.component.ts |   38 +-
 .../components/pipeline/pipeline.component.html    |  116 +-
 .../components/pipeline/pipeline.component.ts      | 1107 ++++++++++++--------
 ui/src/app/editor/constants/editor.constants.ts    |   13 +-
 .../compatible-elements.component.html             |   41 +-
 .../compatible-elements.component.scss             |   13 +-
 .../compatible-elements.component.ts               |  138 +--
 .../dialog/customize/customize.component.html      |  178 +++-
 .../dialog/customize/customize.component.scss      |    7 +-
 .../editor/dialog/customize/customize.component.ts |  365 ++++---
 ui/src/app/editor/dialog/help/help.component.html  |   88 +-
 ui/src/app/editor/dialog/help/help.component.scss  |    8 +-
 ui/src/app/editor/dialog/help/help.component.ts    |  157 +--
 .../matching-error/matching-error.component.html   |   39 +-
 .../matching-error/matching-error.component.scss   |    2 +-
 .../matching-error/matching-error.component.ts     |   31 +-
 .../missing-elements-for-tutorial.component.html   |   24 +-
 .../missing-elements-for-tutorial.component.scss   |    2 +-
 .../missing-elements-for-tutorial.component.ts     |   24 +-
 .../pipeline-element-discovery.component.html      |   41 +-
 .../pipeline-element-discovery.component.scss      |    4 +-
 .../pipeline-element-discovery.component.ts        |  124 +--
 .../save-pipeline/save-pipeline.component.html     |  144 ++-
 .../save-pipeline/save-pipeline.component.scss     |   20 +-
 .../save-pipeline/save-pipeline.component.ts       |  306 +++---
 .../welcome-tour/welcome-tour.component.html       |   45 +-
 .../welcome-tour/welcome-tour.component.scss       |   28 +-
 .../dialog/welcome-tour/welcome-tour.component.ts  |   69 +-
 ui/src/app/editor/editor.component.html            |   47 +-
 ui/src/app/editor/editor.component.scss            |   10 +-
 ui/src/app/editor/editor.component.ts              |  272 ++---
 ui/src/app/editor/editor.module.ts                 |   19 +-
 .../filter/enabled-pipeline-element.filter.ts      |   17 +-
 ui/src/app/editor/model/editor.model.ts            |   86 +-
 ui/src/app/editor/model/jsplumb.model.ts           |   12 +-
 ui/src/app/editor/services/editor.service.ts       |  228 ++--
 .../app/editor/services/jsplumb-bridge.service.ts  |   32 +-
 .../app/editor/services/jsplumb-config.service.ts  |  314 +++---
 .../editor/services/jsplumb-endpoint.service.ts    |   80 +-
 .../app/editor/services/jsplumb-factory.service.ts |   43 +-
 ui/src/app/editor/services/jsplumb.service.ts      |  695 +++++++-----
 .../app/editor/services/object-provider.service.ts |   74 +-
 .../services/pipeline-canvas-scrolling.service.ts  |   19 +-
 .../app/editor/services/pipeline-editor.service.ts |   23 +-
 .../services/pipeline-element-dragged.service.ts   |   12 +-
 .../services/pipeline-element-group-filter.pipe.ts |   29 +-
 .../services/pipeline-element-name-filter.pipe.ts  |   28 +-
 .../pipeline-element-recommendation.service.ts     |   43 +-
 .../services/pipeline-element-type-filter.pipe.ts  |   25 +-
 .../services/pipeline-positioning.service.ts       |  362 ++++---
 .../app/editor/services/pipeline-style.service.ts  |  114 +-
 .../editor/services/pipeline-validation.service.ts |  119 ++-
 ui/src/app/editor/utils/editor.utils.ts            |  127 ++-
 ui/src/app/editor/utils/style-sanitizer.ts         |   13 +-
 .../elements/pipeline-elements-row.component.html  |    4 +-
 90 files changed, 5283 insertions(+), 3635 deletions(-)

diff --git a/ui/.eslintignore b/ui/.eslintignore
index c980966c1..4c9d16627 100644
--- a/ui/.eslintignore
+++ b/ui/.eslintignore
@@ -25,7 +25,6 @@ src/app/core-ui
 src/app/CustomMaterial
 src/app/dashboard
 src/app/data-explorer
-src/app/editor
 src/app/files
 src/app/info
 src/app/login
diff --git a/ui/.prettierignore b/ui/.prettierignore
index 3930e91ee..fd1073283 100644
--- a/ui/.prettierignore
+++ b/ui/.prettierignore
@@ -25,7 +25,6 @@ src/app/core-ui
 src/app/CustomMaterial
 src/app/dashboard
 src/app/data-explorer
-src/app/editor
 src/app/files
 src/app/info
 src/app/login
diff --git a/ui/src/app/editor/components/output-strategy/base/BaseOutputStrategy.ts b/ui/src/app/editor/components/output-strategy/base/BaseOutputStrategy.ts
index 8a920817f..1d57a7d45 100644
--- a/ui/src/app/editor/components/output-strategy/base/BaseOutputStrategy.ts
+++ b/ui/src/app/editor/components/output-strategy/base/BaseOutputStrategy.ts
@@ -19,28 +19,24 @@
 import { Input, Directive } from '@angular/core';
 import { UntypedFormGroup } from '@angular/forms';
 import {
-  DataProcessorInvocation,
-  OutputStrategy
+    DataProcessorInvocation,
+    OutputStrategy,
 } from '@streampipes/platform-services';
 
 @Directive()
 // eslint-disable-next-line @angular-eslint/directive-class-suffix
 export abstract class BaseOutputStrategy<T extends OutputStrategy> {
+    @Input()
+    parentForm: UntypedFormGroup;
 
-  @Input()
-  parentForm: UntypedFormGroup;
+    @Input()
+    outputStrategy: T;
 
-  @Input()
-  outputStrategy: T;
+    @Input()
+    selectedElement: DataProcessorInvocation;
 
-  @Input()
-  selectedElement: DataProcessorInvocation;
-
-  @Input()
-  restrictedEditMode: boolean;
-
-  constructor() {
-
-  }
+    @Input()
+    restrictedEditMode: boolean;
 
+    constructor() {}
 }
diff --git a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.html b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.html
index 288298b2c..c2321fe8e 100644
--- a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.html
+++ b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.html
@@ -17,35 +17,81 @@
   -->
 <div fxFlex="100" fxLayout="column">
     <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center">
-        <h5 style="margin-right:10px;">{{selectedElement.inputStreams[0].name}}</h5>
-        <button mat-button mat-raised-button color="accent" class="small-button"
-                (click)="selectAll(collectedPropertiesFirstStream)"
-                style="margin-right:10px;margin-left:10px;" [disabled]="restrictedEditMode">Select all
+        <h5 style="margin-right: 10px">
+            {{ selectedElement.inputStreams[0].name }}
+        </h5>
+        <button
+            mat-button
+            mat-raised-button
+            color="accent"
+            class="small-button"
+            (click)="selectAll(collectedPropertiesFirstStream)"
+            style="margin-right: 10px; margin-left: 10px"
+            [disabled]="restrictedEditMode"
+        >
+            Select all
         </button>
-        <button mat-button mat-raised-button class="mat-basic small-button"
-                (click)="deselectAll(collectedPropertiesFirstStream)" [disabled]="restrictedEditMode">Select
-            none
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic small-button"
+            (click)="deselectAll(collectedPropertiesFirstStream)"
+            [disabled]="restrictedEditMode"
+        >
+            Select none
         </button>
     </div>
     <div *ngFor="let property of collectedPropertiesFirstStream; let i = index">
-        <property-selection (validateForm)="checkFormValidity()" [outputStrategy]="outputStrategy" [eventProperty]="property"
-                            [layer]="0" [restrictedEditMode]="restrictedEditMode"></property-selection>
+        <sp-property-selection
+            (validateForm)="checkFormValidity()"
+            [outputStrategy]="outputStrategy"
+            [eventProperty]="property"
+            [layer]="0"
+            [restrictedEditMode]="restrictedEditMode"
+        ></sp-property-selection>
     </div>
-    <div fxLayout="column" fxFlex="100" *ngIf="collectedPropertiesSecondStream.length > 0">
+    <div
+        fxLayout="column"
+        fxFlex="100"
+        *ngIf="collectedPropertiesSecondStream.length > 0"
+    >
         <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center">
-            <h5 style="margin-right:10px;">{{selectedElement.inputStreams[1].name}}</h5>
-            <button mat-button mat-raised-button color="accent" class="small-button"
-                    (click)="selectAll(collectedPropertiesSecondStream)"
-                    style="margin-right:10px;margin-left:10px;" [disabled]="restrictedEditMode">Select all
+            <h5 style="margin-right: 10px">
+                {{ selectedElement.inputStreams[1].name }}
+            </h5>
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                class="small-button"
+                (click)="selectAll(collectedPropertiesSecondStream)"
+                style="margin-right: 10px; margin-left: 10px"
+                [disabled]="restrictedEditMode"
+            >
+                Select all
             </button>
-            <button mat-button mat-raised-button class="mat-basic small-button"
-                    (click)="deselectAll(collectedPropertiesSecondStream)" [disabled]="restrictedEditMode">Select
-                none
+            <button
+                mat-button
+                mat-raised-button
+                class="mat-basic small-button"
+                (click)="deselectAll(collectedPropertiesSecondStream)"
+                [disabled]="restrictedEditMode"
+            >
+                Select none
             </button>
         </div>
-        <div *ngFor="let property of collectedPropertiesSecondStream; let i = index">
-            <property-selection [outputStrategy]="outputStrategy" [eventProperty]="property"
-                                [layer]="0" [restrictedEditMode]="restrictedEditMode"></property-selection>
+        <div
+            *ngFor="
+                let property of collectedPropertiesSecondStream;
+                let i = index
+            "
+        >
+            <sp-property-selection
+                [outputStrategy]="outputStrategy"
+                [eventProperty]="property"
+                [layer]="0"
+                [restrictedEditMode]="restrictedEditMode"
+            ></sp-property-selection>
         </div>
     </div>
 </div>
diff --git a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.scss b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.scss
index 58ba04bdd..13cbc4aac 100644
--- a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.scss
+++ b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.scss
@@ -15,4 +15,3 @@
  * limitations under the License.
  *
  */
-
diff --git a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.ts b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.ts
index 12faf2615..281e5c41a 100644
--- a/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.ts
+++ b/ui/src/app/editor/components/output-strategy/custom-output/custom-output-strategy.component.ts
@@ -23,51 +23,74 @@ import { PropertySelectorService } from '../../../../services/property-selector.
 import { UntypedFormControl } from '@angular/forms';
 
 @Component({
-  selector: 'custom-output-strategy',
-  templateUrl: './custom-output-strategy.component.html',
-  styleUrls: ['./custom-output-strategy.component.scss']
+    selector: 'sp-custom-output-strategy',
+    templateUrl: './custom-output-strategy.component.html',
+    styleUrls: ['./custom-output-strategy.component.scss'],
 })
-export class CustomOutputStrategyComponent extends BaseOutputStrategy<CustomOutputStrategy> implements OnInit {
+export class CustomOutputStrategyComponent
+    extends BaseOutputStrategy<CustomOutputStrategy>
+    implements OnInit
+{
+    collectedPropertiesFirstStream: any;
+    collectedPropertiesSecondStream: any;
 
-  collectedPropertiesFirstStream: any;
-  collectedPropertiesSecondStream: any;
-
-  constructor(private propertySelectorService: PropertySelectorService) {
-    super();
-  }
+    constructor(private propertySelectorService: PropertySelectorService) {
+        super();
+    }
 
-  ngOnInit() {
-    this.parentForm.addControl('output-strategy', new UntypedFormControl());
-    this.collectedPropertiesFirstStream = this.propertySelectorService
-        .makeProperties(this.getProperties(0), this.outputStrategy.availablePropertyKeys, this.propertySelectorService.firstStreamPrefix);
-    this.collectedPropertiesSecondStream = this.propertySelectorService
-        .makeProperties(this.getProperties(1), this.outputStrategy.availablePropertyKeys, this.propertySelectorService.secondStreamPrefix);
-    this.checkFormValidity();
-  }
+    ngOnInit() {
+        this.parentForm.addControl('output-strategy', new UntypedFormControl());
+        this.collectedPropertiesFirstStream =
+            this.propertySelectorService.makeProperties(
+                this.getProperties(0),
+                this.outputStrategy.availablePropertyKeys,
+                this.propertySelectorService.firstStreamPrefix,
+            );
+        this.collectedPropertiesSecondStream =
+            this.propertySelectorService.makeProperties(
+                this.getProperties(1),
+                this.outputStrategy.availablePropertyKeys,
+                this.propertySelectorService.secondStreamPrefix,
+            );
+        this.checkFormValidity();
+    }
 
-  getProperties(streamIndex) {
-    return this.selectedElement.inputStreams[streamIndex] === undefined ?
-      [] : this.selectedElement.inputStreams[streamIndex].eventSchema.eventProperties;
-  }
+    getProperties(streamIndex) {
+        return this.selectedElement.inputStreams[streamIndex] === undefined
+            ? []
+            : this.selectedElement.inputStreams[streamIndex].eventSchema
+                  .eventProperties;
+    }
 
-  selectAll(collectedProperties) {
-    collectedProperties.forEach(ep => this.outputStrategy.selectedPropertyKeys.push(ep.runtimeId));
-    // This is needed to trigger update of scope
-    this.outputStrategy.selectedPropertyKeys = this.outputStrategy.selectedPropertyKeys.filter(el => true);
-    this.checkFormValidity();
-  }
+    selectAll(collectedProperties) {
+        collectedProperties.forEach(ep =>
+            this.outputStrategy.selectedPropertyKeys.push(ep.runtimeId),
+        );
+        // This is needed to trigger update of scope
+        this.outputStrategy.selectedPropertyKeys =
+            this.outputStrategy.selectedPropertyKeys.filter(el => true);
+        this.checkFormValidity();
+    }
 
-  deselectAll(collectedProperties) {
-    collectedProperties.forEach(ep => this.outputStrategy.selectedPropertyKeys =
-        this.outputStrategy.selectedPropertyKeys.filter(item => item !== ep.runtimeId));
-    this.checkFormValidity();
-  }
+    deselectAll(collectedProperties) {
+        collectedProperties.forEach(
+            ep =>
+                (this.outputStrategy.selectedPropertyKeys =
+                    this.outputStrategy.selectedPropertyKeys.filter(
+                        item => item !== ep.runtimeId,
+                    )),
+        );
+        this.checkFormValidity();
+    }
 
-  checkFormValidity() {
-    if (!this.outputStrategy.selectedPropertyKeys || this.outputStrategy.selectedPropertyKeys.length === 0) {
-      this.parentForm.controls['output-strategy'].setErrors({});
-    } else {
-      this.parentForm.controls['output-strategy'].setErrors(undefined);
+    checkFormValidity() {
+        if (
+            !this.outputStrategy.selectedPropertyKeys ||
+            this.outputStrategy.selectedPropertyKeys.length === 0
+        ) {
+            this.parentForm.controls['output-strategy'].setErrors({});
+        } else {
+            this.parentForm.controls['output-strategy'].setErrors(undefined);
+        }
     }
-  }
 }
diff --git a/ui/src/app/editor/components/output-strategy/output-strategy.component.html b/ui/src/app/editor/components/output-strategy/output-strategy.component.html
index e208f753d..ce736ced7 100644
--- a/ui/src/app/editor/components/output-strategy/output-strategy.component.html
+++ b/ui/src/app/editor/components/output-strategy/output-strategy.component.html
@@ -22,22 +22,36 @@
             <b>Select output</b>
         </div>
         <div fxFlex="100">
-            <div class="customize-item-content"
-                 *ngIf="outputStrategy['@class'] === 'org.apache.streampipes.model.output.CustomOutputStrategy'">
-                <custom-output-strategy [outputStrategy]="outputStrategy"
-                               [selectedElement]="selectedElement"
-                               [parentForm]="parentForm"
-                               [restrictedEditMode]="restrictedEditMode">
-                </custom-output-strategy>
+            <div
+                class="customize-item-content"
+                *ngIf="
+                    outputStrategy['@class'] ===
+                    'org.apache.streampipes.model.output.CustomOutputStrategy'
+                "
+            >
+                <sp-custom-output-strategy
+                    [outputStrategy]="outputStrategy"
+                    [selectedElement]="selectedElement"
+                    [parentForm]="parentForm"
+                    [restrictedEditMode]="restrictedEditMode"
+                >
+                </sp-custom-output-strategy>
             </div>
-            <div class="customize-item-content"
-                 *ngIf="outputStrategy['@class'] === 'org.apache.streampipes.model.output.UserDefinedOutputStrategy'">
-                <user-defined-output-strategy [outputStrategy]="outputStrategy"
-                                     [selectedElement]="selectedElement"
-                                     [parentForm]="parentForm"
-                                     [restrictedEditMode]="restrictedEditMode">
-                </user-defined-output-strategy>
+            <div
+                class="customize-item-content"
+                *ngIf="
+                    outputStrategy['@class'] ===
+                    'org.apache.streampipes.model.output.UserDefinedOutputStrategy'
+                "
+            >
+                <sp-user-defined-output-strategy
+                    [outputStrategy]="outputStrategy"
+                    [selectedElement]="selectedElement"
+                    [parentForm]="parentForm"
+                    [restrictedEditMode]="restrictedEditMode"
+                >
+                </sp-user-defined-output-strategy>
             </div>
         </div>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/editor/components/output-strategy/output-strategy.component.scss b/ui/src/app/editor/components/output-strategy/output-strategy.component.scss
index e513418ca..84830c8ed 100644
--- a/ui/src/app/editor/components/output-strategy/output-strategy.component.scss
+++ b/ui/src/app/editor/components/output-strategy/output-strategy.component.scss
@@ -17,8 +17,8 @@
  */
 
 .static-property-panel {
-  border-left:5px solid gray;
-  padding-left: 10px;
-  margin-bottom: 10px;
-  margin-top: 10px;
-}
\ No newline at end of file
+    border-left: 5px solid gray;
+    padding-left: 10px;
+    margin-bottom: 10px;
+    margin-top: 10px;
+}
diff --git a/ui/src/app/editor/components/output-strategy/output-strategy.component.ts b/ui/src/app/editor/components/output-strategy/output-strategy.component.ts
index c51d716fa..634023a8a 100644
--- a/ui/src/app/editor/components/output-strategy/output-strategy.component.ts
+++ b/ui/src/app/editor/components/output-strategy/output-strategy.component.ts
@@ -17,34 +17,39 @@
  */
 
 import { Component, Input, OnInit } from '@angular/core';
-import { DataProcessorInvocation, OutputStrategy } from '@streampipes/platform-services';
+import {
+    DataProcessorInvocation,
+    OutputStrategy,
+} from '@streampipes/platform-services';
 import { UntypedFormGroup } from '@angular/forms';
 
 @Component({
-  selector: 'output-strategy',
-  templateUrl: './output-strategy.component.html',
-  styleUrls: ['./output-strategy.component.scss']
+    selector: 'sp-output-strategy',
+    templateUrl: './output-strategy.component.html',
+    styleUrls: ['./output-strategy.component.scss'],
 })
 export class OutputStrategyComponent implements OnInit {
+    @Input()
+    parentForm: UntypedFormGroup;
 
-  @Input()
-  parentForm: UntypedFormGroup;
+    @Input()
+    outputStrategy: OutputStrategy;
 
-  @Input()
-  outputStrategy: OutputStrategy;
+    @Input()
+    selectedElement: DataProcessorInvocation;
 
-  @Input()
-  selectedElement: DataProcessorInvocation;
+    @Input()
+    restrictedEditMode: boolean;
 
-  @Input()
-  restrictedEditMode: boolean;
+    label: string;
 
-  label: string;
+    customizableOutputStrategy: boolean;
 
-  customizableOutputStrategy: boolean;
-
-  ngOnInit(): void {
-    this.customizableOutputStrategy = this.outputStrategy['@class'] === 'org.apache.streampipes.model.output.CustomOutputStrategy' ||
-        this.outputStrategy['@class'] === 'org.apache.streampipes.model.output.UserDefinedOutputStrategy';
-  }
+    ngOnInit(): void {
+        this.customizableOutputStrategy =
+            this.outputStrategy['@class'] ===
+                'org.apache.streampipes.model.output.CustomOutputStrategy' ||
+            this.outputStrategy['@class'] ===
+                'org.apache.streampipes.model.output.UserDefinedOutputStrategy';
+    }
 }
diff --git a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.html b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.html
index baff41c64..6ceb0ddec 100644
--- a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.html
+++ b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.html
@@ -16,26 +16,39 @@
   ~
   -->
 
-<div class="property-selection" style="margin-left:{{layer*5}}%">
+<div class="property-selection" style="margin-left:{{ layer * 5 }}%">
     <div fxLayout="row">
-        <mat-checkbox [checked]="exists(eventProperty.runtimeId)"
-                      (change)="toggle(eventProperty.runtimeId)"
-                      style="margin-right: 10px;" [disabled]="restrictedEditMode"
-                      [attr.data-cy]="eventProperty.runtimeName">
+        <mat-checkbox
+            [checked]="exists(eventProperty.runtimeId)"
+            (change)="toggle(eventProperty.runtimeId)"
+            style="margin-right: 10px"
+            [disabled]="restrictedEditMode"
+            [attr.data-cy]="eventProperty.runtimeName"
+        >
         </mat-checkbox>
         <div>
-            <div *ngIf="eventProperty.label"><b>{{eventProperty.label}}</b><br/>
-                <mat-hint class="description">{{eventProperty.description}},
-                    field name: {{eventProperty.runtimeName}}</mat-hint>
-                <br/></div>
-            <div *ngIf="!eventProperty.label"><b>{{eventProperty.runtimeName}}</b><br/>
+            <div *ngIf="eventProperty.label">
+                <b>{{ eventProperty.label }}</b
+                ><br />
+                <mat-hint class="description"
+                    >{{ eventProperty.description }}, field name:
+                    {{ eventProperty.runtimeName }}</mat-hint
+                >
+                <br />
+            </div>
+            <div *ngIf="!eventProperty.label">
+                <b>{{ eventProperty.runtimeName }}</b
+                ><br />
             </div>
         </div>
     </div>
 </div>
 <div *ngIf="isNestedProperty">
     <div *ngFor="let nestedProperty of eventProperty.eventProperties">
-        <property-selection [outputStrategy]="outputStrategy" [eventProperty]="nestedProperty"
-                            [layer]="(layer + 1)"></property-selection>
+        <sp-property-selection
+            [outputStrategy]="outputStrategy"
+            [eventProperty]="nestedProperty"
+            [layer]="layer + 1"
+        ></sp-property-selection>
     </div>
 </div>
diff --git a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.scss b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.scss
index ad64fae11..440a058e0 100644
--- a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.scss
+++ b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.scss
@@ -17,5 +17,5 @@
  */
 
 .description {
-  font-size: 10px;
-}
\ No newline at end of file
+    font-size: 10px;
+}
diff --git a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.ts b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.ts
index b3623c4d6..b04615b67 100644
--- a/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.ts
+++ b/ui/src/app/editor/components/output-strategy/property-selection/property-selection.component.ts
@@ -18,63 +18,69 @@
 
 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
 import {
-  CustomOutputStrategy,
-  EventPropertyNested,
-  EventPropertyUnion
+    CustomOutputStrategy,
+    EventPropertyNested,
+    EventPropertyUnion,
 } from '@streampipes/platform-services';
 
 @Component({
-  selector: 'property-selection',
-  templateUrl: './property-selection.component.html',
-  styleUrls: ['./property-selection.component.scss']
+    selector: 'sp-property-selection',
+    templateUrl: './property-selection.component.html',
+    styleUrls: ['./property-selection.component.scss'],
 })
 export class PropertySelectionComponent implements OnInit {
+    @Input()
+    outputStrategy: CustomOutputStrategy;
 
-  @Input()
-  outputStrategy: CustomOutputStrategy;
+    @Input()
+    eventProperty: EventPropertyUnion;
 
-  @Input()
-  eventProperty: EventPropertyUnion;
+    @Input()
+    layer: number;
 
-  @Input()
-  layer: number;
+    @Input()
+    restrictedEditMode: boolean;
 
-  @Input()
-  restrictedEditMode: boolean;
+    @Output()
+    validateForm: EventEmitter<boolean> = new EventEmitter<boolean>();
 
-  @Output()
-  validateForm: EventEmitter<boolean> = new EventEmitter<boolean>();
+    isNestedProperty: boolean;
 
-  isNestedProperty: boolean;
-
-  ngOnInit() {
-    this.isNestedProperty = this.eventProperty instanceof EventPropertyNested;
-  }
+    ngOnInit() {
+        this.isNestedProperty =
+            this.eventProperty instanceof EventPropertyNested;
+    }
 
-  toggle(runtimeId) {
-    if (this.exists(runtimeId)) {
-      this.remove(runtimeId);
-    } else {
-      this.add(runtimeId);
+    toggle(runtimeId) {
+        if (this.exists(runtimeId)) {
+            this.remove(runtimeId);
+        } else {
+            this.add(runtimeId);
+        }
+        this.triggerFormValidation();
     }
-    this.triggerFormValidation();
-  }
 
-  exists(runtimeId) {
-    return this.outputStrategy.selectedPropertyKeys.some(e => e === runtimeId);
-  }
+    exists(runtimeId) {
+        return this.outputStrategy.selectedPropertyKeys.some(
+            e => e === runtimeId,
+        );
+    }
 
-  add(runtimeId) {
-    this.outputStrategy.selectedPropertyKeys.push(runtimeId);
-    // This is needed to trigger update of scope
-    this.outputStrategy.selectedPropertyKeys = this.outputStrategy.selectedPropertyKeys.filter(el => true);
-  }
+    add(runtimeId) {
+        this.outputStrategy.selectedPropertyKeys.push(runtimeId);
+        // This is needed to trigger update of scope
+        this.outputStrategy.selectedPropertyKeys =
+            this.outputStrategy.selectedPropertyKeys.filter(el => true);
+    }
 
-  remove(runtimeId) {
-    this.outputStrategy.selectedPropertyKeys =  this.outputStrategy.selectedPropertyKeys.filter(el => el !== runtimeId);
-  }
+    remove(runtimeId) {
+        this.outputStrategy.selectedPropertyKeys =
+            this.outputStrategy.selectedPropertyKeys.filter(
+                el => el !== runtimeId,
+            );
+    }
 
-  triggerFormValidation() {
-    this.validateForm.emit(true);
-  }
+    triggerFormValidation() {
+        this.validateForm.emit(true);
+    }
 }
diff --git a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
index 17b383880..918c5f389 100644
--- a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
+++ b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
@@ -17,33 +17,55 @@
   -->
 
 <div fxFlex="100" fxLayout="column">
-    <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" style="margin-bottom:20px;">
-        <button mat-button mat-raised-button color="accent" class="small-button"
-                (click)="applyDefaultSchema()"
-                style="margin-right:10px;margin-left:10px;"
-                [disabled]="restrictedEditMode"
-                data-cy="use-input-schema">Use input schema
+    <div
+        fxFlex="100"
+        fxLayout="row"
+        fxLayoutAlign="start center"
+        style="margin-bottom: 20px"
+    >
+        <button
+            mat-button
+            mat-raised-button
+            color="accent"
+            class="small-button"
+            (click)="applyDefaultSchema()"
+            style="margin-right: 10px; margin-left: 10px"
+            [disabled]="restrictedEditMode"
+            data-cy="use-input-schema"
+        >
+            Use input schema
         </button>
     </div>
 
-    <div fxFlex="100" fxLayout="row" *ngFor="let ep of outputStrategy.eventProperties; let i = index">
+    <div
+        fxFlex="100"
+        fxLayout="row"
+        *ngFor="let ep of outputStrategy.eventProperties; let i = index"
+    >
         <div fxLayout="column" fxFlex="30">
             <mat-form-field fxFlex>
                 <mat-label>Runtime name</mat-label>
-                <input [(ngModel)]="ep.runtimeName"
-                       data-cy="runtime-name"
-                       fxFlex
-                       matInput>
+                <input
+                    [(ngModel)]="ep.runtimeName"
+                    data-cy="runtime-name"
+                    fxFlex
+                    matInput
+                />
             </mat-form-field>
         </div>
         <div fxLayout="column" fxFlex="30">
             <mat-form-field class="example-full-width">
                 <mat-label>Runtime type</mat-label>
-                <mat-select [(ngModel)]="ep.runtimeType"
-                            [disabled]="restrictedEditMode"
-                            data-cy="runtime-type">
-                    <mat-option *ngFor="let primitive of primitiveClasses" [value]="primitive.id">
-                        {{primitive.label}}
+                <mat-select
+                    [(ngModel)]="ep.runtimeType"
+                    [disabled]="restrictedEditMode"
+                    data-cy="runtime-type"
+                >
+                    <mat-option
+                        *ngFor="let primitive of primitiveClasses"
+                        [value]="primitive.id"
+                    >
+                        {{ primitive.label }}
                     </mat-option>
                 </mat-select>
             </mat-form-field>
@@ -51,25 +73,34 @@
         <div fxLayout="column" fxFlex="30">
             <mat-form-field fxFlex>
                 <mat-label>Semantic type</mat-label>
-                <input [(ngModel)]="ep.domainProperties[0]"
-                       [disabled]="restrictedEditMode"
-                       data-cy="semantic-type"
-                       fxFlex
-                       matInput>
+                <input
+                    [(ngModel)]="ep.domainProperties[0]"
+                    [disabled]="restrictedEditMode"
+                    data-cy="semantic-type"
+                    fxFlex
+                    matInput
+                />
             </mat-form-field>
         </div>
         <div fxLayout="column" fxFlex="10">
-            <button mat-icon-button class="icon-button" (click)="removeProperty(ep)" [disabled]="restrictedEditMode">
+            <button
+                mat-icon-button
+                class="icon-button"
+                (click)="removeProperty(ep)"
+                [disabled]="restrictedEditMode"
+            >
                 <mat-icon class="icon">remove</mat-icon>
             </button>
         </div>
     </div>
     <div>
-        <button mat-button
-                mat-flat-button
-                (click)="addProperty()"
-                [disabled]="restrictedEditMode"
-                data-cy="add-field">
+        <button
+            mat-button
+            mat-flat-button
+            (click)="addProperty()"
+            [disabled]="restrictedEditMode"
+            data-cy="add-field"
+        >
             <mat-icon class="icon">add</mat-icon>
             <span>Add field</span>
         </button>
diff --git a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.scss b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.scss
index 58ba04bdd..13cbc4aac 100644
--- a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.scss
+++ b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.scss
@@ -15,4 +15,3 @@
  * limitations under the License.
  *
  */
-
diff --git a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
index 2207b42f4..737c8db9a 100644
--- a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
+++ b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
@@ -19,84 +19,99 @@
 import { Component, OnInit } from '@angular/core';
 import { BaseOutputStrategy } from '../base/BaseOutputStrategy';
 import {
-  EventPropertyPrimitive,
-  UserDefinedOutputStrategy
+    EventPropertyPrimitive,
+    UserDefinedOutputStrategy,
 } from '@streampipes/platform-services';
 import { UntypedFormControl } from '@angular/forms';
 
 @Component({
-  selector: 'user-defined-output-strategy',
-  templateUrl: './user-defined-output.component.html',
-  styleUrls: ['./user-defined-output.component.scss']
+    selector: 'sp-user-defined-output-strategy',
+    templateUrl: './user-defined-output.component.html',
+    styleUrls: ['./user-defined-output.component.scss'],
 })
-export class UserDefinedOutputStrategyComponent extends BaseOutputStrategy<UserDefinedOutputStrategy> implements OnInit {
+export class UserDefinedOutputStrategyComponent
+    extends BaseOutputStrategy<UserDefinedOutputStrategy>
+    implements OnInit
+{
+    private prefix = 'urn:streampipes.org:spi:';
+    private chars =
+        '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 
-  private prefix = 'urn:streampipes.org:spi:';
-  private chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+    collectedPropertiesFirstStream: any;
+    collectedPropertiesSecondStream: any;
 
-  collectedPropertiesFirstStream: any;
-  collectedPropertiesSecondStream: any;
+    primitiveClasses = [
+        { label: 'String', id: 'http://www.w3.org/2001/XMLSchema#string' },
+        { label: 'Boolean', id: 'http://www.w3.org/2001/XMLSchema#boolean' },
+        { label: 'Integer', id: 'http://www.w3.org/2001/XMLSchema#integer' },
+        { label: 'Long', id: 'http://www.w3.org/2001/XMLSchema#long' },
+        { label: 'Double', id: 'http://www.w3.org/2001/XMLSchema#double' },
+        { label: 'Float', id: 'http://www.w3.org/2001/XMLSchema#float' },
+    ];
 
-  primitiveClasses = [{'label': 'String', 'id': 'http://www.w3.org/2001/XMLSchema#string'},
-    {'label': 'Boolean', 'id': 'http://www.w3.org/2001/XMLSchema#boolean'},
-    {'label': 'Integer', 'id': 'http://www.w3.org/2001/XMLSchema#integer'},
-    {'label': 'Long', 'id': 'http://www.w3.org/2001/XMLSchema#long'},
-    {'label': 'Double', 'id': 'http://www.w3.org/2001/XMLSchema#double'},
-    {'label': 'Float', 'id': 'http://www.w3.org/2001/XMLSchema#float'}];
-
-  constructor() {
-    super();
-  }
+    constructor() {
+        super();
+    }
 
-  ngOnInit() {
-    this.parentForm.addControl('output-strategy', new UntypedFormControl());
-    if (!this.outputStrategy.eventProperties) {
-      this.outputStrategy.eventProperties = [];
+    ngOnInit() {
+        this.parentForm.addControl('output-strategy', new UntypedFormControl());
+        if (!this.outputStrategy.eventProperties) {
+            this.outputStrategy.eventProperties = [];
+        }
+        this.checkFormValidity();
     }
-    this.checkFormValidity();
-  }
 
-  applyDefaultSchema() {
-    this.outputStrategy.eventProperties =
-        [...this.selectedElement.inputStreams[0].eventSchema.eventProperties];
-    this.checkFormValidity();
-  }
+    applyDefaultSchema() {
+        this.outputStrategy.eventProperties = [
+            ...this.selectedElement.inputStreams[0].eventSchema.eventProperties,
+        ];
+        this.checkFormValidity();
+    }
 
-  removeProperty(ep: any) {
-    this.outputStrategy.eventProperties
-        .splice(this.outputStrategy.eventProperties.indexOf(ep), 1);
-    this.checkFormValidity();
-  }
+    removeProperty(ep: any) {
+        this.outputStrategy.eventProperties.splice(
+            this.outputStrategy.eventProperties.indexOf(ep),
+            1,
+        );
+        this.checkFormValidity();
+    }
 
-  addProperty() {
-    this.outputStrategy.eventProperties.push(this.makeDefaultProperty());
-    this.checkFormValidity();
-  }
+    addProperty() {
+        this.outputStrategy.eventProperties.push(this.makeDefaultProperty());
+        this.checkFormValidity();
+    }
 
-  makeDefaultProperty() {
-    const ep = {} as EventPropertyPrimitive;
-    ep['@class'] = 'org.apache.streampipes.model.schema.EventPropertyPrimitive';
-    ep.domainProperties = [];
-    ep.elementId = 'urn:streampipes.org:spi:eventpropertyprimitive:' + this.makeId();
+    makeDefaultProperty() {
+        const ep = {} as EventPropertyPrimitive;
+        ep['@class'] =
+            'org.apache.streampipes.model.schema.EventPropertyPrimitive';
+        ep.domainProperties = [];
+        ep.elementId =
+            'urn:streampipes.org:spi:eventpropertyprimitive:' + this.makeId();
 
-    return ep;
-  }
+        return ep;
+    }
 
-  makeId() {
-    return this.prefix + this.randomString(6);
-  }
+    makeId() {
+        return this.prefix + this.randomString(6);
+    }
 
-  randomString(length) {
-    let result = '';
-    for (let i = length; i > 0; --i) { result += this.chars[Math.floor(Math.random() * this.chars.length)]; }
-    return result;
-  }
+    randomString(length) {
+        let result = '';
+        for (let i = length; i > 0; --i) {
+            result += this.chars[Math.floor(Math.random() * this.chars.length)];
+        }
+        return result;
+    }
 
-  checkFormValidity() {
-    if (!this.outputStrategy.eventProperties || this.outputStrategy.eventProperties.length === 0) {
-      this.parentForm.controls['output-strategy'].setErrors({});
-    } else {
-      this.parentForm.controls['output-strategy'].setErrors(undefined);
+    checkFormValidity() {
+        if (
+            !this.outputStrategy.eventProperties ||
+            this.outputStrategy.eventProperties.length === 0
+        ) {
+            this.parentForm.controls['output-strategy'].setErrors({});
+        } else {
+            this.parentForm.controls['output-strategy'].setErrors(undefined);
+        }
     }
-  }
 }
diff --git a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.html b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.html
index 4e39a963d..6cc1bc621 100644
--- a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.html
+++ b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.html
@@ -19,13 +19,17 @@
 <div fxFlex="100" fxLayout="column">
     <div class="pipeline-assembly-options sp-bg-lightgray page-container-nav">
         <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center">
-            <button mat-button
-                    mat-raised-button
-                    color="accent"
-                    matTooltip="Save Pipeline" [matTooltipPosition]="'above'"
-                    [disabled]="!pipelineValidationService.pipelineValid"
-                    (click)="submit()" type="submit"
-                    data-cy="sp-editor-save-pipeline">
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                matTooltip="Save Pipeline"
+                [matTooltipPosition]="'above'"
+                [disabled]="!pipelineValidationService.pipelineValid"
+                (click)="submit()"
+                type="submit"
+                data-cy="sp-editor-save-pipeline"
+            >
                 <div fxLayoutAlign="start center" fxLayout="row">
                     <i class="material-icons">save</i>
                     <span>&nbsp;Save pipeline</span>
@@ -43,50 +47,88 @@
             <!--                    (click)="toggleSelectMode()">-->
             <!--                <i class="material-icons">mode_edit</i>-->
             <!--            </button>-->
-            <button mat-button
-                    color="accent"
-                    matTooltip="Data Preview"
-                    [matTooltipPosition]="'above'"
-                    (click)="triggerPipelinePreview()" [disabled]="isPipelineAssemblyEmpty()">
+            <button
+                mat-button
+                color="accent"
+                matTooltip="Data Preview"
+                [matTooltipPosition]="'above'"
+                (click)="triggerPipelinePreview()"
+                [disabled]="isPipelineAssemblyEmpty()"
+            >
                 <div fxLayoutAlign="start center" fxLayout="row">
                     <i class="material-icons">visibility</i>
-                    <span *ngIf="!pipelineComponent.previewModeActive">&nbsp;Enable live preview</span>
-                    <span *ngIf="pipelineComponent.previewModeActive">&nbsp;Disable live preview</span>
+                    <span *ngIf="!pipelineComponent.previewModeActive"
+                        >&nbsp;Enable live preview</span
+                    >
+                    <span *ngIf="pipelineComponent.previewModeActive"
+                        >&nbsp;Disable live preview</span
+                    >
                 </div>
             </button>
             <span class="assembly-options-divider"></span>
-            <button mat-button
-                    color="accent"
-                    mat-icon-button
-                    matTooltip="Auto Layout" [matTooltipPosition]="'above'"
-                    (click)="autoLayout()">
+            <button
+                mat-button
+                color="accent"
+                mat-icon-button
+                matTooltip="Auto Layout"
+                [matTooltipPosition]="'above'"
+                (click)="autoLayout()"
+            >
                 <i class="material-icons">settings_overscan</i>
             </button>
-            <button mat-button
-                    color="accent"
-                    mat-icon-button
-                    matTooltip="Add pipeline element" [matTooltipPosition]="'above'"
-                    (click)="openDiscoverDialog()"
-                    data-cy="sp-editor-add-pipeline-element">
+            <button
+                mat-button
+                color="accent"
+                mat-icon-button
+                matTooltip="Add pipeline element"
+                [matTooltipPosition]="'above'"
+                (click)="openDiscoverDialog()"
+                data-cy="sp-editor-add-pipeline-element"
+            >
                 <i class="material-icons">add</i>
             </button>
-            <div fxLayout="column" fxLayoutAlign="start center" class="pipeline-cache-block">
-                <div fxFlex="100" fxLayoutAlign="start center" fxLayout="row"
-                     *ngIf="pipelineCached || pipelineCacheRunning">
-                    <div *ngIf="pipelineCached" fxLayout="row" fxLayoutAlign="start center">
-                        <mat-spinner [mode]="'indeterminate'" class="mat-spinner-color" [diameter]="15"
-                                     *ngIf="pipelineCacheRunning"></mat-spinner>
-                        <span>&nbsp;{{pipelineCacheRunning ? '&nbsp;Saving pipeline modifications' : 'All pipeline modifications saved.'}}</span>
+            <div
+                fxLayout="column"
+                fxLayoutAlign="start center"
+                class="pipeline-cache-block"
+            >
+                <div
+                    fxFlex="100"
+                    fxLayoutAlign="start center"
+                    fxLayout="row"
+                    *ngIf="pipelineCached || pipelineCacheRunning"
+                >
+                    <div
+                        *ngIf="pipelineCached"
+                        fxLayout="row"
+                        fxLayoutAlign="start center"
+                    >
+                        <mat-spinner
+                            [mode]="'indeterminate'"
+                            class="mat-spinner-color"
+                            [diameter]="15"
+                            *ngIf="pipelineCacheRunning"
+                        ></mat-spinner>
+                        <span
+                            >&nbsp;{{
+                                pipelineCacheRunning
+                                    ? '&nbsp;Saving pipeline modifications'
+                                    : 'All pipeline modifications saved.'
+                            }}</span
+                        >
                     </div>
                 </div>
             </div>
             <span fxFlex></span>
-            <button mat-button
-                    color="accent"
-                    mat-icon-button matTooltip="Clear Assembly Area"
-                    [matTooltipPosition]="'above'"
-                    [disabled]="editorService.pipelineAssemblyEmpty"
-                    (click)="showClearAssemblyConfirmDialog($event)">
+            <button
+                mat-button
+                color="accent"
+                mat-icon-button
+                matTooltip="Clear Assembly Area"
+                [matTooltipPosition]="'above'"
+                [disabled]="editorService.pipelineAssemblyEmpty"
+                (click)="showClearAssemblyConfirmDialog($event)"
+            >
                 <i class="material-icons">clear</i>
             </button>
         </div>
@@ -95,9 +137,10 @@
         <div class="pipeline-canvas-outer" #outerCanvas>
             <div class="pipeline-validation-hint">
                 <sp-error-hint
-                        [displayMessages]="!isPipelineAssemblyEmpty()"
-                        [errorMessages]="pipelineValidationService.errorMessages"
-                        [validationString]="'Pipeline'">
+                    [displayMessages]="!isPipelineAssemblyEmpty()"
+                    [errorMessages]="pipelineValidationService.errorMessages"
+                    [validationString]="'Pipeline'"
+                >
                 </sp-error-hint>
             </div>
             <div class="pan-control">
@@ -130,20 +173,23 @@
                     </div>
                 </div>
             </div>
-            <pipeline class="canvas jtk-surface" id="assembly"
-                      #pipelineComponent
-                      [pipelineValid]="pipelineValid"
-                      [canvasId]="'assembly'"
-                      [rawPipelineModel]="rawPipelineModel"
-                      [allElements]="allElements"
-                      [preview]="false"
-                      [pipelineCached]="pipelineCached"
-                      [pipelineCanvasMetadata]="pipelineCanvasMetadata"
-                      [pipelineCacheRunning]="pipelineCacheRunning"
-                      (pipelineCachedChanged)="pipelineCached=$event"
-                      (pipelineCacheRunningChanged)="pipelineCacheRunning=$event" style="position:absolute;">
+            <pipeline
+                class="canvas jtk-surface"
+                id="assembly"
+                #pipelineComponent
+                [pipelineValid]="pipelineValid"
+                [canvasId]="'assembly'"
+                [rawPipelineModel]="rawPipelineModel"
+                [allElements]="allElements"
+                [preview]="false"
+                [pipelineCached]="pipelineCached"
+                [pipelineCanvasMetadata]="pipelineCanvasMetadata"
+                [pipelineCacheRunning]="pipelineCacheRunning"
+                (pipelineCachedChanged)="pipelineCached = $event"
+                (pipelineCacheRunningChanged)="pipelineCacheRunning = $event"
+                style="position: absolute"
+            >
             </pipeline>
-
         </div>
     </div>
 </div>
diff --git a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.scss b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.scss
index 52b217d9c..df77313f0 100644
--- a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.scss
+++ b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.scss
@@ -18,17 +18,17 @@
 
 @import '../../../../scss/_variables.scss';
 
-.mat-spinner-color::ng-deep svg circle{
+.mat-spinner-color::ng-deep svg circle {
     stroke: var(--color-accent) !important;
 }
 
 .pipeline-cache-progress {
-    display:inline-block;
+    display: inline-block;
 }
 
 .pipeline-cache-block {
     height: 100%;
-    margin-left:15px;
+    margin-left: 15px;
 }
 
 .outerAssembly {
@@ -76,7 +76,7 @@
 
 .jtk-surface-nopan {
     overflow: scroll !important;
-    cursor:default;
+    cursor: default;
 }
 
 .zoom-control {
@@ -89,7 +89,6 @@
     background: var(--color-bg-1);
     box-shadow: 0.175em 0.175em 0 0 rgba(15, 28, 63, 0.125);
     border-radius: 10px;
-
 }
 
 .pipeline-validation-hint {
@@ -174,5 +173,3 @@
 .color-warn {
     color: var(--color-warn);
 }
-
-
diff --git a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
index edf8e0db5..7507ffd11 100644
--- a/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
+++ b/ui/src/app/editor/components/pipeline-assembly/pipeline-assembly.component.ts
@@ -32,13 +32,25 @@ import { PipelinePositioningService } from '../../services/pipeline-positioning.
 import { PipelineValidationService } from '../../services/pipeline-validation.service';
 import { JsplumbService } from '../../services/jsplumb.service';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
-import { PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import {
+    PipelineElementConfig,
+    PipelineElementUnion,
+} from '../../model/editor.model';
 import { ObjectProvider } from '../../services/object-provider.service';
-import { ConfirmDialogComponent, DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui';
+import {
+    ConfirmDialogComponent,
+    DialogService,
+    PanelType,
+    SpBreadcrumbService,
+} from '@streampipes/shared-ui';
 import { SavePipelineComponent } from '../../dialog/save-pipeline/save-pipeline.component';
 import { MatDialog } from '@angular/material/dialog';
 import { EditorService } from '../../services/editor.service';
-import { PipelineCanvasMetadata, PipelineCanvasMetadataService, PipelineService } from '@streampipes/platform-services';
+import {
+    PipelineCanvasMetadata,
+    PipelineCanvasMetadataService,
+    PipelineService,
+} from '@streampipes/platform-services';
 import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
 import Panzoom, { PanzoomObject } from '@panzoom/panzoom';
 import { PipelineElementDraggedService } from '../../services/pipeline-element-dragged.service';
@@ -48,14 +60,12 @@ import { PipelineElementDiscoveryComponent } from '../../dialog/pipeline-element
 import { SpPipelineRoutes } from '../../../pipelines/pipelines.routes';
 import { Router } from '@angular/router';
 
-
 @Component({
-    selector: 'pipeline-assembly',
+    selector: 'sp-pipeline-assembly',
     templateUrl: './pipeline-assembly.component.html',
-    styleUrls: ['./pipeline-assembly.component.scss']
+    styleUrls: ['./pipeline-assembly.component.scss'],
 })
 export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
-
     @Input()
     rawPipelineModel: PipelineElementConfig[];
 
@@ -66,7 +76,8 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
     allElements: PipelineElementUnion[];
 
     @Output()
-    pipelineCanvasMaximizedEmitter: EventEmitter<boolean> = new EventEmitter<boolean>();
+    pipelineCanvasMaximizedEmitter: EventEmitter<boolean> =
+        new EventEmitter<boolean>();
 
     JsplumbBridge: JsplumbBridge;
 
@@ -85,7 +96,8 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
     pipelineCacheRunning = false;
     pipelineCached = false;
 
-    pipelineCanvasMetadata: PipelineCanvasMetadata = new PipelineCanvasMetadata();
+    pipelineCanvasMetadata: PipelineCanvasMetadata =
+        new PipelineCanvasMetadata();
     pipelineCanvasMetadataAvailable = false;
 
     config: any = {};
@@ -96,22 +108,23 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
 
     panzoom: PanzoomObject;
 
-    constructor(private jsPlumbFactoryService: JsplumbFactoryService,
-                private pipelinePositioningService: PipelinePositioningService,
-                private objectProvider: ObjectProvider,
-                public editorService: EditorService,
-                public pipelineValidationService: PipelineValidationService,
-                private pipelineService: PipelineService,
-                private jsplumbService: JsplumbService,
-                private shepherdService: ShepherdService,
-                private dialogService: DialogService,
-                private dialog: MatDialog,
-                private ngZone: NgZone,
-                private pipelineElementDraggedService: PipelineElementDraggedService,
-                private pipelineCanvasMetadataService: PipelineCanvasMetadataService,
-                private breadcrumbService: SpBreadcrumbService,
-                private router: Router) {
-
+    constructor(
+        private jsPlumbFactoryService: JsplumbFactoryService,
+        private pipelinePositioningService: PipelinePositioningService,
+        private objectProvider: ObjectProvider,
+        public editorService: EditorService,
+        public pipelineValidationService: PipelineValidationService,
+        private pipelineService: PipelineService,
+        private jsplumbService: JsplumbService,
+        private shepherdService: ShepherdService,
+        private dialogService: DialogService,
+        private dialog: MatDialog,
+        private ngZone: NgZone,
+        private pipelineElementDraggedService: PipelineElementDraggedService,
+        private pipelineCanvasMetadataService: PipelineCanvasMetadataService,
+        private breadcrumbService: SpBreadcrumbService,
+        private router: Router,
+    ) {
         this.selectMode = true;
         this.currentZoomLevel = 1;
     }
@@ -122,37 +135,48 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
         } else {
             this.checkAndDisplayCachedPipeline();
         }
-        this.pipelineElementDraggedService.pipelineElementMovedSubject.subscribe(position => {
-            const offsetHeight = this.pipelineCanvas.nativeElement.offsetHeight;
-            const offsetWidth = this.pipelineCanvas.nativeElement.offsetWidth;
-            const currentPan = this.panzoom.getPan();
-            let xOffset = 0;
-            let yOffset = 0;
-            if ((position.y + currentPan.y) > (offsetHeight - 100)) {
-              yOffset = -10;
-            }
-            if ((position.x + currentPan.x) > (offsetWidth - 100)) {
-              xOffset = -10;
-            }
-            if (xOffset < 0 || yOffset < 0) {
-              this.pan(xOffset, yOffset);
-            }
-        });
+        this.pipelineElementDraggedService.pipelineElementMovedSubject.subscribe(
+            position => {
+                const offsetHeight =
+                    this.pipelineCanvas.nativeElement.offsetHeight;
+                const offsetWidth =
+                    this.pipelineCanvas.nativeElement.offsetWidth;
+                const currentPan = this.panzoom.getPan();
+                let xOffset = 0;
+                let yOffset = 0;
+                if (position.y + currentPan.y > offsetHeight - 100) {
+                    yOffset = -10;
+                }
+                if (position.x + currentPan.x > offsetWidth - 100) {
+                    xOffset = -10;
+                }
+                if (xOffset < 0 || yOffset < 0) {
+                    this.pan(xOffset, yOffset);
+                }
+            },
+        );
     }
 
     ngAfterViewInit() {
-        this.JsplumbBridge = this.jsPlumbFactoryService.getJsplumbBridge(this.preview);
+        this.JsplumbBridge = this.jsPlumbFactoryService.getJsplumbBridge(
+            this.preview,
+        );
         const elem = document.getElementById('assembly');
         this.panzoom = Panzoom(elem, {
             maxScale: 5,
             excludeClass: 'sp-no-pan',
             canvas: true,
-            contain: 'outside'
+            contain: 'outside',
         });
     }
 
     autoLayout() {
-        this.pipelinePositioningService.layoutGraph('#assembly', 'div[id^=\'jsplumb\']', 110, false);
+        this.pipelinePositioningService.layoutGraph(
+            '#assembly',
+            "div[id^='jsplumb']",
+            110,
+            false,
+        );
         this.JsplumbBridge.repaintEverything();
     }
 
@@ -175,11 +199,11 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
         const dialogRef = this.dialog.open(ConfirmDialogComponent, {
             width: '500px',
             data: {
-                'title': 'Do you really want to delete the current pipeline?',
-                'subtitle': 'This cannot be undone.',
-                'cancelTitle': 'No',
-                'okTitle': 'Yes',
-                'confirmAndCancel': true
+                title: 'Do you really want to delete the current pipeline?',
+                subtitle: 'This cannot be undone.',
+                cancelTitle: 'No',
+                okTitle: 'Yes',
+                confirmAndCancel: true,
             },
         });
         dialogRef.afterClosed().subscribe(ev => {
@@ -204,9 +228,14 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
         this.JsplumbBridge.setZoom(this.currentZoomLevel);
         this.JsplumbBridge.repaintEverything();
 
-        const removePipelineFromCache = this.editorService.removePipelineFromCache();
-        const removeCanvasMetadataFromCache = this.editorService.removeCanvasMetadataFromCache();
-        forkJoin([removePipelineFromCache, removeCanvasMetadataFromCache]).subscribe(msg => {
+        const removePipelineFromCache =
+            this.editorService.removePipelineFromCache();
+        const removeCanvasMetadataFromCache =
+            this.editorService.removeCanvasMetadataFromCache();
+        forkJoin([
+            removePipelineFromCache,
+            removeCanvasMetadataFromCache,
+        ]).subscribe(msg => {
             this.pipelineCached = false;
             this.pipelineCacheRunning = false;
         });
@@ -218,7 +247,10 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
     submit() {
         const pipelineModel = this.pipelineComponent.rawPipelineModel;
         const pipeline = this.objectProvider.makeFinalPipeline(pipelineModel);
-        this.pipelinePositioningService.collectPipelineElementPositions(this.pipelineCanvasMetadata, pipelineModel);
+        this.pipelinePositioningService.collectPipelineElementPositions(
+            this.pipelineCanvasMetadata,
+            pipelineModel,
+        );
         pipeline.name = this.currentPipelineName;
         pipeline.description = this.currentPipelineDescription;
         if (this.currentModifiedPipelineId) {
@@ -229,16 +261,17 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
             panelType: PanelType.SLIDE_IN_PANEL,
             title: 'Save pipeline',
             data: {
-                'pipeline': pipeline,
-                'currentModifiedPipelineId': this.currentModifiedPipelineId,
-                'pipelineCanvasMetadata': this.pipelineCanvasMetadata
-            }
+                pipeline: pipeline,
+                currentModifiedPipelineId: this.currentModifiedPipelineId,
+                pipelineCanvasMetadata: this.pipelineCanvasMetadata,
+            },
         });
     }
 
     checkAndDisplayCachedPipeline() {
         const cachedPipeline = this.editorService.getCachedPipeline();
-        const cachedCanvasMetadata = this.editorService.getCachedPipelineCanvasMetadata();
+        const cachedCanvasMetadata =
+            this.editorService.getCachedPipelineCanvasMetadata();
         forkJoin([cachedPipeline, cachedCanvasMetadata]).subscribe(results => {
             if (results[0] && results[0].length > 0) {
                 this.rawPipelineModel = results[0] as PipelineElementConfig[];
@@ -248,20 +281,35 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
     }
 
     displayPipelineById() {
-        const pipelineRequest = this.pipelineService.getPipelineById(this.currentModifiedPipelineId);
-        const canvasRequest = this.pipelineCanvasMetadataService.getPipelineCanvasMetadata(this.currentModifiedPipelineId);
+        const pipelineRequest = this.pipelineService.getPipelineById(
+            this.currentModifiedPipelineId,
+        );
+        const canvasRequest =
+            this.pipelineCanvasMetadataService.getPipelineCanvasMetadata(
+                this.currentModifiedPipelineId,
+            );
         pipelineRequest.subscribe(pipelineResp => {
-                const pipeline = pipelineResp;
-                this.currentPipelineName = pipeline.name;
-                this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: pipeline.name}, {label: 'Modify'}]);
-                this.currentPipelineDescription = pipeline.description;
-                this.rawPipelineModel = this.jsplumbService.makeRawPipeline(pipeline, false);
-                canvasRequest.subscribe(canvasResp => {
+            const pipeline = pipelineResp;
+            this.currentPipelineName = pipeline.name;
+            this.breadcrumbService.updateBreadcrumb([
+                SpPipelineRoutes.BASE,
+                { label: pipeline.name },
+                { label: 'Modify' },
+            ]);
+            this.currentPipelineDescription = pipeline.description;
+            this.rawPipelineModel = this.jsplumbService.makeRawPipeline(
+                pipeline,
+                false,
+            );
+            canvasRequest.subscribe(
+                canvasResp => {
                     this.handleCanvasMetadataResponse(canvasResp);
-                }, error => {
+                },
+                error => {
                     this.handleCanvasMetadataResponse(undefined);
-                });
-            });
+                },
+            );
+        });
     }
 
     handleCanvasMetadataResponse(canvasMetadata: PipelineCanvasMetadata) {
@@ -272,25 +320,43 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
             this.pipelineCanvasMetadataAvailable = false;
             this.pipelineCanvasMetadata = new PipelineCanvasMetadata();
         }
-        this.displayPipelineInEditor(!this.pipelineCanvasMetadataAvailable, this.pipelineCanvasMetadata);
+        this.displayPipelineInEditor(
+            !this.pipelineCanvasMetadataAvailable,
+            this.pipelineCanvasMetadata,
+        );
     }
 
-    displayPipelineInEditor(autoLayout,
-                            pipelineCanvasMetadata?: PipelineCanvasMetadata) {
+    displayPipelineInEditor(
+        autoLayout,
+        pipelineCanvasMetadata?: PipelineCanvasMetadata,
+    ) {
         setTimeout(() => {
-            this.pipelinePositioningService.displayPipeline(this.rawPipelineModel, '#assembly', false, autoLayout, pipelineCanvasMetadata);
+            this.pipelinePositioningService.displayPipeline(
+                this.rawPipelineModel,
+                '#assembly',
+                false,
+                autoLayout,
+                pipelineCanvasMetadata,
+            );
             this.editorService.makePipelineAssemblyEmpty(false);
             this.ngZone.run(() => {
-                this.pipelineValid = this.pipelineValidationService
-                    .isValidPipeline(this.rawPipelineModel.filter(pe => !(pe.settings.disabled)), false);
+                this.pipelineValid =
+                    this.pipelineValidationService.isValidPipeline(
+                        this.rawPipelineModel.filter(
+                            pe => !pe.settings.disabled,
+                        ),
+                        false,
+                    );
             });
             this.pipelineComponent.triggerPipelineModification();
         });
     }
 
-
     isPipelineAssemblyEmpty() {
-        return this.rawPipelineModel.length === 0 || this.rawPipelineModel.every(pe => pe.settings.disabled);
+        return (
+            this.rawPipelineModel.length === 0 ||
+            this.rawPipelineModel.every(pe => pe.settings.disabled)
+        );
     }
 
     panLeft() {
@@ -334,9 +400,9 @@ export class PipelineAssemblyComponent implements OnInit, AfterViewInit {
             title: 'Discover pipeline elements',
             width: '50vw',
             data: {
-                'currentElements': this.allElements,
-                'rawPipelineModel': this.rawPipelineModel
-            }
+                currentElements: this.allElements,
+                rawPipelineModel: this.rawPipelineModel,
+            },
         });
     }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.html b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.html
index 3cb34c9ae..ab2cf5756 100644
--- a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.html
+++ b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.html
@@ -16,9 +16,11 @@
   ~
   -->
 
-<p showdown="{{documentationMarkdown}}" *ngIf="documentationMarkdown && !error" [ngClass]="useStyling ? 'note' : ''">
-
-</p>
+<p
+    showdown="{{ documentationMarkdown }}"
+    *ngIf="documentationMarkdown && !error"
+    [ngClass]="useStyling ? 'note' : ''"
+></p>
 <p *ngIf="error" [ngClass]="useStyling ? 'note' : ''">
     (no documentation available)
 </p>
diff --git a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.scss b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.scss
index 41ecef044..13cbc4aac 100644
--- a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.scss
+++ b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.scss
@@ -14,4 +14,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- */
\ No newline at end of file
+ */
diff --git a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.ts b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.ts
index bbe039d05..f128ce70d 100644
--- a/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-documentation/pipeline-element-documentation.component.ts
@@ -20,33 +20,31 @@ import { Component, Input, OnInit } from '@angular/core';
 import { PipelineElementService } from '@streampipes/platform-services';
 
 @Component({
-  selector: 'pipeline-element-documentation',
-  templateUrl: './pipeline-element-documentation.component.html',
-  styleUrls: ['./pipeline-element-documentation.component.scss']
+    selector: 'sp-pipeline-element-documentation',
+    templateUrl: './pipeline-element-documentation.component.html',
+    styleUrls: ['./pipeline-element-documentation.component.scss'],
 })
 export class PipelineElementDocumentationComponent implements OnInit {
-
-  @Input()
-  appId: string;
-
-  @Input()
-  useStyling: boolean;
-
-  documentationMarkdown: any;
-  error: any;
-
-  constructor(private pipelineElementService: PipelineElementService) {
-
-  }
-
-  ngOnInit(): void {
-    this.pipelineElementService.getDocumentation(this.appId).subscribe(msg => {
-      this.error = false;
-      this.documentationMarkdown = msg;
-    }, error => {
-      this.error = true;
-    });
-  }
-
-
+    @Input()
+    appId: string;
+
+    @Input()
+    useStyling: boolean;
+
+    documentationMarkdown: any;
+    error: any;
+
+    constructor(private pipelineElementService: PipelineElementService) {}
+
+    ngOnInit(): void {
+        this.pipelineElementService.getDocumentation(this.appId).subscribe(
+            msg => {
+                this.error = false;
+                this.documentationMarkdown = msg;
+            },
+            error => {
+                this.error = true;
+            },
+        );
+    }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.html b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.html
index 25eb72dec..18970b039 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.html
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.html
@@ -15,44 +15,56 @@
   ~ limitations under the License.
   ~
   -->
-<div fxLayout="row"
-     class="draggable-pipeline-element"
-     fxFlex="100"
-     id="{{ element.appId }}"
-     [attr.data-pe]="element.elementId"
-     (mouseenter)="updateMouseOver(element.name)"
-     (mouseleave)="updateMouseOver('')">
+<div
+    fxLayout="row"
+    class="draggable-pipeline-element"
+    fxFlex="100"
+    id="{{ element.appId }}"
+    [attr.data-pe]="element.elementId"
+    (mouseenter)="updateMouseOver(element.name)"
+    (mouseleave)="updateMouseOver('')"
+>
     <div fxFlex="50px">
-        <div matTooltip="{{element.name}}" [matTooltipPosition]="'above'"
-             class="draggable-icon-editor tt"
-             [ngClass]="activeCssClass">
+        <div
+            matTooltip="{{ element.name }}"
+            [matTooltipPosition]="'above'"
+            class="draggable-icon-editor tt"
+            [ngClass]="activeCssClass"
+        >
             <span id="container" class="pe-container">
-            <pipeline-element
+                <sp-pipeline-element
                     id="pe-icon-stand-{{ element.appId }}"
-                    style="margin-left:-3%"
+                    style="margin-left: -3%"
                     [iconStandSize]="true"
                     [attr.data-cy]="'sp-pipeline-element-' + cypressName"
                     [pipelineElement]="element"
-                    [preview]="false"></pipeline-element>
+                    [preview]="false"
+                ></sp-pipeline-element>
             </span>
         </div>
     </div>
     <div fxFlex fxLayoutAlign="start start" fxLayout="column">
         <div class="element-name" fxLayoutAlign="start start">
-            {{element.name}}
+            {{ element.name }}
         </div>
-        <div class="element-description" *ngIf="currentMouseOver" fxLayoutAlign="start start">
-            <small>{{element.description}}</small>
+        <div
+            class="element-description"
+            *ngIf="currentMouseOver"
+            fxLayoutAlign="start start"
+        >
+            <small>{{ element.description }}</small>
         </div>
     </div>
     <div fxLayoutAlign="end start" *ngIf="currentMouseOver">
-        <button mat-button
-                mat-raised-button
-                mat-icon-button
-                color="accent"
-                class="help-button-stand"
-                (click)="openHelpDialog(element)">?
+        <button
+            mat-button
+            mat-raised-button
+            mat-icon-button
+            color="accent"
+            class="help-button-stand"
+            (click)="openHelpDialog(element)"
+        >
+            ?
         </button>
     </div>
 </div>
-
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.scss b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.scss
index 085ba5084..170b40e0d 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.scss
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.scss
@@ -17,67 +17,67 @@
  */
 
 .draggable-icon-editor {
-  cursor: move;
-  vertical-align: top;
-  background-color: var(--color-pe);
-  display: inline-block;
-  height: 35px;
-  width: 35px;
-  line-height: 35px;
-  box-shadow: 1px 1px 2px var(--color-shadow);
-  text-align: center;
-  z-index:100;
+    cursor: move;
+    vertical-align: top;
+    background-color: var(--color-pe);
+    display: inline-block;
+    height: 35px;
+    width: 35px;
+    line-height: 35px;
+    box-shadow: 1px 1px 2px var(--color-shadow);
+    text-align: center;
+    z-index: 100;
 }
 
 .draggable-icon-drag {
-  cursor: pointer;
-  vertical-align: top;
-  background: var(--color-pe);
-  display: inline-block;
-  height: 70px;
-  width: 70px;
-  line-height: 70px;
-  box-shadow: 1px 1px 2px var(--color-shadow);
-  text-align: center;
-  background: white;
-  z-index: 100;
+    cursor: pointer;
+    vertical-align: top;
+    background: var(--color-pe);
+    display: inline-block;
+    height: 70px;
+    width: 70px;
+    line-height: 70px;
+    box-shadow: 1px 1px 2px var(--color-shadow);
+    text-align: center;
+    background: white;
+    z-index: 100;
 }
 
 .draggable-pipeline-element {
-  cursor: move;
-  z-index: 100;
+    cursor: move;
+    z-index: 100;
 }
 
 .element-name {
-  font-size: 11pt;
-  font-weight: 500;
+    font-size: 11pt;
+    font-weight: 500;
 }
 
 .element-description {
-  font-weight: 300;
+    font-weight: 300;
 }
 
 .help-button-stand {
-  padding: 0;
-  min-width: 0;
-  width: 20px;
-  height: 20px;
-  flex-shrink: 0;
-  line-height: 20px;
-  border-radius: 0;
-  margin-right: 5px;
+    padding: 0;
+    min-width: 0;
+    width: 20px;
+    height: 20px;
+    flex-shrink: 0;
+    line-height: 20px;
+    border-radius: 0;
+    margin-right: 5px;
 }
 
 .pe-container {
-  position:relative;
-  display:block;
-  width:35px;
-  height:35px;
+    position: relative;
+    display: block;
+    width: 35px;
+    height: 35px;
 }
 
 .pe-container-drag {
-  position:relative;
-  display:block;
-  width:70px;
-  height:70px;
+    position: relative;
+    display: block;
+    width: 70px;
+    height: 70px;
 }
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.ts b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.ts
index bd799a073..ab0e2385c 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand-row/pipeline-element-icon-stand-row.component.ts
@@ -16,46 +16,47 @@
  *
  */
 
-import { Component, Input, OnInit, } from '@angular/core';
-import { PipelineElementType, PipelineElementUnion } from '../../model/editor.model';
+import { Component, Input, OnInit } from '@angular/core';
+import {
+    PipelineElementType,
+    PipelineElementUnion,
+} from '../../model/editor.model';
 import { PipelineElementTypeUtils } from '../../utils/editor.utils';
 import { EditorService } from '../../services/editor.service';
 
-
 @Component({
-  selector: 'sp-pe-icon-stand-row',
-  templateUrl: './pipeline-element-icon-stand-row.component.html',
-  styleUrls: ['./pipeline-element-icon-stand-row.component.scss']
+    selector: 'sp-pe-icon-stand-row',
+    templateUrl: './pipeline-element-icon-stand-row.component.html',
+    styleUrls: ['./pipeline-element-icon-stand-row.component.scss'],
 })
 export class PipelineElementIconStandRowComponent implements OnInit {
+    @Input()
+    element: PipelineElementUnion;
 
-  @Input()
-  element: PipelineElementUnion;
-
-  activeCssClass: string;
-  cypressName: string;
-
-  currentMouseOver = false;
+    activeCssClass: string;
+    cypressName: string;
 
-  constructor(private editorService: EditorService) {
+    currentMouseOver = false;
 
-  }
+    constructor(private editorService: EditorService) {}
 
-  ngOnInit(): void {
-    const activeType = PipelineElementTypeUtils.fromClassName(this.element['@class']);
-    this.activeCssClass = this.makeActiveCssClass(activeType);
-    this.cypressName = this.element.name.toLowerCase().replace(' ', '_');
-  }
+    ngOnInit(): void {
+        const activeType = PipelineElementTypeUtils.fromClassName(
+            this.element['@class'],
+        );
+        this.activeCssClass = this.makeActiveCssClass(activeType);
+        this.cypressName = this.element.name.toLowerCase().replace(' ', '_');
+    }
 
-  makeActiveCssClass(elementType: PipelineElementType): string {
-    return PipelineElementTypeUtils.toCssShortHand(elementType);
-  }
+    makeActiveCssClass(elementType: PipelineElementType): string {
+        return PipelineElementTypeUtils.toCssShortHand(elementType);
+    }
 
-  updateMouseOver(e: string) {
-    this.currentMouseOver = !this.currentMouseOver;
-  }
+    updateMouseOver(e: string) {
+        this.currentMouseOver = !this.currentMouseOver;
+    }
 
-  openHelpDialog(pipelineElement) {
-    this.editorService.openHelpDialog(pipelineElement);
-  }
+    openHelpDialog(pipelineElement) {
+        this.editorService.openHelpDialog(pipelineElement);
+    }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.html b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.html
index f625f1f7a..6b632de6a 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.html
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.html
@@ -15,110 +15,196 @@
   ~ limitations under the License.
   ~
   -->
-<div fxFlex="100" fxLayout="column" class="border" style="width: 250px;" [attr.data-cy]="'sp-pipeline-element-selection'">
-    <div class="editorIconStandOptions sp-bg-lightgray page-container-nav" style="padding:0px;">
-        <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" style="padding-left:5px;">
+<div
+    fxFlex="100"
+    fxLayout="column"
+    class="border"
+    style="width: 250px"
+    [attr.data-cy]="'sp-pipeline-element-selection'"
+>
+    <div
+        class="editorIconStandOptions sp-bg-lightgray page-container-nav"
+        style="padding: 0px"
+    >
+        <div
+            fxFlex="100"
+            fxLayout="row"
+            fxLayoutAlign="start center"
+            style="padding-left: 5px"
+        >
             <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
                 <i class="material-icons sp-accent">search</i>
-                <mat-form-field floatLabel="never" color="accent" class="search-field">
+                <mat-form-field
+                    floatLabel="never"
+                    color="accent"
+                    class="search-field"
+                >
                     <mat-label>Find element</mat-label>
-                    <input matInput
-                           type="text"
-                           (keyup)="makeDraggable()"
-                           placeholder="Find element"
-                           [(ngModel)]="elementFilter">
-                    <button *ngIf="elementFilter"
-                            matSuffix
-                            mat-icon-button
-                            aria-label="Find element" (click)="clearInput()">
+                    <input
+                        matInput
+                        type="text"
+                        (keyup)="makeDraggable()"
+                        placeholder="Find element"
+                        [(ngModel)]="elementFilter"
+                    />
+                    <button
+                        *ngIf="elementFilter"
+                        matSuffix
+                        mat-icon-button
+                        aria-label="Find element"
+                        (click)="clearInput()"
+                    >
                         <mat-icon>close</mat-icon>
                     </button>
                 </mat-form-field>
                 <span fxFlex></span>
-                <button mat-button
-                        mat-icon-button
-                        color="accent"
-                        (click)="startCreatePipelineTour()"
-                        [matTooltip]="'Tutorial'" style="margin-right: 5px;">
-                    <i class="material-icons">
-                        school
-                    </i>
+                <button
+                    mat-button
+                    mat-icon-button
+                    color="accent"
+                    (click)="startCreatePipelineTour()"
+                    [matTooltip]="'Tutorial'"
+                    style="margin-right: 5px"
+                >
+                    <i class="material-icons"> school </i>
                 </button>
             </div>
         </div>
     </div>
-    <div id="editor-icon-stand"
-         class="icon-stand"
-         *ngIf="allElements">
-        <div fxFlex="100"
-             fxLayout="column">
-            <div *ngFor="let availableType; let i = index of availableTypes"
-                 fxLayout="column"
-                 class="panel-outer">
-                <div class="panel-header"
-                     id="panel-{{availableType.filters[0]}}"
-                     fxLayout="row"
-                     fxLayoutAlign="start center"
-                     [ngStyle]="{background: 'var(--color-bg-2)'}">
-                    <div class="panel-title"
-                         fxLayoutAlign="start center">
-                        {{availableType.title}}
+    <div id="editor-icon-stand" class="icon-stand" *ngIf="allElements">
+        <div fxFlex="100" fxLayout="column">
+            <div
+                *ngFor="let availableType; let i = index; of: availableTypes"
+                fxLayout="column"
+                class="panel-outer"
+            >
+                <div
+                    class="panel-header"
+                    id="panel-{{ availableType.filters[0] }}"
+                    fxLayout="row"
+                    fxLayoutAlign="start center"
+                    [ngStyle]="{ background: 'var(--color-bg-2)' }"
+                >
+                    <div class="panel-title" fxLayoutAlign="start center">
+                        {{ availableType.title }}
                     </div>
                     <span fxFlex></span>
-                    <button mat-icon-button
-                            matTooltip="Create new source"
-                            (click)="navigateToConnect()"
-                            *ngIf="availableType.title === availableTypes[0].title">
+                    <button
+                        mat-icon-button
+                        matTooltip="Create new source"
+                        (click)="navigateToConnect()"
+                        *ngIf="availableType.title === availableTypes[0].title"
+                    >
                         <mat-icon>add</mat-icon>
                     </button>
-                    <button mat-icon-button
-                            (click)="toggleOpen(availableType)"
-                            *ngIf="!availableType.open">
+                    <button
+                        mat-icon-button
+                        (click)="toggleOpen(availableType)"
+                        *ngIf="!availableType.open"
+                    >
                         <mat-icon>expand_more</mat-icon>
                     </button>
-                    <button mat-icon-button
-                            (click)="toggleOpen(availableType)"
-                            *ngIf="availableType.open">
+                    <button
+                        mat-icon-button
+                        (click)="toggleOpen(availableType)"
+                        *ngIf="availableType.open"
+                    >
                         <mat-icon>expand_less</mat-icon>
                     </button>
                 </div>
-                <div fxFlex="100"
-                     fxLayout="column"
-                     *ngIf="availableType.open" class="panel-content">
-                    <div fxLayout="row"
-                         fxLayoutAlign="end center"
-                         class="panel-options"
-                         *ngIf="!(availableType.filters[0] === 1)">
-                        <small>Sort:&nbsp;<a (click)="changeSorting(availableType, 'group')"
-                                             class="sort-option"
-                                             [ngClass]="availableType.sort === 'group' ? 'sort-selected' : 'sort-unselected'">Group</a>&nbsp;|&nbsp;
-                            <a (click)="changeSorting(availableType, 'name')"
-                               class="sort-option"
-                               [ngClass]="availableType.sort === 'name' ? 'sort-selected' : 'sort-unselected'">Name</a></small>
+                <div
+                    fxFlex="100"
+                    fxLayout="column"
+                    *ngIf="availableType.open"
+                    class="panel-content"
+                >
+                    <div
+                        fxLayout="row"
+                        fxLayoutAlign="end center"
+                        class="panel-options"
+                        *ngIf="!(availableType.filters[0] === 1)"
+                    >
+                        <small
+                            >Sort:&nbsp;<a
+                                (click)="changeSorting(availableType, 'group')"
+                                class="sort-option"
+                                [ngClass]="
+                                    availableType.sort === 'group'
+                                        ? 'sort-selected'
+                                        : 'sort-unselected'
+                                "
+                                >Group</a
+                            >&nbsp;|&nbsp;
+                            <a
+                                (click)="changeSorting(availableType, 'name')"
+                                class="sort-option"
+                                [ngClass]="
+                                    availableType.sort === 'name'
+                                        ? 'sort-selected'
+                                        : 'sort-unselected'
+                                "
+                                >Name</a
+                            ></small
+                        >
                     </div>
-                    <div fxFlex="100"
-                         fxLayout="column"
-                         *ngIf="availableType.sort === 'name'">
-                        <div fxLayout="column"
-                             fxFlex="100"
-                             *ngFor="let element of allElements | pipelineElementType:availableType.filters | pipelineElementName:elementFilter"
-                             class="pe-row">
-                            <sp-pe-icon-stand-row [element]="element" fxFlex="100"></sp-pe-icon-stand-row>
+                    <div
+                        fxFlex="100"
+                        fxLayout="column"
+                        *ngIf="availableType.sort === 'name'"
+                    >
+                        <div
+                            fxLayout="column"
+                            fxFlex="100"
+                            *ngFor="
+                                let element of allElements
+                                    | pipelineElementType
+                                        : availableType.filters
+                                    | pipelineElementName : elementFilter
+                            "
+                            class="pe-row"
+                        >
+                            <sp-pe-icon-stand-row
+                                [element]="element"
+                                fxFlex="100"
+                            ></sp-pe-icon-stand-row>
                         </div>
                     </div>
-                    <div fxFlex="100"
-                         fxLayout="column"
-                         *ngIf="availableType.sort === 'group' && categoriesReady">
-                        <div *ngFor="let category of allCategories.get(availableType.filters[0])"
-                             fxLayout="column">
+                    <div
+                        fxFlex="100"
+                        fxLayout="column"
+                        *ngIf="
+                            availableType.sort === 'group' && categoriesReady
+                        "
+                    >
+                        <div
+                            *ngFor="
+                                let category of allCategories.get(
+                                    availableType.filters[0]
+                                )
+                            "
+                            fxLayout="column"
+                        >
                             <div class="group-outer">
-                                <span class="group-title">{{category.label}}</span>
+                                <span class="group-title">{{
+                                    category.label
+                                }}</span>
                             </div>
-                            <div fxLayout="column"
-                                 fxFlex="100"
-                                 *ngFor="let element of allElements | pipelineElementType:availableType.filters | pipelineElementName:elementFilter | pipelineElementGroup:category"
-                                 class="pe-row">
-                                <sp-pe-icon-stand-row [element]="element" fxFlex="100"></sp-pe-icon-stand-row>
+                            <div
+                                fxLayout="column"
+                                fxFlex="100"
+                                *ngFor="
+                                    let element of allElements
+                                        | pipelineElementType
+                                            : availableType.filters
+                                        | pipelineElementName : elementFilter
+                                        | pipelineElementGroup : category
+                                "
+                                class="pe-row"
+                            >
+                                <sp-pe-icon-stand-row
+                                    [element]="element"
+                                    fxFlex="100"
+                                ></sp-pe-icon-stand-row>
                             </div>
                         </div>
                     </div>
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss
index be1bab152..76b298677 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.scss
@@ -19,100 +19,99 @@
 @import '../../../../scss/_variables.scss';
 
 .menu-text-color {
-  color: var(--color-accent);
-  display: flex;
-  align-items: center;
+    color: var(--color-accent);
+    display: flex;
+    align-items: center;
 }
 
 .icon-stand {
-  max-height: calc(100vh - 148px);
-  overflow-y: auto;
-  background: var(--color-bg-1);
-  margin-top: 5px;
+    max-height: calc(100vh - 148px);
+    overflow-y: auto;
+    background: var(--color-bg-1);
+    margin-top: 5px;
 }
 
 .border {
-  border: 1px solid var(--color-bg-3);
+    border: 1px solid var(--color-bg-3);
 }
 
 .pe-row {
-  padding-top: 5px;
-  padding-bottom: 5px;
-  padding-left: 5px;
+    padding-top: 5px;
+    padding-bottom: 5px;
+    padding-left: 5px;
 }
 
-
 .pe-row:nth-child(even) {
-  background-color: var(--color-bg-1);
+    background-color: var(--color-bg-1);
 }
 
 .pe-row:nth-child(odd) {
-  background-color: var(--color-bg-0);
+    background-color: var(--color-bg-0);
 }
 
 .pe-row:hover {
-  background-color: var(--color-bg-2);
-  cursor: pointer;
+    background-color: var(--color-bg-2);
+    cursor: pointer;
 }
 
 .panel-header {
-  padding: 3px;
+    padding: 3px;
 }
 
 .panel-title {
-  font-weight: 400;
-  padding-left: 5px;
+    font-weight: 400;
+    padding-left: 5px;
 }
 
 .panel-options {
-  margin-top: 10px;
-  margin-bottom: 5px;
-  margin-right: 5px;
+    margin-top: 10px;
+    margin-bottom: 5px;
+    margin-right: 5px;
 }
 
 .panel-content {
-  margin-top: 10px;
+    margin-top: 10px;
 }
 
 .sort-selected {
-  padding: 3px;
-  background: var(--color-accent);
-  color: white;
+    padding: 3px;
+    background: var(--color-accent);
+    color: white;
 }
 
 .sort-unselected {
-  padding: 3px;
-  color: var(--color-accent);
+    padding: 3px;
+    color: var(--color-accent);
 }
 
 .panel-outer {
-  margin-bottom: 10px;
-  margin-left: 0;
-  margin-right: 0px;
-  border-right: 1px solid var(--color-bg-3);
-  border-bottom: 1px solid var(--color-bg-3);
-  border-top: 1px solid var(--color-bg-3);
+    margin-bottom: 10px;
+    margin-left: 0;
+    margin-right: 0px;
+    border-right: 1px solid var(--color-bg-3);
+    border-bottom: 1px solid var(--color-bg-3);
+    border-top: 1px solid var(--color-bg-3);
 }
 
 .search-field {
-  width: 160px;
+    width: 160px;
 }
 
 .group-outer {
-  margin-top: 15px;
-  margin-bottom: 10px;
-  margin-left: 5px;
+    margin-top: 15px;
+    margin-bottom: 10px;
+    margin-left: 5px;
 }
 
 .group-title {
-  padding-left: 5px;
-  padding-right: 5px;
-  border-radius: 3px;
-  font-size: small;
-  background: var(--color-primary);
-  color: var(--color-accent);
+    padding-left: 5px;
+    padding-right: 5px;
+    border-radius: 3px;
+    font-size: small;
+    background: var(--color-primary);
+    color: var(--color-accent);
 }
 
 .sort-option {
-  cursor: pointer;
+    cursor: pointer;
 }
diff --git a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
index c1c5dac02..7754f1ad3 100644
--- a/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
@@ -16,143 +16,185 @@
  *
  */
 
-import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output, } from '@angular/core';
+import {
+    AfterViewInit,
+    Component,
+    EventEmitter,
+    Input,
+    OnInit,
+    Output,
+} from '@angular/core';
 import { RestApi } from '../../../services/rest-api.service';
-import { PeCategory, PipelineElementType, PipelineElementUnion } from '../../model/editor.model';
+import {
+    PeCategory,
+    PipelineElementType,
+    PipelineElementUnion,
+} from '../../model/editor.model';
 import { EditorService } from '../../services/editor.service';
 import { zip } from 'rxjs';
-import { Router } from "@angular/router";
-
+import { Router } from '@angular/router';
 
 @Component({
-  selector: 'pipeline-element-icon-stand',
-  templateUrl: './pipeline-element-icon-stand.component.html',
-  styleUrls: ['./pipeline-element-icon-stand.component.scss']
+    selector: 'sp-pipeline-element-icon-stand',
+    templateUrl: './pipeline-element-icon-stand.component.html',
+    styleUrls: ['./pipeline-element-icon-stand.component.scss'],
 })
-export class PipelineElementIconStandComponent implements OnInit, AfterViewInit {
-
-  availableTypes = [
-    {
-      title: 'Data Sources',
-      filters: [PipelineElementType.DataStream, PipelineElementType.DataSet],
-      open: true,
-      color: 'var(--color-stream)',
-      sort: 'name'
-    },
-    {
-      title: 'Data Processors',
-      filters: [PipelineElementType.DataProcessor],
-      open: true,
-      color: 'var(--color-processor)',
-      sort: 'name'
-    },
-    {
-      title: 'Data Sinks',
-      filters: [PipelineElementType.DataSink],
-      open: true,
-      color: 'var(--color-sink)',
-      sort: 'name'
-    }];
-
-  @Input()
-  allElements: PipelineElementUnion[];
-
-  @Output()
-  startTourEmitter: EventEmitter<void> = new EventEmitter<void>();
-
-  elementFilter = '';
-  allCategories: Map<PipelineElementType, PeCategory[]> = new Map();
-  categoriesReady = false;
-  uncategorized: PeCategory = {code: 'UNCATEGORIZED', label: 'Uncategorized', description: ''};
-
-  constructor(private restApi: RestApi,
-              private editorService: EditorService,
-              private router: Router) {
-
-  }
-
-  ngOnInit(): void {
-    this.loadOptions();
-  }
-
-  ngAfterViewInit() {
-    this.makeDraggable();
-  }
-
-  loadOptions() {
-    zip(this.editorService.getEpCategories(),
-      this.editorService.getEpaCategories(),
-      this.editorService.getEcCategories()).subscribe((results) => {
-      results[0] = this.sort(results[0]).filter(category => this.filterForExistingCategories(category));
-      results[1] = this.sort(results[1]).filter(category => this.filterForExistingCategories(category));
-      results[2] = this.sort(results[2]).filter(category => this.filterForExistingCategories(category));
-      this.allCategories.set(PipelineElementType.DataStream, results[0]);
-      this.allCategories.set(PipelineElementType.DataProcessor, results[1]);
-      this.allCategories.set(PipelineElementType.DataSink, results[2]);
-      this.categoriesReady = true;
-    });
-  }
-
-  filterForExistingCategories(category: PeCategory): boolean {
-    return this.allElements
-      .filter(element => element.category)
-      .find(element => element.category.find(elCat => elCat === category.code)) !== undefined ||
-      ((category.code === this.uncategorized.code) && this.allElements.find(element => (!element.category)) !== undefined);
-  }
-
-  sort(categories: PeCategory[]) {
-    return categories.sort((a, b) => {
-      return a.label.localeCompare(b.label);
-    });
-  }
-
-  makeDraggable() {
-    setTimeout(() => {
-      ($('.draggable-pipeline-element') as any).draggable({
-        revert: 'invalid',
-        helper: ((ev) => {
-          const draggable = $(ev.currentTarget).find('.draggable-icon-editor').first().clone();
-          const draggableContainer = $(draggable).find('.pe-container').first();
-          $(draggable).removeClass('draggable-icon-editor');
-          $(draggable).addClass('draggable-icon-drag');
-          $(draggableContainer).removeClass('pe-container');
-          $(draggableContainer).addClass('pe-container-drag');
-          return draggable.clone();
-        }),
-        stack: '.draggable-pipeline-element',
-        start(el, ui) {
-          ui.helper.appendTo('#content');
-          $('#outerAssemblyArea').css('border', '3px dashed #39b54a');
+export class PipelineElementIconStandComponent
+    implements OnInit, AfterViewInit
+{
+    availableTypes = [
+        {
+            title: 'Data Sources',
+            filters: [
+                PipelineElementType.DataStream,
+                PipelineElementType.DataSet,
+            ],
+            open: true,
+            color: 'var(--color-stream)',
+            sort: 'name',
         },
-        stop(el, ui) {
-          $('#outerAssemblyArea').css('border', '1px solid var(--color-bg-3)');
-        }
-      });
-    });
-  }
-
-  toggleOpen(availableType: any): void {
-    availableType.open = !availableType.open;
-    this.makeDraggable();
-  }
-
-  startCreatePipelineTour() {
-    this.startTourEmitter.emit();
-  }
-
-  changeSorting(availableType: any,
-                sortMode: string) {
-    availableType.sort = sortMode;
-    this.makeDraggable();
-  }
-
-  clearInput() {
-    this.elementFilter = '';
-    this.makeDraggable();
-  }
-
-  navigateToConnect() {
-    this.router.navigate(['connect']);
-  }
-
+        {
+            title: 'Data Processors',
+            filters: [PipelineElementType.DataProcessor],
+            open: true,
+            color: 'var(--color-processor)',
+            sort: 'name',
+        },
+        {
+            title: 'Data Sinks',
+            filters: [PipelineElementType.DataSink],
+            open: true,
+            color: 'var(--color-sink)',
+            sort: 'name',
+        },
+    ];
+
+    @Input()
+    allElements: PipelineElementUnion[];
+
+    @Output()
+    startTourEmitter: EventEmitter<void> = new EventEmitter<void>();
+
+    elementFilter = '';
+    allCategories: Map<PipelineElementType, PeCategory[]> = new Map();
+    categoriesReady = false;
+    uncategorized: PeCategory = {
+        code: 'UNCATEGORIZED',
+        label: 'Uncategorized',
+        description: '',
+    };
+
+    constructor(
+        private restApi: RestApi,
+        private editorService: EditorService,
+        private router: Router,
+    ) {}
+
+    ngOnInit(): void {
+        this.loadOptions();
+    }
+
+    ngAfterViewInit() {
+        this.makeDraggable();
+    }
+
+    loadOptions() {
+        zip(
+            this.editorService.getEpCategories(),
+            this.editorService.getEpaCategories(),
+            this.editorService.getEcCategories(),
+        ).subscribe(results => {
+            results[0] = this.sort(results[0]).filter(category =>
+                this.filterForExistingCategories(category),
+            );
+            results[1] = this.sort(results[1]).filter(category =>
+                this.filterForExistingCategories(category),
+            );
+            results[2] = this.sort(results[2]).filter(category =>
+                this.filterForExistingCategories(category),
+            );
+            this.allCategories.set(PipelineElementType.DataStream, results[0]);
+            this.allCategories.set(
+                PipelineElementType.DataProcessor,
+                results[1],
+            );
+            this.allCategories.set(PipelineElementType.DataSink, results[2]);
+            this.categoriesReady = true;
+        });
+    }
+
+    filterForExistingCategories(category: PeCategory): boolean {
+        return (
+            this.allElements
+                .filter(element => element.category)
+                .find(element =>
+                    element.category.find(elCat => elCat === category.code),
+                ) !== undefined ||
+            (category.code === this.uncategorized.code &&
+                this.allElements.find(element => !element.category) !==
+                    undefined)
+        );
+    }
+
+    sort(categories: PeCategory[]) {
+        return categories.sort((a, b) => {
+            return a.label.localeCompare(b.label);
+        });
+    }
+
+    makeDraggable() {
+        setTimeout(() => {
+            ($('.draggable-pipeline-element') as any).draggable({
+                revert: 'invalid',
+                helper: ev => {
+                    const draggable = $(ev.currentTarget)
+                        .find('.draggable-icon-editor')
+                        .first()
+                        .clone();
+                    const draggableContainer = $(draggable)
+                        .find('.pe-container')
+                        .first();
+                    $(draggable).removeClass('draggable-icon-editor');
+                    $(draggable).addClass('draggable-icon-drag');
+                    $(draggableContainer).removeClass('pe-container');
+                    $(draggableContainer).addClass('pe-container-drag');
+                    return draggable.clone();
+                },
+                stack: '.draggable-pipeline-element',
+                start(el, ui) {
+                    ui.helper.appendTo('#content');
+                    $('#outerAssemblyArea').css('border', '3px dashed #39b54a');
+                },
+                stop(el, ui) {
+                    $('#outerAssemblyArea').css(
+                        'border',
+                        '1px solid var(--color-bg-3)',
+                    );
+                },
+            });
+        });
+    }
+
+    toggleOpen(availableType: any): void {
+        availableType.open = !availableType.open;
+        this.makeDraggable();
+    }
+
+    startCreatePipelineTour() {
+        this.startTourEmitter.emit();
+    }
+
+    changeSorting(availableType: any, sortMode: string) {
+        availableType.sort = sortMode;
+        this.makeDraggable();
+    }
+
+    clearInput() {
+        this.elementFilter = '';
+        this.makeDraggable();
+    }
+
+    navigateToConnect() {
+        this.router.navigate(['connect']);
+    }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
index b2597f3a3..92e1483c1 100644
--- a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
+++ b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.html
@@ -16,57 +16,127 @@
   ~
   -->
 <div>
-    <div  [ngStyle]="currentMouseOverElement==pipelineElement.payload.dom ? {opacity: 1} : {opacity: 1}" class="sp-fade-options">
-        <span class="options-button customize-button" *ngIf="pipelineElement.type!='stream'" style="z-index:10">
-            <button class="options-icon-button" mat-button mat-icon-button matTooltip="Configure Element"
-                    [matTooltipPosition]="'above'"
-                    (click)="customizeElement(pipelineElement)">
+    <div
+        [ngStyle]="
+            currentMouseOverElement === pipelineElement.payload.dom
+                ? { opacity: 1 }
+                : { opacity: 1 }
+        "
+        class="sp-fade-options"
+    >
+        <span
+            class="options-button customize-button"
+            *ngIf="pipelineElement.type !== 'stream'"
+            style="z-index: 10"
+        >
+            <button
+                class="options-icon-button"
+                mat-button
+                mat-icon-button
+                matTooltip="Configure Element"
+                [matTooltipPosition]="'above'"
+                (click)="customizeElement(pipelineElement)"
+            >
                 <i class="material-icons options-icon-size">settings</i>
-                </button>
+            </button>
         </span>
-        <span class="options-button customize-button"
-              *ngIf="pipelineElement.type=='stream' && isWildcardTopic()"
-              style="z-index:10">
-            <button class="options-icon-button" mat-button mat-icon-button matTooltip="Configure Element" [matTooltipPosition]="'above'"
-                    (click)="openCustomizeStreamDialog()">
+        <span
+            class="options-button customize-button"
+            *ngIf="pipelineElement.type === 'stream' && isWildcardTopic()"
+            style="z-index: 10"
+        >
+            <button
+                class="options-icon-button"
+                mat-button
+                mat-icon-button
+                matTooltip="Configure Element"
+                [matTooltipPosition]="'above'"
+                (click)="openCustomizeStreamDialog()"
+            >
                 <i class="material-icons options-icon-size">settings</i>
             </button>
         </span>
-        <span class="options-button delete-button" style="z-index:10">
-            <button class="options-icon-button" mat-button mat-icon-button matTooltip="Delete Element" [matTooltipPosition]="'above'"
-                    (click)="removeElement(pipelineElement)">
+        <span class="options-button delete-button" style="z-index: 10">
+            <button
+                class="options-icon-button"
+                mat-button
+                mat-icon-button
+                matTooltip="Delete Element"
+                [matTooltipPosition]="'above'"
+                (click)="removeElement(pipelineElement)"
+            >
                 <i class="material-icons options-icon-size">clear</i>
             </button>
         </span>
-        <span class="options-button possible-button" *ngIf="pipelineElement.type!='action'" style="z-index:10">
-            <button class="options-icon-button" mat-button mat-icon-button matTooltip="Compatible Elements" [matTooltipPosition]="'below'"
-                    [disabled]="!possibleElements || possibleElements.length == 0"
-                    (click)="openPossibleElementsDialog()"
-                    [attr.data-cy]="'sp-possible-elements-' + pipelineElement.payload.name.toLowerCase().replaceAll(' ', '_')"_>
+        <span
+            class="options-button possible-button"
+            *ngIf="pipelineElement.type !== 'action'"
+            style="z-index: 10"
+        >
+            <button
+                class="options-icon-button"
+                mat-button
+                mat-icon-button
+                matTooltip="Compatible Elements"
+                [matTooltipPosition]="'below'"
+                [disabled]="!possibleElements || possibleElements.length === 0"
+                (click)="openPossibleElementsDialog()"
+                [attr.data-cy]="
+                    'sp-possible-elements-' +
+                    pipelineElement.payload.name
+                        .toLowerCase()
+                        .replaceAll(' ', '_')
+                "
+                _
+            >
                 <i class="material-icons options-icon-size">account_tree</i>
-        </button>
+            </button>
         </span>
-        <span class="options-button recommended-button"
-              *ngIf="pipelineElement.type!='action' && (recommendationsAvailable) && recommendedElements.length > 0"
-              style="z-index:10">
-            <button class="options-icon-button" mat-button mat-icon-button matTooltip="Recommended Elements" [matTooltipPosition]="'below'"
-                    (click)="showRecommendations($event)"
-                    [disabled]="!recommendationsAvailable">
+        <span
+            class="options-button recommended-button"
+            *ngIf="
+                pipelineElement.type !== 'action' &&
+                recommendationsAvailable &&
+                recommendedElements.length > 0
+            "
+            style="z-index: 10"
+        >
+            <button
+                class="options-icon-button"
+                mat-button
+                mat-icon-button
+                matTooltip="Recommended Elements"
+                [matTooltipPosition]="'below'"
+                (click)="showRecommendations($event)"
+                [disabled]="!recommendationsAvailable"
+            >
                 <i class="material-icons options-icon-size">add</i>
             </button>
         </span>
-        <span class="options-button help-button" style="z-index:10">
-            <button class="options-icon-button" matTooltip="Help" [matTooltipPosition]="'below'"
-                    mat-button mat-icon-button (click)="openHelpDialog()">
+        <span class="options-button help-button" style="z-index: 10">
+            <button
+                class="options-icon-button"
+                matTooltip="Help"
+                [matTooltipPosition]="'below'"
+                mat-button
+                mat-icon-button
+                (click)="openHelpDialog()"
+            >
                 <i class="material-icons options-icon-size">help</i>
-                </button>
+            </button>
         </span>
-        <div class="editor-pe-info" [ngClass]="'pe-info-' + pipelineElementCssType">
-            {{pipelineElement.payload.name}}
+        <div
+            class="editor-pe-info"
+            [ngClass]="'pe-info-' + pipelineElementCssType"
+        >
+            {{ pipelineElement.payload.name }}
         </div>
     </div>
-    <pipeline-element-recommendation [rawPipelineModel]="rawPipelineModel"
-                                 [pipelineElementDomId]="pipelineElement.payload.dom"
-                                 [recommendedElements]="recommendedElements"
-                                 [recommendationsShown]="recommendationsShown" *ngIf="recommendationsAvailable"></pipeline-element-recommendation>
+    <sp-pipeline-element-recommendation
+        [rawPipelineModel]="rawPipelineModel"
+        [pipelineElementDomId]="pipelineElement.payload.dom"
+        [recommendedElements]="recommendedElements"
+        [recommendationsShown]="recommendationsShown"
+        *ngIf="recommendationsAvailable"
+    ></sp-pipeline-element-recommendation>
 </div>
diff --git a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
index 50f079989..d4762ec6d 100644
--- a/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-options/pipeline-element-options.component.ts
@@ -20,19 +20,26 @@ import { JsplumbBridge } from '../../services/jsplumb-bridge.service';
 import { JsplumbService } from '../../services/jsplumb.service';
 import { PipelineValidationService } from '../../services/pipeline-validation.service';
 import { RestApi } from '../../../services/rest-api.service';
-import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
+import {
+    Component,
+    EventEmitter,
+    Input,
+    OnDestroy,
+    OnInit,
+    Output,
+} from '@angular/core';
 import { PipelineElementRecommendationService } from '../../services/pipeline-element-recommendation.service';
 import { ObjectProvider } from '../../services/object-provider.service';
 import {
-  PipelineElementConfig,
-  PipelineElementConfigurationStatus,
-  PipelineElementUnion
+    PipelineElementConfig,
+    PipelineElementConfigurationStatus,
+    PipelineElementUnion,
 } from '../../model/editor.model';
 import {
-  DataProcessorInvocation,
-  DataSinkInvocation,
-  SpDataStream,
-  WildcardTopicDefinition
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    SpDataStream,
+    WildcardTopicDefinition,
 } from '@streampipes/platform-services';
 import { EditorService } from '../../services/editor.service';
 import { DialogService, PanelType } from '@streampipes/shared-ui';
@@ -42,148 +49,183 @@ import { Subscription } from 'rxjs';
 import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
 
 @Component({
-  selector: 'pipeline-element-options',
-  templateUrl: './pipeline-element-options.component.html',
-  styleUrls: ['./pipeline-element-options.component.css']
+    selector: 'sp-pipeline-element-options',
+    templateUrl: './pipeline-element-options.component.html',
+    styleUrls: ['./pipeline-element-options.component.css'],
 })
 export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
+    recommendationsAvailable: any = false;
+    possibleElements: PipelineElementUnion[];
+    recommendedElements: PipelineElementUnion[];
+    recommendationsShown: any = false;
+    pipelineElementCssType: string;
+    isDataSource: boolean;
+
+    @Input()
+    currentMouseOverElement: string;
+
+    @Input()
+    pipelineElementId: string;
+
+    @Input()
+    pipelineValid: boolean;
+
+    @Input()
+    internalId: string;
+
+    @Input()
+    pipelineElement: PipelineElementConfig;
+
+    @Input()
+    rawPipelineModel: PipelineElementConfig[];
+
+    @Input()
+    allElements: PipelineElementUnion[];
+
+    @Output()
+    delete: EventEmitter<PipelineElementConfig> =
+        new EventEmitter<PipelineElementConfig>();
+
+    @Output()
+    customize: EventEmitter<PipelineElementConfig> =
+        new EventEmitter<PipelineElementConfig>();
+
+    pipelineElementConfiguredObservable: Subscription;
+
+    JsplumbBridge: JsplumbBridge;
+
+    constructor(
+        private objectProvider: ObjectProvider,
+        private pipelineElementRecommendationService: PipelineElementRecommendationService,
+        private dialogService: DialogService,
+        private editorService: EditorService,
+        private jsplumbFactoryService: JsplumbFactoryService,
+        private jsplumbService: JsplumbService,
+        private pipelineValidationService: PipelineValidationService,
+        private restApi: RestApi,
+    ) {
+        this.recommendationsAvailable = false;
+        this.possibleElements = [];
+        this.recommendedElements = [];
+        this.recommendationsShown = false;
+        this.JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
+    }
+
+    ngOnInit() {
+        this.pipelineElementConfiguredObservable =
+            this.editorService.pipelineElementConfigured$.subscribe(
+                pipelineElementDomId => {
+                    this.pipelineElement.settings.openCustomize = false;
+                    this.restApi.updateCachedPipeline(this.rawPipelineModel);
+                    if (
+                        pipelineElementDomId ===
+                            this.pipelineElement.payload.dom &&
+                        !(
+                            this.pipelineElement.payload instanceof
+                            DataSinkInvocation
+                        )
+                    ) {
+                        this.initRecs(this.pipelineElement.payload.dom);
+                    }
+                },
+            );
+        this.pipelineElementCssType = this.pipelineElement.type;
+
+        this.isDataSource =
+            this.pipelineElement.type === 'stream' ||
+            this.pipelineElement.type === 'set';
+
+        if (
+            this.isDataSource ||
+            (this.pipelineElement.payload instanceof DataProcessorInvocation &&
+                this.pipelineElement.settings.completed ===
+                    PipelineElementConfigurationStatus.OK)
+        ) {
+            this.initRecs(this.pipelineElement.payload.dom);
+        }
+    }
+
+    removeElement(pipelineElement: PipelineElementConfig) {
+        this.delete.emit(pipelineElement);
+    }
+
+    customizeElement(pipelineElement: PipelineElementConfig) {
+        this.customize.emit(pipelineElement);
+    }
+
+    openHelpDialog() {
+        this.editorService.openHelpDialog(this.pipelineElement.payload);
+    }
+
+    openCustomizeStreamDialog() {
+        // this.EditorDialogManager.showCustomizeStreamDialog(this.pipelineElement.payload);
+    }
+
+    initRecs(pipelineElementDomId) {
+        const clonedModel: PipelineElementConfig[] = cloneDeep(
+            this.rawPipelineModel,
+        );
+        const currentPipeline = this.objectProvider.makePipeline(clonedModel);
+        this.editorService
+            .recommendPipelineElement(currentPipeline, pipelineElementDomId)
+            .subscribe(result => {
+                if (result.success) {
+                    this.possibleElements = cloneDeep(
+                        this.pipelineElementRecommendationService.collectPossibleElements(
+                            this.allElements,
+                            result.possibleElements,
+                        ),
+                    );
+                    this.recommendedElements = cloneDeep(
+                        this.pipelineElementRecommendationService.populateRecommendedList(
+                            this.allElements,
+                            result.recommendedElements,
+                        ),
+                    );
+                    this.recommendationsAvailable = true;
+                }
+            });
+    }
+
+    openPossibleElementsDialog() {
+        const dialogRef = this.dialogService.open(CompatibleElementsComponent, {
+            panelType: PanelType.SLIDE_IN_PANEL,
+            title: 'Compatible Elements',
+            data: {
+                rawPipelineModel: this.rawPipelineModel,
+                possibleElements: this.possibleElements,
+                pipelineElementDomId: this.pipelineElement.payload.dom,
+            },
+        });
+
+        dialogRef.afterClosed().subscribe(c => {});
+    }
+
+    showRecommendations(e) {
+        this.recommendationsShown = !this.recommendationsShown;
+        e.stopPropagation();
+    }
+
+    isRootElement() {
+        return (
+            this.JsplumbBridge.getConnections({
+                source: document.getElementById(
+                    this.pipelineElement.payload.dom,
+                ),
+            }).length === 0
+        );
+    }
+
+    isWildcardTopic() {
+        console.log(this.pipelineElement);
+        return (
+            (this.pipelineElement.payload as SpDataStream).eventGrounding
+                .transportProtocols[0].topicDefinition instanceof
+            WildcardTopicDefinition
+        );
+    }
 
-  recommendationsAvailable: any = false;
-  possibleElements: PipelineElementUnion[];
-  recommendedElements: PipelineElementUnion[];
-  recommendationsShown: any = false;
-  pipelineElementCssType: string;
-  isDataSource: boolean;
-
-  @Input()
-  currentMouseOverElement: string;
-
-  @Input()
-  pipelineElementId: string;
-
-  @Input()
-  pipelineValid: boolean;
-
-  @Input()
-  internalId: string;
-
-  @Input()
-  pipelineElement: PipelineElementConfig;
-
-  @Input()
-  rawPipelineModel: PipelineElementConfig[];
-
-  @Input()
-  allElements: PipelineElementUnion[];
-
-  @Output()
-  delete: EventEmitter<PipelineElementConfig> = new EventEmitter<PipelineElementConfig>();
-
-  @Output()
-  customize: EventEmitter<PipelineElementConfig> = new EventEmitter<PipelineElementConfig>();
-
-  pipelineElementConfiguredObservable: Subscription;
-
-  JsplumbBridge: JsplumbBridge;
-
-  constructor(private objectProvider: ObjectProvider,
-              private pipelineElementRecommendationService: PipelineElementRecommendationService,
-              private dialogService: DialogService,
-              private editorService: EditorService,
-              private jsplumbFactoryService: JsplumbFactoryService,
-              private jsplumbService: JsplumbService,
-              private pipelineValidationService: PipelineValidationService,
-              private restApi: RestApi) {
-    this.recommendationsAvailable = false;
-    this.possibleElements = [];
-    this.recommendedElements = [];
-    this.recommendationsShown = false;
-    this.JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
-  }
-
-  ngOnInit() {
-    this.pipelineElementConfiguredObservable = this.editorService.pipelineElementConfigured$.subscribe(pipelineElementDomId => {
-      this.pipelineElement.settings.openCustomize = false;
-      this.restApi.updateCachedPipeline(this.rawPipelineModel);
-      if (pipelineElementDomId === this.pipelineElement.payload.dom && ! (this.pipelineElement.payload instanceof DataSinkInvocation)) {
-        this.initRecs(this.pipelineElement.payload.dom);
-      }
-    });
-    this.pipelineElementCssType = this.pipelineElement.type;
-
-    this.isDataSource = this.pipelineElement.type === 'stream' || this.pipelineElement.type === 'set';
-
-    if (this.isDataSource ||
-      (this.pipelineElement.payload instanceof DataProcessorInvocation && this.pipelineElement.settings.completed === PipelineElementConfigurationStatus.OK)) {
-      this.initRecs(this.pipelineElement.payload.dom);
+    ngOnDestroy(): void {
+        this.pipelineElementConfiguredObservable.unsubscribe();
     }
-  }
-
-  removeElement(pipelineElement: PipelineElementConfig) {
-    this.delete.emit(pipelineElement);
-  }
-
-  customizeElement(pipelineElement: PipelineElementConfig) {
-    this.customize.emit(pipelineElement);
-  }
-
-  openHelpDialog() {
-    this.editorService.openHelpDialog(this.pipelineElement.payload);
-  }
-
-  openCustomizeStreamDialog() {
-    // this.EditorDialogManager.showCustomizeStreamDialog(this.pipelineElement.payload);
-  }
-
-  initRecs(pipelineElementDomId) {
-    const clonedModel: PipelineElementConfig[] = cloneDeep(this.rawPipelineModel);
-    const currentPipeline = this.objectProvider.makePipeline(clonedModel);
-    this.editorService.recommendPipelineElement(currentPipeline, pipelineElementDomId).subscribe((result) => {
-      if (result.success) {
-        this.possibleElements =
-            cloneDeep(this.pipelineElementRecommendationService.collectPossibleElements(this.allElements, result.possibleElements));
-        this.recommendedElements =
-            cloneDeep(this.pipelineElementRecommendationService.populateRecommendedList(this.allElements, result.recommendedElements));
-        this.recommendationsAvailable = true;
-      }
-    });
-  }
-
-  openPossibleElementsDialog() {
-    const dialogRef = this.dialogService.open(CompatibleElementsComponent, {
-      panelType: PanelType.SLIDE_IN_PANEL,
-      title: 'Compatible Elements',
-      data: {
-        'rawPipelineModel': this.rawPipelineModel,
-        'possibleElements': this.possibleElements,
-        'pipelineElementDomId': this.pipelineElement.payload.dom
-      }
-    });
-
-    dialogRef.afterClosed().subscribe(c => {
-
-    });
-  }
-
-  showRecommendations(e) {
-    this.recommendationsShown = !this.recommendationsShown;
-    e.stopPropagation();
-  }
-
-  isRootElement() {
-    return this.JsplumbBridge.getConnections({source: document.getElementById(this.pipelineElement.payload.dom)}).length === 0;
-  }
-
-  isWildcardTopic() {
-    console.log(this.pipelineElement);
-    return (this.pipelineElement
-        .payload as SpDataStream)
-        .eventGrounding
-        .transportProtocols[0]
-        .topicDefinition instanceof WildcardTopicDefinition;
-  }
-
-  ngOnDestroy(): void {
-    this.pipelineElementConfiguredObservable.unsubscribe();
-  }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.html b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.html
index a2cf510de..306b9f582 100644
--- a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.html
+++ b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.html
@@ -17,16 +17,23 @@
   -->
 
 <div class="data-preview">
-    <div *ngIf="!runtimeData" fxFlex="100" fxLayout="column" fxLayoutAlign="center center">
+    <div
+        *ngIf="!runtimeData"
+        fxFlex="100"
+        fxLayout="column"
+        fxLayoutAlign="center center"
+    >
         <mat-spinner [diameter]="20" color="accent"></mat-spinner>
         <span class="preview-table mt-10">Waiting for live data...</span>
     </div>
     <table class="row-border hover preview-table" *ngIf="runtimeData">
         <tbody id="preview-data-rows-id">
-        <tr *ngFor="let item of runtimeData | keyvalue" class="preview-row">
-            <td><b>{{item.key}}</b></td>
-            <td>{{item.value}}</td>
-        </tr>
+            <tr *ngFor="let item of runtimeData | keyvalue" class="preview-row">
+                <td>
+                    <b>{{ item.key }}</b>
+                </td>
+                <td>{{ item.value }}</td>
+            </tr>
         </tbody>
     </table>
 </div>
diff --git a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.scss b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.scss
index 691742f3f..bf2c8f643 100644
--- a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.scss
+++ b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.scss
@@ -17,31 +17,31 @@
  */
 
 .data-preview {
-  position: relative;
-  left: 0px;
-  top: 120px;
-  width: 250px;
-  height: 120px;
-  background: var(--color-bg-dialog);
-  overflow: auto;
-  border: 1px solid gray;
-  box-shadow: 0.175em 0.175em 0 0 rgba(15, 28, 63, 0.125);
-  z-index:50;
+    position: relative;
+    left: 0px;
+    top: 120px;
+    width: 250px;
+    height: 120px;
+    background: var(--color-bg-dialog);
+    overflow: auto;
+    border: 1px solid gray;
+    box-shadow: 0.175em 0.175em 0 0 rgba(15, 28, 63, 0.125);
+    z-index: 50;
 }
 
 .preview-table {
-  font-size:9pt;
+    font-size: 9pt;
 }
 
 .mt-10 {
-  margin-top: 10px;
+    margin-top: 10px;
 }
 
-.preview-row, .preview-table {
-  background: var(--color-bg-dialog);
+.preview-row,
+.preview-table {
+    background: var(--color-bg-dialog);
 }
 
 .dataTable tbody tr:hover {
-  background: var(--color-bg-1);
+    background: var(--color-bg-1);
 }
-
diff --git a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.ts b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.ts
index e4501f842..8e57fc405 100644
--- a/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-preview/pipeline-element-preview.component.ts
@@ -16,53 +16,53 @@
  *
  */
 
-import { Component, Input, OnDestroy, OnInit } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
 import { EditorService } from '../../services/editor.service';
 
 @Component({
-  selector: 'pipeline-element-preview',
-  templateUrl: './pipeline-element-preview.component.html',
-  styleUrls: ['./pipeline-element-preview.component.scss']
+    selector: 'sp-pipeline-element-preview',
+    templateUrl: './pipeline-element-preview.component.html',
+    styleUrls: ['./pipeline-element-preview.component.scss'],
 })
-export class PipelineElementPreviewComponent implements OnInit, OnDestroy {
+export class PipelineElementPreviewComponent implements OnInit {
+    @Input()
+    previewId: string;
 
-  @Input()
-  previewId: string;
+    @Input()
+    pipelineElementDomId: string;
 
-  @Input()
-  pipelineElementDomId: string;
+    runtimeData: ReadonlyMap<string, unknown>;
 
-  runtimeData: ReadonlyMap<string, unknown>;
+    runtimeDataError = false;
+    timer: any;
 
-  runtimeDataError = false;
-  timer: any;
+    constructor(private editorService: EditorService) {}
 
-  constructor(private editorService: EditorService) {
+    ngOnInit(): void {
+        this.getLatestRuntimeInfo();
+    }
 
-  }
-
-  ngOnInit(): void {
-    this.getLatestRuntimeInfo();
-  }
-
-  ngOnDestroy(): void {
-  }
-
-  getLatestRuntimeInfo() {
-    this.editorService.getPipelinePreviewResult(this.previewId, this.pipelineElementDomId).subscribe(data => {
-      if (data) {
-        this.runtimeDataError = false;
-        if (!(Object.keys(data).length === 0 && data.constructor === Object)) {
-          this.runtimeData = data;
-        }
-
-        this.timer = setTimeout(() => {
-          this.getLatestRuntimeInfo();
-        }, 1000);
-      } else {
-        this.runtimeDataError = true;
-      }
-    });
-  }
+    getLatestRuntimeInfo() {
+        this.editorService
+            .getPipelinePreviewResult(this.previewId, this.pipelineElementDomId)
+            .subscribe(data => {
+                if (data) {
+                    this.runtimeDataError = false;
+                    if (
+                        !(
+                            Object.keys(data).length === 0 &&
+                            data.constructor === Object
+                        )
+                    ) {
+                        this.runtimeData = data;
+                    }
 
+                    this.timer = setTimeout(() => {
+                        this.getLatestRuntimeInfo();
+                    }, 1000);
+                } else {
+                    this.runtimeDataError = true;
+                }
+            });
+    }
 }
diff --git a/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html b/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html
index 09748fce6..aab5cdff7 100644
--- a/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html
+++ b/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html
@@ -16,16 +16,35 @@
   ~
   -->
 
-<div *ngIf="recommendationsPrepared && recommendedElements.length > 0" class="cv-wrapper" [ngClass]="recommendationsShown ? 'opened-nav' : ''">
+<div
+    *ngIf="recommendationsPrepared && recommendedElements.length > 0"
+    class="cv-wrapper"
+    [ngClass]="recommendationsShown ? 'opened-nav' : ''"
+>
     <ul>
-        <li *ngFor="let recommendedElement of recommendedElements" style="z-index: -1;"
-            [style]="recommendedElement.layoutSettings.skewStyle">
-            <a [style]="recommendedElement.layoutSettings.unskewStyle" [ngClass]="recommendedElement.layoutSettings.type" (click)="create(recommendedElement)" *ngIf="recommendedElement.name">
+        <li
+            *ngFor="let recommendedElement of recommendedElements"
+            style="z-index: -1"
+            [style]="recommendedElement.layoutSettings.skewStyle"
+        >
+            <a
+                [style]="recommendedElement.layoutSettings.unskewStyle"
+                [ngClass]="recommendedElement.layoutSettings.type"
+                (click)="create(recommendedElement)"
+                *ngIf="recommendedElement.name"
+            >
             </a>
-            <div (click)="create(recommendedElement)" [style]="recommendedElement.layoutSettings.unskewStyleLabel"
-                 [ngClass]="recommendedElement.layoutSettings.type">
-                <pipeline-element [iconSize]="'small'" [pipelineElement]="recommendedElement" *ngIf="recommendedElement.name">
-                </pipeline-element>
+            <div
+                (click)="create(recommendedElement)"
+                [style]="recommendedElement.layoutSettings.unskewStyleLabel"
+                [ngClass]="recommendedElement.layoutSettings.type"
+            >
+                <sp-pipeline-element
+                    [iconSize]="'small'"
+                    [pipelineElement]="recommendedElement"
+                    *ngIf="recommendedElement.name"
+                >
+                </sp-pipeline-element>
             </div>
         </li>
     </ul>
diff --git a/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts b/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts
index 32fe6c453..92a2752ad 100644
--- a/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts
+++ b/ui/src/app/editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts
@@ -17,139 +17,171 @@
  */
 
 import { JsplumbService } from '../../services/jsplumb.service';
-import { AfterViewInit, Component, Input, OnInit } from '@angular/core';
-import { InvocablePipelineElementUnion, PipelineElementConfig } from '../../model/editor.model';
+import { Component, Input } from '@angular/core';
+import {
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+} from '../../model/editor.model';
 import { DataProcessorInvocation } from '@streampipes/platform-services';
 import { SafeCss } from '../../utils/style-sanitizer';
 
 @Component({
-  selector: 'pipeline-element-recommendation',
-  templateUrl: './pipeline-element-recommendation.component.html',
-  styleUrls: ['./pipeline-element-recommendation.component.scss']
+    selector: 'sp-pipeline-element-recommendation',
+    templateUrl: './pipeline-element-recommendation.component.html',
+    styleUrls: ['./pipeline-element-recommendation.component.scss'],
 })
-export class PipelineElementRecommendationComponent implements OnInit, AfterViewInit {
-
-  @Input()
-  recommendationsShown: boolean;
-
-  @Input()
-  rawPipelineModel: PipelineElementConfig[];
-
-  @Input()
-  pipelineElementDomId: string;
-
-  _recommendedElements: any;
-
-  recommendationsPrepared = false;
-
-  constructor(private jsplumbService: JsplumbService,
-              public safeCss: SafeCss) {
-
-  }
-
-  ngOnInit() {
-  }
-
-  ngAfterViewInit(): void {
-
-  }
-
-  prepareStyles(recommendedElements) {
-    recommendedElements.forEach((element, index) => {
-      this.setLayoutSettings(element, index, recommendedElements);
-    });
-  }
-
-  setLayoutSettings(element, index, recommendedElements) {
-    element.layoutSettings = {
-      skewStyle: element.name ? this.getSkewStyle(index, recommendedElements) : {'opacity': 0},
-      unskewStyle: this.getUnskewStyle(element, index, recommendedElements),
-      unskewStyleLabel: this.getUnskewStyleLabel(index, recommendedElements),
-      type: element instanceof DataProcessorInvocation ? 'sepa' : 'action'
-    };
-  }
-
-  create(recommendedElement: InvocablePipelineElementUnion) {
-    this.recommendationsShown = false;
-    this.jsplumbService.createElement(this.rawPipelineModel, recommendedElement, this.pipelineElementDomId);
-  }
-
-  getUnskewStyle(recommendedElement, index, recommendedElements) {
-    const unskew = -(this.getSkew(recommendedElements));
-    const rotate = -(90 - (this.getSkew(recommendedElements) / 2));
-
-    return 'transform: skew(' + unskew + 'deg)' + ' rotate(' + rotate + 'deg)' + ' scale(1);'
-       + 'background-color: ' + this.getBackgroundColor(recommendedElement, index);
-  }
-
-  getBackgroundColor(recommendedElement, index) {
-    let alpha = (recommendedElement.weight < 0.2 ? 0.2 : (recommendedElement.weight - 0.2));
-    alpha = Math.round((alpha * 10)) / 10;
-    const rgb = recommendedElement instanceof DataProcessorInvocation ? this.getSepaColor(index) : this.getActionColor(index);
-    return 'rgba(' + rgb + ',' + alpha + ')';
-  }
-
-  getSepaColor(index) {
-    return (index % 2 === 0) ? '0, 150, 136' : '0, 164, 150';
-  }
-
-  getActionColor(index) {
-    return (index % 2 === 0) ? '63, 81, 181' : '79, 101, 230';
-  }
-
-  getSkewStyle(index, recommendedElements) {
-    // transform: rotate(72deg) skew(18deg);
-    const skew = this.getSkew(recommendedElements);
-    const rotate = (index + 1) * this.getAngle(recommendedElements);
-
-    return 'transform: rotate(' + rotate + 'deg) skew(' + skew + 'deg);';
-  }
-
-  getUnskewStyleLabel(index, recommendedElements) {
-    const unskew = -(this.getSkew(recommendedElements));
-    const rotate =  (index + 1) * this.getAngle(recommendedElements);
-    const unrotate = -360 + (rotate * -1);
-
-    return 'transform: skew(' + unskew + 'deg)' + ' rotate(' + unrotate + 'deg)' + ' scale(1);'
-      + 'z-index: -1;'
-      + 'margin-left: 50%;'
-      + 'margin-top: 50%;'
-      + 'position: absolute;'
-      + 'background: white;'
-      + 'height: 50px;'
-      + 'width: 50px;'
-      + 'font-size: 16px;'
-      + 'text-align: center;'
-      + 'line-height: 50px;'
-      + 'top: 0px;';
-  }
-
-  getSkew(recommendedElements) {
-    return (90 - this.getAngle(recommendedElements));
-  }
-
-  getAngle(recommendedElements) {
-    return (360 / recommendedElements.length);
-  }
-
-  fillRemainingItems(recommendedElements) {
-    if (recommendedElements.length < 6) {
-      for (let i = recommendedElements.length; i < 6; i++) {
-        const element = {fakeElement: true, weight: 0};
-        recommendedElements.push(element);
-      }
+export class PipelineElementRecommendationComponent {
+    @Input()
+    recommendationsShown: boolean;
+
+    @Input()
+    rawPipelineModel: PipelineElementConfig[];
+
+    @Input()
+    pipelineElementDomId: string;
+
+    _recommendedElements: any;
+
+    recommendationsPrepared = false;
+
+    constructor(
+        private jsplumbService: JsplumbService,
+        public safeCss: SafeCss,
+    ) {}
+
+    prepareStyles(recommendedElements) {
+        recommendedElements.forEach((element, index) => {
+            this.setLayoutSettings(element, index, recommendedElements);
+        });
+    }
+
+    setLayoutSettings(element, index, recommendedElements) {
+        element.layoutSettings = {
+            skewStyle: element.name
+                ? this.getSkewStyle(index, recommendedElements)
+                : { opacity: 0 },
+            unskewStyle: this.getUnskewStyle(
+                element,
+                index,
+                recommendedElements,
+            ),
+            unskewStyleLabel: this.getUnskewStyleLabel(
+                index,
+                recommendedElements,
+            ),
+            type:
+                element instanceof DataProcessorInvocation ? 'sepa' : 'action',
+        };
+    }
+
+    create(recommendedElement: InvocablePipelineElementUnion) {
+        this.recommendationsShown = false;
+        this.jsplumbService.createElement(
+            this.rawPipelineModel,
+            recommendedElement,
+            this.pipelineElementDomId,
+        );
+    }
+
+    getUnskewStyle(recommendedElement, index, recommendedElements) {
+        const unskew = -this.getSkew(recommendedElements);
+        const rotate = -(90 - this.getSkew(recommendedElements) / 2);
+
+        return (
+            'transform: skew(' +
+            unskew +
+            'deg)' +
+            ' rotate(' +
+            rotate +
+            'deg)' +
+            ' scale(1);' +
+            'background-color: ' +
+            this.getBackgroundColor(recommendedElement, index)
+        );
+    }
+
+    getBackgroundColor(recommendedElement, index) {
+        let alpha =
+            recommendedElement.weight < 0.2
+                ? 0.2
+                : recommendedElement.weight - 0.2;
+        alpha = Math.round(alpha * 10) / 10;
+        const rgb =
+            recommendedElement instanceof DataProcessorInvocation
+                ? this.getSepaColor(index)
+                : this.getActionColor(index);
+        return 'rgba(' + rgb + ',' + alpha + ')';
+    }
+
+    getSepaColor(index) {
+        return index % 2 === 0 ? '0, 150, 136' : '0, 164, 150';
+    }
+
+    getActionColor(index) {
+        return index % 2 === 0 ? '63, 81, 181' : '79, 101, 230';
+    }
+
+    getSkewStyle(index, recommendedElements) {
+        // transform: rotate(72deg) skew(18deg);
+        const skew = this.getSkew(recommendedElements);
+        const rotate = (index + 1) * this.getAngle(recommendedElements);
+
+        return 'transform: rotate(' + rotate + 'deg) skew(' + skew + 'deg);';
+    }
+
+    getUnskewStyleLabel(index, recommendedElements) {
+        const unskew = -this.getSkew(recommendedElements);
+        const rotate = (index + 1) * this.getAngle(recommendedElements);
+        const unrotate = -360 + rotate * -1;
+
+        return (
+            'transform: skew(' +
+            unskew +
+            'deg)' +
+            ' rotate(' +
+            unrotate +
+            'deg)' +
+            ' scale(1);' +
+            'z-index: -1;' +
+            'margin-left: 50%;' +
+            'margin-top: 50%;' +
+            'position: absolute;' +
+            'background: white;' +
+            'height: 50px;' +
+            'width: 50px;' +
+            'font-size: 16px;' +
+            'text-align: center;' +
+            'line-height: 50px;' +
+            'top: 0px;'
+        );
+    }
+
+    getSkew(recommendedElements) {
+        return 90 - this.getAngle(recommendedElements);
+    }
+
+    getAngle(recommendedElements) {
+        return 360 / recommendedElements.length;
+    }
+
+    fillRemainingItems(recommendedElements) {
+        if (recommendedElements.length < 6) {
+            for (let i = recommendedElements.length; i < 6; i++) {
+                const element = { fakeElement: true, weight: 0 };
+                recommendedElements.push(element);
+            }
+        }
+    }
+
+    get recommendedElements() {
+        return this._recommendedElements;
+    }
+
+    @Input()
+    set recommendedElements(recommendedElements: any) {
+        this.fillRemainingItems(recommendedElements);
+        this.prepareStyles(recommendedElements);
+        this._recommendedElements = recommendedElements;
+        this.recommendationsPrepared = true;
     }
-  }
-
-  get recommendedElements() {
-    return this._recommendedElements;
-  }
-
-  @Input()
-  set recommendedElements(recommendedElements: any) {
-    this.fillRemainingItems(recommendedElements);
-    this.prepareStyles(recommendedElements);
-    this._recommendedElements = recommendedElements;
-    this.recommendationsPrepared = true;
-  }
 }
diff --git a/ui/src/app/editor/components/pipeline-element/pipeline-element.component.html b/ui/src/app/editor/components/pipeline-element/pipeline-element.component.html
index 60a30dc8f..0ef40b4a2 100644
--- a/ui/src/app/editor/components/pipeline-element/pipeline-element.component.html
+++ b/ui/src/app/editor/components/pipeline-element/pipeline-element.component.html
@@ -16,7 +16,10 @@
   ~
   -->
 
-<img [src]="image" *ngIf="showImage" style="{{iconSizeCss()}}">
-<span *ngIf="!showImage" [ngClass]="iconStandSize ? 'text-small<' : 'element-text-icon'">
-            {{iconText}}
+<img [src]="image" *ngIf="showImage" style="{{ iconSizeCss() }}" />
+<span
+    *ngIf="!showImage"
+    [ngClass]="iconStandSize ? 'text-small<' : 'element-text-icon'"
+>
+    {{ iconText }}
 </span>
diff --git a/ui/src/app/editor/components/pipeline-element/pipeline-element.component.ts b/ui/src/app/editor/components/pipeline-element/pipeline-element.component.ts
index f6ac75cb0..b987980ec 100644
--- a/ui/src/app/editor/components/pipeline-element/pipeline-element.component.ts
+++ b/ui/src/app/editor/components/pipeline-element/pipeline-element.component.ts
@@ -16,20 +16,18 @@
  *
  */
 
-import { Component, Input, OnInit, } from '@angular/core';
+import { Component, Input } from '@angular/core';
 import { RestApi } from '../../../services/rest-api.service';
 import { ElementIconText } from '../../../services/get-element-icon-text.service';
 import { PipelineElementUnion } from '../../model/editor.model';
 import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
 
-
 @Component({
-    selector: 'pipeline-element',
+    selector: 'sp-pipeline-element',
     templateUrl: './pipeline-element.component.html',
-    styleUrls: ['./pipeline-element.component.css']
+    styleUrls: ['./pipeline-element.component.css'],
 })
-export class PipelineElementComponent implements OnInit {
-
+export class PipelineElementComponent {
     showImage: any;
     iconText: any;
 
@@ -47,19 +45,20 @@ export class PipelineElementComponent implements OnInit {
     iconUrl: any;
     image: SafeUrl;
 
-    constructor(private restApi: RestApi,
-                private elementIconText: ElementIconText,
-                private sanitizer: DomSanitizer) {
-
-    }
-
-    ngOnInit(): void {
-
-    }
+    constructor(
+        private restApi: RestApi,
+        private elementIconText: ElementIconText,
+        private sanitizer: DomSanitizer,
+    ) {}
 
     checkImageAvailable() {
-        if (this.pipelineElement.includesAssets && this.pipelineElement.includedAssets.indexOf('icon.png') > -1) {
-            this.image = this.sanitizer.bypassSecurityTrustUrl(this.makeAssetIconUrl());
+        if (
+            this.pipelineElement.includesAssets &&
+            this.pipelineElement.includedAssets.indexOf('icon.png') > -1
+        ) {
+            this.image = this.sanitizer.bypassSecurityTrustUrl(
+                this.makeAssetIconUrl(),
+            );
             this.showImage = true;
         } else {
             this.showImage = false;
@@ -89,8 +88,9 @@ export class PipelineElementComponent implements OnInit {
     @Input()
     set pipelineElement(pipelineElement: PipelineElementUnion) {
         this.pipelineElement_ = pipelineElement;
-        this.iconText =  this.elementIconText.getElementIconText(this.pipelineElement.name);
+        this.iconText = this.elementIconText.getElementIconText(
+            this.pipelineElement.name,
+        );
         this.checkImageAvailable();
     }
-
 }
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.html b/ui/src/app/editor/components/pipeline/pipeline.component.html
index 5a2def9d0..7cd3a3206 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.html
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.html
@@ -15,50 +15,92 @@
   ~ limitations under the License.
   ~
   -->
-<div [attr.data-jtk-managed]="pipelineElement.payload.dom"
-     id="{{pipelineElement.payload.dom}}"
-     style="{{getElementCss(pipelineElement.settings)}}"
-     (click)="updateOptionsClick(pipelineElement.payload.dom)"
-     (mouseenter)="updateMouseover(pipelineElement.payload.dom)"
-     (mouseleave)="updateMouseover('')"
-     *ngFor="let pipelineElement of rawPipelineModel | enabledPipelineElement" class="sp-no-pan">
-    <div style="z-index:5;"
-         [ngClass]="getElementCssClasses(pipelineElement)">
-        <div class="pipeline-element-progress-container sp-fade" *ngIf="pipelineElement.settings.loadingStatus">
-            <mat-spinner [mode]="'indeterminate'" class="pipeline-element-progress" [diameter]="40"
-                         color="accent"></mat-spinner>
+<div
+    [attr.data-jtk-managed]="pipelineElement.payload.dom"
+    id="{{ pipelineElement.payload.dom }}"
+    style="{{ getElementCss(pipelineElement.settings) }}"
+    (click)="updateOptionsClick(pipelineElement.payload.dom)"
+    (mouseenter)="updateMouseover(pipelineElement.payload.dom)"
+    (mouseleave)="updateMouseover('')"
+    *ngFor="let pipelineElement of rawPipelineModel | enabledPipelineElement"
+    class="sp-no-pan"
+>
+    <div style="z-index: 5" [ngClass]="getElementCssClasses(pipelineElement)">
+        <div
+            class="pipeline-element-progress-container sp-fade"
+            *ngIf="pipelineElement.settings.loadingStatus"
+        >
+            <mat-spinner
+                [mode]="'indeterminate'"
+                class="pipeline-element-progress"
+                [diameter]="40"
+                color="accent"
+            ></mat-spinner>
         </div>
-        <div class="pipeline-element-loading-container sp-fade-opacity"
-             *ngIf="pipelineElement.settings.loadingStatus"></div>
-        <div class="pipeline-element-configuration-status {{pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'}}" *ngIf="!preview">
-            <i class="material-icons pipeline-element-configuration-invalid-icon" *ngIf="pipelineElement.settings.completed === 3">
+        <div
+            class="pipeline-element-loading-container sp-fade-opacity"
+            *ngIf="pipelineElement.settings.loadingStatus"
+        ></div>
+        <div
+            class="pipeline-element-configuration-status {{
+                pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'
+            }}"
+            *ngIf="!preview"
+        >
+            <i
+                class="material-icons pipeline-element-configuration-invalid-icon"
+                *ngIf="pipelineElement.settings.completed === 3"
+            >
                 warning
             </i>
-            <i class="material-icons pipeline-element-configuration-modified-icon" *ngIf="pipelineElement.settings.completed === 2">
+            <i
+                class="material-icons pipeline-element-configuration-modified-icon"
+                *ngIf="pipelineElement.settings.completed === 2"
+            >
                 warning
             </i>
-            <i class="material-icons pipeline-element-configuration-ok-icon" *ngIf="pipelineElement.settings.completed === 1">
+            <i
+                class="material-icons pipeline-element-configuration-ok-icon"
+                *ngIf="pipelineElement.settings.completed === 1"
+            >
                 check_circle
             </i>
         </div>
-        <pipeline-element [pipelineElement]="pipelineElement.payload" [preview]="preview"></pipeline-element>
+        <sp-pipeline-element
+            [pipelineElement]="pipelineElement.payload"
+            [preview]="preview"
+        ></sp-pipeline-element>
     </div>
-    <pipeline-element-options *ngIf="!preview"
-                              (delete)="handleDeleteOption($event)"
-                              (customize)="showCustomizeDialog($event)"
-                              [currentMouseOverElement]="currentMouseOverElement"
-                              [pipelineValid]="pipelineValid"
-                              [allElements]="allElements"
-                              [pipelineElement]="pipelineElement"
-                              [rawPipelineModel]="rawPipelineModel"
-                              [pipelineElementId]="(pipelineElement.type == 'stream' || pipelineElement.type == 'set') ? pipelineElement.payload.elementId : pipelineElement.payload.belongsTo"
-                              [internalId]="pipelineElement.payload.dom"
-                              [attr.data-cy]="'sp-pe-menu-' + pipelineElement.payload.name.toLowerCase().replaceAll(' ', '_')">
-    </pipeline-element-options>
-    <pipeline-element-preview
-            *ngIf="previewModeActive && (pipelinePreview.supportedPipelineElementDomIds.indexOf(pipelineElement.payload.dom) > -1)"
-            [previewId]="pipelinePreview.previewId"
-            [pipelineElementDomId]="pipelineElement.payload.dom">
-
-    </pipeline-element-preview>
+    <sp-pipeline-element-options
+        *ngIf="!preview"
+        (delete)="handleDeleteOption($event)"
+        (customize)="showCustomizeDialog($event)"
+        [currentMouseOverElement]="currentMouseOverElement"
+        [pipelineValid]="pipelineValid"
+        [allElements]="allElements"
+        [pipelineElement]="pipelineElement"
+        [rawPipelineModel]="rawPipelineModel"
+        [pipelineElementId]="
+            pipelineElement.type === 'stream' || pipelineElement.type === 'set'
+                ? pipelineElement.payload.elementId
+                : pipelineElement.payload.belongsTo
+        "
+        [internalId]="pipelineElement.payload.dom"
+        [attr.data-cy]="
+            'sp-pe-menu-' +
+            pipelineElement.payload.name.toLowerCase().replaceAll(' ', '_')
+        "
+    >
+    </sp-pipeline-element-options>
+    <sp-pipeline-element-preview
+        *ngIf="
+            previewModeActive &&
+            pipelinePreview.supportedPipelineElementDomIds.indexOf(
+                pipelineElement.payload.dom
+            ) > -1
+        "
+        [previewId]="pipelinePreview.previewId"
+        [pipelineElementDomId]="pipelineElement.payload.dom"
+    >
+    </sp-pipeline-element-preview>
 </div>
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.ts b/ui/src/app/editor/components/pipeline/pipeline.component.ts
index 4e6598b13..fd9ce2c44 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -21,505 +21,684 @@ import { JsplumbService } from '../../services/jsplumb.service';
 import { PipelineEditorService } from '../../services/pipeline-editor.service';
 import { JsplumbBridge } from '../../services/jsplumb-bridge.service';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
-import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
 import {
-  InvocablePipelineElementUnion,
-  PipelineElementConfig,
-  PipelineElementConfigurationStatus,
-  PipelineElementUnion
+    Component,
+    EventEmitter,
+    Input,
+    NgZone,
+    OnDestroy,
+    OnInit,
+    Output,
+} from '@angular/core';
+import {
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+    PipelineElementConfigurationStatus,
+    PipelineElementUnion,
 } from '../../model/editor.model';
 import {
-  CustomOutputStrategy,
-  DataProcessorInvocation,
-  DataSinkInvocation,
-  Notification,
-  Pipeline,
-  PipelineCanvasMetadata,
-  PipelineEdgeValidation,
-  PipelineModificationMessage,
-  PipelinePreviewModel,
-  SpDataSet,
-  SpDataStream
+    CustomOutputStrategy,
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    Notification,
+    Pipeline,
+    PipelineCanvasMetadata,
+    PipelineEdgeValidation,
+    PipelineModificationMessage,
+    PipelinePreviewModel,
+    SpDataSet,
+    SpDataStream,
 } from '@streampipes/platform-services';
 import { ObjectProvider } from '../../services/object-provider.service';
 import { CustomizeComponent } from '../../dialog/customize/customize.component';
-import { DialogService, PanelType, ConfirmDialogComponent } from '@streampipes/shared-ui';
+import {
+    DialogService,
+    PanelType,
+    ConfirmDialogComponent,
+} from '@streampipes/shared-ui';
 import { EditorService } from '../../services/editor.service';
 import { MatchingErrorComponent } from '../../dialog/matching-error/matching-error.component';
 import { MatDialog } from '@angular/material/dialog';
 import { forkJoin } from 'rxjs';
 import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
 import { PipelinePositioningService } from '../../services/pipeline-positioning.service';
-import { EVENT_CONNECTION_ABORT, EVENT_CONNECTION_DRAG } from '@jsplumb/browser-ui';
-import { EVENT_CONNECTION, EVENT_CONNECTION_DETACHED, EVENT_CONNECTION_MOVED } from '@jsplumb/core';
+import {
+    EVENT_CONNECTION_ABORT,
+    EVENT_CONNECTION_DRAG,
+} from '@jsplumb/browser-ui';
+import {
+    EVENT_CONNECTION,
+    EVENT_CONNECTION_DETACHED,
+    EVENT_CONNECTION_MOVED,
+} from '@jsplumb/core';
 import { PipelineStyleService } from '../../services/pipeline-style.service';
 
 @Component({
-  selector: 'pipeline',
-  templateUrl: './pipeline.component.html',
-  styleUrls: ['./pipeline.component.css']
+    selector: 'sp-pipeline',
+    templateUrl: './pipeline.component.html',
+    styleUrls: ['./pipeline.component.css'],
 })
 export class PipelineComponent implements OnInit, OnDestroy {
+    @Input()
+    pipelineValid: boolean;
 
-  @Input()
-  pipelineValid: boolean;
-
-  @Input()
-  canvasId: string;
-
-  @Input()
-  rawPipelineModel: PipelineElementConfig[];
-
-  @Input()
-  allElements: PipelineElementUnion[];
-
-  @Input()
-  preview: boolean;
-
-  @Input()
-  pipelineCached: boolean;
-
-  @Output()
-  pipelineCachedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
-
-  @Input()
-  pipelineCacheRunning: boolean;
-
-  @Input()
-  pipelineCanvasMetadata: PipelineCanvasMetadata;
-
-  @Output()
-  pipelineCacheRunningChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
-
-  currentMouseOverElement: string;
-  currentPipelineModel: Pipeline;
-  idCounter: any;
-  currentZoomLevel: any;
-
-  canvasWidth = '100%';
-  canvasHeight = '100%';
-
-  JsplumbBridge: JsplumbBridge;
-
-  previewModeActive = false;
-  pipelinePreview: PipelinePreviewModel;
-
-  constructor(private jsplumbService: JsplumbService,
-              private pipelineEditorService: PipelineEditorService,
-              private pipelinePositioningService: PipelinePositioningService,
-              private jsplumbFactoryService: JsplumbFactoryService,
-              private objectProvider: ObjectProvider,
-              private editorService: EditorService,
-              private shepherdService: ShepherdService,
-              private pipelineStyleService: PipelineStyleService,
-              private pipelineValidationService: PipelineValidationService,
-              private dialogService: DialogService,
-              private dialog: MatDialog,
-              private ngZone: NgZone) {
-    this.currentMouseOverElement = '';
-    this.currentPipelineModel = new Pipeline();
-    this.idCounter = 0;
-
-    this.currentZoomLevel = 1;
-  }
-
-  ngOnInit() {
-    this.JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(this.preview);
-    this.initAssembly();
-    this.initPlumb();
-  }
-
-  validatePipeline() {
-    setTimeout(() => {
-      this.ngZone.run(() => {
-        this.pipelineValid = this.pipelineValidationService
-          .isValidPipeline(this.rawPipelineModel.filter(pe => !(pe.settings.disabled)), this.preview);
-      });
-    });
-  }
-
-  ngOnDestroy() {
-    this.deletePipelineElementPreview(false);
-    this.jsplumbFactoryService.destroy(this.preview);
-  }
-
-  updateMouseover(elementId) {
-    this.currentMouseOverElement = elementId;
-  }
-
-  updateOptionsClick(elementId) {
-    this.currentMouseOverElement = this.currentMouseOverElement === elementId ? '' : elementId;
-  }
-
-  getElementCss(currentPipelineElementSettings) {
-    return 'position:absolute;'
-      + (this.preview ? 'width:75px;' : 'width:90px;')
-      + (this.preview ? 'height:75px;' : 'height:90px;')
-      + 'left: ' + currentPipelineElementSettings.position.x + 'px; '
-      + 'top: ' + currentPipelineElementSettings.position.y + 'px; ';
-  }
-
-  getElementCssClasses(currentPipelineElement) {
-    return currentPipelineElement.type + ' ' + (currentPipelineElement.settings.openCustomize ? '' : '')
-      + currentPipelineElement.settings.connectable + ' '
-      + currentPipelineElement.settings.displaySettings;
-  }
-
-  isStreamInPipeline() {
-    return this.isInPipeline('stream');
-  }
-
-  isSetInPipeline() {
-    return this.isInPipeline('set');
-  }
-
-  isInPipeline(type) {
-    return this.rawPipelineModel.some(x => (x.type === type && !(x.settings.disabled)));
-  }
-
-  showMixedStreamAlert() {
-    this.dialog.open(ConfirmDialogComponent, {
-      width: '500px',
-      data: {
-        'title': 'Currently, it is not possible to mix data streams and data sets in a single pipeline.',
-        'confirmAndCancel': false,
-        'okTitle': 'Ok',
-      },
-    });
-  }
-
-  findPipelineElementByElementId(elementId: string) {
-    return this.allElements.find(a => a.elementId === elementId);
-  }
-
-  initAssembly() {
-    ($('#assembly') as any).droppable({
-      tolerance: 'fit',
-      drop: (element, ui) => {
-        const pipelineElementId = ui.draggable.data('pe');
-        const pipelineElement: PipelineElementUnion = this.findPipelineElementByElementId(pipelineElementId);
-        if (ui.draggable.hasClass('draggable-pipeline-element')) {
-          this.editorService.makePipelineAssemblyEmpty(false);
-          const newElementId = pipelineElement.elementId + ':' + this.jsplumbService.makeId(5);
-          const pipelineElementConfig = this.jsplumbService.createNewPipelineElementConfig(pipelineElement,
-            this.pipelineEditorService.getCoordinates(ui, this.currentZoomLevel),
-            false,
-            false,
-            newElementId);
-          if ((this.isStreamInPipeline() && pipelineElementConfig.type === 'set') ||
-            this.isSetInPipeline() && pipelineElementConfig.type === 'stream') {
-            this.showMixedStreamAlert();
-          } else {
-            this.rawPipelineModel.push(pipelineElementConfig);
-            if (pipelineElementConfig.type === 'set') {
-              setTimeout(() => {
-                this.editorService.updateDataSet(pipelineElementConfig.payload).subscribe(data => {
-                  (pipelineElementConfig.payload as SpDataSet).eventGrounding = data.eventGrounding;
-                  (pipelineElementConfig.payload as SpDataSet).datasetInvocationId = data.invocationId;
-                  this.jsplumbService.dataStreamDropped(
-                    pipelineElementConfig.payload.dom,
-                    pipelineElementConfig.payload as SpDataSet,
-                    true,
-                    false);
-                });
-              }, 0);
-            } else if (pipelineElementConfig.type === 'stream') {
-              this.checkTopicModel(pipelineElementConfig);
-            } else if (pipelineElementConfig.type === 'sepa') {
-              setTimeout(() => {
-                this.jsplumbService.dataProcessorDropped(
-                  pipelineElementConfig.payload.dom,
-                  pipelineElementConfig.payload as DataProcessorInvocation,
-                  true,
-                  false
-                );
-              }, 10);
-            } else if (pipelineElementConfig.type === 'action') {
-              setTimeout(() => {
-                this.jsplumbService.dataSinkDropped(
-                  pipelineElementConfig.payload.dom,
-                  pipelineElementConfig.payload as DataSinkInvocation,
-                  true,
-                  false);
-              }, 10);
-            }
-            if (this.shepherdService.isTourActive()) {
-              this.shepherdService.trigger('drop-' + pipelineElementConfig.type);
-            }
-          }
+    @Input()
+    canvasId: string;
+
+    @Input()
+    rawPipelineModel: PipelineElementConfig[];
+
+    @Input()
+    allElements: PipelineElementUnion[];
+
+    @Input()
+    preview: boolean;
+
+    @Input()
+    pipelineCached: boolean;
+
+    @Output()
+    pipelineCachedChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
+
+    @Input()
+    pipelineCacheRunning: boolean;
+
+    @Input()
+    pipelineCanvasMetadata: PipelineCanvasMetadata;
+
+    @Output()
+    pipelineCacheRunningChanged: EventEmitter<boolean> =
+        new EventEmitter<boolean>();
+
+    currentMouseOverElement: string;
+    currentPipelineModel: Pipeline;
+    idCounter: any;
+    currentZoomLevel: any;
+
+    canvasWidth = '100%';
+    canvasHeight = '100%';
+
+    JsplumbBridge: JsplumbBridge;
+
+    previewModeActive = false;
+    pipelinePreview: PipelinePreviewModel;
+
+    constructor(
+        private jsplumbService: JsplumbService,
+        private pipelineEditorService: PipelineEditorService,
+        private pipelinePositioningService: PipelinePositioningService,
+        private jsplumbFactoryService: JsplumbFactoryService,
+        private objectProvider: ObjectProvider,
+        private editorService: EditorService,
+        private shepherdService: ShepherdService,
+        private pipelineStyleService: PipelineStyleService,
+        private pipelineValidationService: PipelineValidationService,
+        private dialogService: DialogService,
+        private dialog: MatDialog,
+        private ngZone: NgZone,
+    ) {
+        this.currentMouseOverElement = '';
+        this.currentPipelineModel = new Pipeline();
+        this.idCounter = 0;
+
+        this.currentZoomLevel = 1;
+    }
+
+    ngOnInit() {
+        this.JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(
+            this.preview,
+        );
+        this.initAssembly();
+        this.initPlumb();
+    }
+
+    validatePipeline() {
+        setTimeout(() => {
+            this.ngZone.run(() => {
+                this.pipelineValid =
+                    this.pipelineValidationService.isValidPipeline(
+                        this.rawPipelineModel.filter(
+                            pe => !pe.settings.disabled,
+                        ),
+                        this.preview,
+                    );
+            });
+        });
+    }
+
+    ngOnDestroy() {
+        this.deletePipelineElementPreview(false);
+        this.jsplumbFactoryService.destroy(this.preview);
+    }
+
+    updateMouseover(elementId) {
+        this.currentMouseOverElement = elementId;
+    }
+
+    updateOptionsClick(elementId) {
+        this.currentMouseOverElement =
+            this.currentMouseOverElement === elementId ? '' : elementId;
+    }
+
+    getElementCss(currentPipelineElementSettings) {
+        return (
+            'position:absolute;' +
+            (this.preview ? 'width:75px;' : 'width:90px;') +
+            (this.preview ? 'height:75px;' : 'height:90px;') +
+            'left: ' +
+            currentPipelineElementSettings.position.x +
+            'px; ' +
+            'top: ' +
+            currentPipelineElementSettings.position.y +
+            'px; '
+        );
+    }
+
+    getElementCssClasses(currentPipelineElement) {
+        return (
+            currentPipelineElement.type +
+            ' ' +
+            (currentPipelineElement.settings.openCustomize ? '' : '') +
+            currentPipelineElement.settings.connectable +
+            ' ' +
+            currentPipelineElement.settings.displaySettings
+        );
+    }
+
+    isStreamInPipeline() {
+        return this.isInPipeline('stream');
+    }
+
+    isSetInPipeline() {
+        return this.isInPipeline('set');
+    }
+
+    isInPipeline(type) {
+        return this.rawPipelineModel.some(
+            x => x.type === type && !x.settings.disabled,
+        );
+    }
+
+    showMixedStreamAlert() {
+        this.dialog.open(ConfirmDialogComponent, {
+            width: '500px',
+            data: {
+                title: 'Currently, it is not possible to mix data streams and data sets in a single pipeline.',
+                confirmAndCancel: false,
+                okTitle: 'Ok',
+            },
+        });
+    }
+
+    findPipelineElementByElementId(elementId: string) {
+        return this.allElements.find(a => a.elementId === elementId);
+    }
+
+    initAssembly() {
+        ($('#assembly') as any).droppable({
+            tolerance: 'fit',
+            drop: (element, ui) => {
+                const pipelineElementId = ui.draggable.data('pe');
+                const pipelineElement: PipelineElementUnion =
+                    this.findPipelineElementByElementId(pipelineElementId);
+                if (ui.draggable.hasClass('draggable-pipeline-element')) {
+                    this.editorService.makePipelineAssemblyEmpty(false);
+                    const newElementId =
+                        pipelineElement.elementId +
+                        ':' +
+                        this.jsplumbService.makeId(5);
+                    const pipelineElementConfig =
+                        this.jsplumbService.createNewPipelineElementConfig(
+                            pipelineElement,
+                            this.pipelineEditorService.getCoordinates(
+                                ui,
+                                this.currentZoomLevel,
+                            ),
+                            false,
+                            false,
+                            newElementId,
+                        );
+                    if (
+                        (this.isStreamInPipeline() &&
+                            pipelineElementConfig.type === 'set') ||
+                        (this.isSetInPipeline() &&
+                            pipelineElementConfig.type === 'stream')
+                    ) {
+                        this.showMixedStreamAlert();
+                    } else {
+                        this.rawPipelineModel.push(pipelineElementConfig);
+                        if (pipelineElementConfig.type === 'set') {
+                            setTimeout(() => {
+                                this.editorService
+                                    .updateDataSet(
+                                        pipelineElementConfig.payload,
+                                    )
+                                    .subscribe(data => {
+                                        (
+                                            pipelineElementConfig.payload as SpDataSet
+                                        ).eventGrounding = data.eventGrounding;
+                                        (
+                                            pipelineElementConfig.payload as SpDataSet
+                                        ).datasetInvocationId =
+                                            data.invocationId;
+                                        this.jsplumbService.dataStreamDropped(
+                                            pipelineElementConfig.payload.dom,
+                                            pipelineElementConfig.payload as SpDataSet,
+                                            true,
+                                            false,
+                                        );
+                                    });
+                            }, 0);
+                        } else if (pipelineElementConfig.type === 'stream') {
+                            this.checkTopicModel(pipelineElementConfig);
+                        } else if (pipelineElementConfig.type === 'sepa') {
+                            setTimeout(() => {
+                                this.jsplumbService.dataProcessorDropped(
+                                    pipelineElementConfig.payload.dom,
+                                    pipelineElementConfig.payload as DataProcessorInvocation,
+                                    true,
+                                    false,
+                                );
+                            }, 10);
+                        } else if (pipelineElementConfig.type === 'action') {
+                            setTimeout(() => {
+                                this.jsplumbService.dataSinkDropped(
+                                    pipelineElementConfig.payload.dom,
+                                    pipelineElementConfig.payload as DataSinkInvocation,
+                                    true,
+                                    false,
+                                );
+                            }, 10);
+                        }
+                        if (this.shepherdService.isTourActive()) {
+                            this.shepherdService.trigger(
+                                'drop-' + pipelineElementConfig.type,
+                            );
+                        }
+                    }
+                }
+                this.JsplumbBridge.repaintEverything();
+                this.validatePipeline();
+                this.triggerPipelineCacheUpdate();
+            },
+        });
+    }
+
+    checkTopicModel(pipelineElementConfig: PipelineElementConfig) {
+        console.log(pipelineElementConfig);
+        setTimeout(() => {
+            this.jsplumbService.dataStreamDropped(
+                pipelineElementConfig.payload.dom,
+                pipelineElementConfig.payload as SpDataStream,
+                true,
+                false,
+            );
+        }, 10);
+
+        const streamDescription = pipelineElementConfig.payload as SpDataStream;
+        if (
+            streamDescription.eventGrounding.transportProtocols[0]
+                .topicDefinition['@class'] ===
+            'org.apache.streampipes.model.grounding.WildcardTopicDefinition'
+        ) {
+            // this.EditorDialogManager.showCustomizeStreamDialog(streamDescription);
+        }
+    }
+
+    handleDeleteOption(pipelineElement: PipelineElementConfig) {
+        this.JsplumbBridge.removeAllEndpoints(pipelineElement.payload.dom);
+        this.rawPipelineModel = this.rawPipelineModel.filter(
+            pe => !(pe.payload.dom === pipelineElement.payload.dom),
+        );
+        if (this.rawPipelineModel.every(pe => pe.settings.disabled)) {
+            this.editorService.makePipelineAssemblyEmpty(true);
         }
         this.JsplumbBridge.repaintEverything();
         this.validatePipeline();
         this.triggerPipelineCacheUpdate();
-      }
-    });
-  }
-
-  checkTopicModel(pipelineElementConfig: PipelineElementConfig) {
-    console.log(pipelineElementConfig);
-    setTimeout(() => {
-      this.jsplumbService.dataStreamDropped(pipelineElementConfig.payload.dom,
-        pipelineElementConfig.payload as SpDataStream,
-        true,
-        false);
-    }, 10);
-
-    const streamDescription = pipelineElementConfig.payload as SpDataStream;
-    if (streamDescription
-      .eventGrounding
-      .transportProtocols[0]
-      .topicDefinition['@class'] === 'org.apache.streampipes.model.grounding.WildcardTopicDefinition') {
-      // this.EditorDialogManager.showCustomizeStreamDialog(streamDescription);
     }
-  }
 
-  handleDeleteOption(pipelineElement: PipelineElementConfig) {
-    this.JsplumbBridge.removeAllEndpoints(pipelineElement.payload.dom);
-    this.rawPipelineModel = this.rawPipelineModel.filter(pe => !(pe.payload.dom === pipelineElement.payload.dom));
-    if (this.rawPipelineModel.every(pe => pe.settings.disabled)) {
-      this.editorService.makePipelineAssemblyEmpty(true);
+    initPlumb() {
+        this.JsplumbBridge.unbind(EVENT_CONNECTION);
+
+        this.JsplumbBridge.bind(EVENT_CONNECTION_MOVED, info => {
+            const pe = this.objectProvider.findElement(
+                info.newTargetEndpoint.elementId,
+                this.rawPipelineModel,
+            );
+            const oldPe = this.objectProvider.findElement(
+                info.originalTargetEndpoint.elementId,
+                this.rawPipelineModel,
+            );
+            (oldPe.payload as InvocablePipelineElementUnion).configured = false;
+            (pe.payload as InvocablePipelineElementUnion).configured = false;
+        });
+
+        this.JsplumbBridge.bind(EVENT_CONNECTION_DETACHED, info => {
+            const pe = this.objectProvider.findElement(
+                info.targetEndpoint.elementId,
+                this.rawPipelineModel,
+            );
+            (pe.payload as InvocablePipelineElementUnion).configured = false;
+            pe.settings.openCustomize = true;
+            info.targetEndpoint.setType('empty');
+            this.JsplumbBridge.repaintEverything();
+            this.validatePipeline();
+        });
+
+        this.JsplumbBridge.bind(EVENT_CONNECTION_DRAG, () => {
+            this.JsplumbBridge.selectEndpoints().each(endpoint => {
+                if (endpoint.isTarget && endpoint.connections.length === 0) {
+                    endpoint.setType('highlight');
+                }
+            });
+            this.JsplumbBridge.repaintEverything();
+        });
+        this.JsplumbBridge.bind(EVENT_CONNECTION_ABORT, () => {
+            this.JsplumbBridge.selectEndpoints().each(endpoint => {
+                if (endpoint.isTarget && endpoint.connections.length === 0) {
+                    endpoint.setType('empty');
+                }
+            });
+            this.JsplumbBridge.repaintEverything();
+        });
+
+        this.JsplumbBridge.bind(EVENT_CONNECTION, info => {
+            const pe = this.objectProvider.findElement(
+                info.target.id,
+                this.rawPipelineModel,
+            );
+            if (pe.settings.openCustomize) {
+                this.currentPipelineModel = this.objectProvider.makePipeline(
+                    this.rawPipelineModel,
+                );
+                pe.settings.loadingStatus = true;
+                this.objectProvider
+                    .updatePipeline(this.currentPipelineModel)
+                    .subscribe(
+                        pipelineModificationMessage => {
+                            pe.settings.loadingStatus = false;
+                            const edgeValidations =
+                                this.getTargetEdgeValidations(
+                                    pipelineModificationMessage,
+                                    info.target.id,
+                                );
+                            const currentConnectionValid =
+                                this.currentConnectionValid(
+                                    pe,
+                                    edgeValidations,
+                                );
+                            if (currentConnectionValid) {
+                                this.validatePipeline();
+                                this.modifyPipeline(
+                                    pipelineModificationMessage,
+                                );
+                                if (
+                                    this.jsplumbService.isFullyConnected(
+                                        pe,
+                                        this.preview,
+                                    )
+                                ) {
+                                    const payload =
+                                        pe.payload as InvocablePipelineElementUnion;
+                                    if (
+                                        (payload.staticProperties &&
+                                            payload.staticProperties.length >
+                                                0) ||
+                                        this.isCustomOutput(pe)
+                                    ) {
+                                        this.showCustomizeDialog(pe);
+                                    } else {
+                                        (
+                                            pe.payload as InvocablePipelineElementUnion
+                                        ).configured = true;
+                                        this.pipelineStyleService.updatePeConfigurationStatus(
+                                            pe,
+                                            PipelineElementConfigurationStatus.OK,
+                                        );
+                                        this.announceConfiguredElement(pe);
+                                        this.triggerPipelineCacheUpdate();
+                                    }
+                                }
+                            } else {
+                                this.JsplumbBridge.detach(info.connection);
+                                const invalidEdgeValidation =
+                                    edgeValidations.find(
+                                        e => e.sourceId === info.source.id,
+                                    );
+                                if (invalidEdgeValidation) {
+                                    this.showMatchingErrorDialog(
+                                        invalidEdgeValidation.status
+                                            .notifications,
+                                    );
+                                }
+                            }
+                        },
+                        status => {
+                            pe.settings.loadingStatus = false;
+                            this.showErrorDialog(
+                                status.error.title,
+                                status.error.description,
+                            );
+                        },
+                    );
+            }
+        });
+
+        window.onresize = () => {
+            this.JsplumbBridge.repaintEverything();
+        };
+    }
+
+    currentConnectionValid(
+        pe: PipelineElementConfig,
+        targetEdges: PipelineEdgeValidation[],
+    ) {
+        const entity = pe.payload as InvocablePipelineElementUnion;
+        return targetEdges.every(
+            e => e.status.validationStatusType === 'COMPLETE',
+        );
     }
-    this.JsplumbBridge.repaintEverything();
-    this.validatePipeline();
-    this.triggerPipelineCacheUpdate();
-  }
-
-  initPlumb() {
-    this.JsplumbBridge.unbind(EVENT_CONNECTION);
-
-    this.JsplumbBridge.bind(EVENT_CONNECTION_MOVED, (info) => {
-      const pe = this.objectProvider.findElement(info.newTargetEndpoint.elementId, this.rawPipelineModel);
-      const oldPe = this.objectProvider.findElement(info.originalTargetEndpoint.elementId, this.rawPipelineModel);
-      (oldPe.payload as InvocablePipelineElementUnion).configured = false;
-      (pe.payload as InvocablePipelineElementUnion).configured = false;
-    });
-
-    this.JsplumbBridge.bind(EVENT_CONNECTION_DETACHED, (info) => {
-      const pe = this.objectProvider.findElement(info.targetEndpoint.elementId, this.rawPipelineModel);
-      (pe.payload as InvocablePipelineElementUnion).configured = false;
-      pe.settings.openCustomize = true;
-      info.targetEndpoint.setType('empty');
-      this.JsplumbBridge.repaintEverything();
-      this.validatePipeline();
-    });
-
-    this.JsplumbBridge.bind(EVENT_CONNECTION_DRAG, () => {
-      this.JsplumbBridge.selectEndpoints().each(endpoint => {
-        if (endpoint.isTarget && endpoint.connections.length === 0) {
-          endpoint.setType('highlight');
+
+    getTargetEdgeValidations(
+        pipelineModificationMessage: PipelineModificationMessage,
+        targetDomId: string,
+    ): PipelineEdgeValidation[] {
+        const edgeValidations = pipelineModificationMessage.edgeValidations;
+        return edgeValidations.filter(ev => ev.targetId === targetDomId);
+    }
+
+    modifyPipeline(pm: PipelineModificationMessage) {
+        if (pm.pipelineModifications) {
+            pm.pipelineModifications.forEach(modification => {
+                const id = modification.domId;
+                if (id !== 'undefined') {
+                    const pe = this.objectProvider.findElement(
+                        id,
+                        this.rawPipelineModel,
+                    );
+                    if (modification.staticProperties) {
+                        (
+                            pe.payload as InvocablePipelineElementUnion
+                        ).staticProperties = modification.staticProperties;
+                    }
+                    if (pe.payload instanceof DataProcessorInvocation) {
+                        if (modification.outputStrategies) {
+                            (
+                                pe.payload as DataProcessorInvocation
+                            ).outputStrategies = modification.outputStrategies;
+                        }
+                        if (modification.outputStream) {
+                            (
+                                pe.payload as DataProcessorInvocation
+                            ).outputStream = modification.outputStream;
+                        }
+                    }
+                    if (modification.inputStreams) {
+                        (
+                            pe.payload as InvocablePipelineElementUnion
+                        ).inputStreams = modification.inputStreams;
+                    }
+                    if (modification.validationInfos.length > 0) {
+                        this.pipelineStyleService.updatePeConfigurationStatus(
+                            pe,
+                            PipelineElementConfigurationStatus.MODIFIED,
+                        );
+                    }
+                }
+            });
         }
-      });
-      this.JsplumbBridge.repaintEverything();
-    });
-    this.JsplumbBridge.bind(EVENT_CONNECTION_ABORT, () => {
-      this.JsplumbBridge.selectEndpoints().each(endpoint => {
-        if (endpoint.isTarget && endpoint.connections.length === 0) {
-          endpoint.setType('empty');
+        if (pm.edgeValidations) {
+            this.pipelineStyleService.updateAllConnectorStyles(
+                pm.edgeValidations,
+            );
+            this.pipelineStyleService.updateAllEndpointStyles(
+                pm.edgeValidations,
+            );
+            this.JsplumbBridge.repaintEverything();
         }
-      });
-      this.JsplumbBridge.repaintEverything();
-    });
-
-    this.JsplumbBridge.bind(EVENT_CONNECTION, (info) => {
-      const pe = this.objectProvider.findElement(info.target.id, this.rawPipelineModel);
-      if (pe.settings.openCustomize) {
-        this.currentPipelineModel = this.objectProvider.makePipeline(this.rawPipelineModel);
-        pe.settings.loadingStatus = true;
-        this.objectProvider.updatePipeline(this.currentPipelineModel)
-          .subscribe(pipelineModificationMessage => {
-            pe.settings.loadingStatus = false;
-            const edgeValidations = this.getTargetEdgeValidations(pipelineModificationMessage, info.target.id);
-            const currentConnectionValid = this.currentConnectionValid(pe, edgeValidations);
-            if (currentConnectionValid) {
-              this.validatePipeline();
-              this.modifyPipeline(pipelineModificationMessage);
-              if (this.jsplumbService.isFullyConnected(pe, this.preview)) {
-                const payload = pe.payload as InvocablePipelineElementUnion;
-                if ((payload.staticProperties && payload.staticProperties.length > 0) || this.isCustomOutput(pe)) {
-                  this.showCustomizeDialog(pe);
-                } else {
-                  (pe.payload as InvocablePipelineElementUnion).configured = true;
-                  this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.OK);
-                  this.announceConfiguredElement(pe);
-                  this.triggerPipelineCacheUpdate();
+    }
+
+    isCustomOutput(pe) {
+        let custom = false;
+        if (pe.payload instanceof DataProcessorInvocation) {
+            pe.payload.outputStrategies.forEach(strategy => {
+                if (strategy instanceof CustomOutputStrategy) {
+                    custom = true;
                 }
-              }
-            } else {
-              this.JsplumbBridge.detach(info.connection);
-              const invalidEdgeValidation = edgeValidations.find(e => e.sourceId === info.source.id);
-              if (invalidEdgeValidation) {
-                this.showMatchingErrorDialog(invalidEdgeValidation.status.notifications);
-              }
-            }
-          }, status => {
-            pe.settings.loadingStatus = false;
-            this.showErrorDialog(status.error.title, status.error.description);
-          });
-      }
-    });
-
-    window.onresize = () => {
-      this.JsplumbBridge.repaintEverything();
-    };
-  }
-
-  currentConnectionValid(pe: PipelineElementConfig,
-                         targetEdges: PipelineEdgeValidation[]) {
-    const entity = pe.payload as InvocablePipelineElementUnion;
-    return targetEdges.every(e => e.status.validationStatusType === 'COMPLETE');
-  }
-
-  getTargetEdgeValidations(pipelineModificationMessage: PipelineModificationMessage,
-                           targetDomId: string): PipelineEdgeValidation[] {
-    const edgeValidations = pipelineModificationMessage.edgeValidations;
-    return edgeValidations.filter(ev => ev.targetId === targetDomId);
-  }
-
-  modifyPipeline(pm: PipelineModificationMessage) {
-    if (pm.pipelineModifications) {
-      pm.pipelineModifications.forEach(modification => {
-        const id = modification.domId;
-        if (id !== 'undefined') {
-          const pe = this.objectProvider.findElement(id, this.rawPipelineModel);
-          if (modification.staticProperties) {
-            (pe.payload as InvocablePipelineElementUnion).staticProperties = modification.staticProperties;
-          }
-          if (pe.payload instanceof DataProcessorInvocation) {
-            if (modification.outputStrategies) {
-              (pe.payload as DataProcessorInvocation).outputStrategies = modification.outputStrategies;
-            }
-            if (modification.outputStream) {
-              (pe.payload as DataProcessorInvocation).outputStream = modification.outputStream;
-            }
-          }
-          if (modification.inputStreams) {
-            (pe.payload as InvocablePipelineElementUnion).inputStreams = modification.inputStreams;
-          }
-          if (modification.validationInfos.length > 0) {
-            this.pipelineStyleService.updatePeConfigurationStatus(pe, PipelineElementConfigurationStatus.MODIFIED);
-          }
+            });
         }
-      });
+        return custom;
     }
-    if (pm.edgeValidations) {
-      this.pipelineStyleService.updateAllConnectorStyles(pm.edgeValidations);
-      this.pipelineStyleService.updateAllEndpointStyles(pm.edgeValidations);
-      this.JsplumbBridge.repaintEverything();
+
+    triggerPipelineCacheUpdate() {
+        setTimeout(() => {
+            this.pipelineCacheRunning = true;
+            this.pipelineCacheRunningChanged.emit(this.pipelineCacheRunning);
+            this.pipelinePositioningService.collectPipelineElementPositions(
+                this.pipelineCanvasMetadata,
+                this.rawPipelineModel,
+            );
+            const updateCachedPipeline =
+                this.editorService.updateCachedPipeline(this.rawPipelineModel);
+            const updateCachedCanvasMetadata =
+                this.editorService.updateCachedCanvasMetadata(
+                    this.pipelineCanvasMetadata,
+                );
+            forkJoin([
+                updateCachedPipeline,
+                updateCachedCanvasMetadata,
+            ]).subscribe(() => {
+                this.pipelineCacheRunning = false;
+                this.pipelineCacheRunningChanged.emit(
+                    this.pipelineCacheRunning,
+                );
+                this.pipelineCached = true;
+                this.pipelineCachedChanged.emit(this.pipelineCached);
+            });
+        });
     }
-  }
-
-  isCustomOutput(pe) {
-    let custom = false;
-    if (pe.payload instanceof DataProcessorInvocation) {
-      pe.payload.outputStrategies.forEach(strategy => {
-        if (strategy instanceof CustomOutputStrategy) {
-          custom = true;
-        }
-      });
+
+    showErrorDialog(title, description) {
+        this.dialog.open(ConfirmDialogComponent, {
+            width: '500px',
+            data: {
+                title: title,
+                subtitle: description,
+                okTitle: 'Ok',
+                confirmAndCancel: false,
+            },
+        });
     }
-    return custom;
-  }
-
-  triggerPipelineCacheUpdate() {
-    setTimeout(() => {
-      this.pipelineCacheRunning = true;
-      this.pipelineCacheRunningChanged.emit(this.pipelineCacheRunning);
-      this.pipelinePositioningService.collectPipelineElementPositions(this.pipelineCanvasMetadata, this.rawPipelineModel);
-      const updateCachedPipeline = this.editorService.updateCachedPipeline(this.rawPipelineModel);
-      const updateCachedCanvasMetadata = this.editorService.updateCachedCanvasMetadata(this.pipelineCanvasMetadata);
-      forkJoin([updateCachedPipeline, updateCachedCanvasMetadata]).subscribe(() => {
-        this.pipelineCacheRunning = false;
-        this.pipelineCacheRunningChanged.emit(this.pipelineCacheRunning);
-        this.pipelineCached = true;
-        this.pipelineCachedChanged.emit(this.pipelineCached);
-      });
-    });
-  }
-
-  showErrorDialog(title, description) {
-    this.dialog.open(ConfirmDialogComponent, {
-      width: '500px',
-      data: {
-        'title': title,
-        'subtitle': description,
-        'okTitle': 'Ok',
-        'confirmAndCancel': false
-      },
-    });
-  }
-
-  showMatchingErrorDialog(notifications: Notification[]) {
-    this.dialogService.open(MatchingErrorComponent, {
-      panelType: PanelType.STANDARD_PANEL,
-      title: 'Invalid Connection',
-      data: {
-        'notifications': notifications
-      }
-    });
-  }
-
-  showCustomizeDialog(pipelineElementConfig: PipelineElementConfig) {
-    const dialogRef = this.dialogService.open(CustomizeComponent, {
-      panelType: PanelType.SLIDE_IN_PANEL,
-      title: 'Customize ' + pipelineElementConfig.payload.name,
-      width: '50vw',
-      data: {
-        'pipelineElement': pipelineElementConfig,
-      }
-    });
-
-    dialogRef.afterClosed().subscribe(c => {
-      if (c) {
-        pipelineElementConfig.settings.openCustomize = false;
-        (pipelineElementConfig.payload as InvocablePipelineElementUnion).configured = true;
-        this.currentPipelineModel = this.objectProvider.makePipeline(this.rawPipelineModel);
-        this.objectProvider.updatePipeline(this.currentPipelineModel).subscribe(pm => {
-          this.modifyPipeline(pm);
-          // if (!(pipelineElementConfig.payload instanceof DataSinkInvocation)) {
-          //   this.JsplumbBridge.activateEndpoint('out-' + pipelineElementConfig.payload.dom, pipelineElementConfig.settings.completed);
-          // }
-          this.triggerPipelineCacheUpdate();
-          this.announceConfiguredElement(pipelineElementConfig);
-          if (this.previewModeActive) {
-            this.deletePipelineElementPreview(true);
-          }
-          this.validatePipeline();
+
+    showMatchingErrorDialog(notifications: Notification[]) {
+        this.dialogService.open(MatchingErrorComponent, {
+            panelType: PanelType.STANDARD_PANEL,
+            title: 'Invalid Connection',
+            data: {
+                notifications: notifications,
+            },
         });
-      } else {
-        this.validatePipeline();
-      }
-    });
-  }
-
-  announceConfiguredElement(pe: PipelineElementConfig) {
-    this.editorService.announceConfiguredElement(pe.payload.dom);
-  }
-
-  initiatePipelineElementPreview() {
-    if (!this.previewModeActive) {
-      const pipeline = this.objectProvider.makePipeline(this.rawPipelineModel);
-      this.editorService.initiatePipelinePreview(pipeline).subscribe(response => {
-        this.pipelinePreview = response;
-        this.previewModeActive = true;
-      });
-    } else {
-      this.deletePipelineElementPreview(false);
     }
-  }
-
-  deletePipelineElementPreview(resume: boolean) {
-    if (this.previewModeActive) {
-      this.editorService.deletePipelinePreviewRequest(this.pipelinePreview.previewId).subscribe(() => {
-        this.previewModeActive = false;
-        if (resume) {
-          this.initiatePipelineElementPreview();
+
+    showCustomizeDialog(pipelineElementConfig: PipelineElementConfig) {
+        const dialogRef = this.dialogService.open(CustomizeComponent, {
+            panelType: PanelType.SLIDE_IN_PANEL,
+            title: 'Customize ' + pipelineElementConfig.payload.name,
+            width: '50vw',
+            data: {
+                pipelineElement: pipelineElementConfig,
+            },
+        });
+
+        dialogRef.afterClosed().subscribe(c => {
+            if (c) {
+                pipelineElementConfig.settings.openCustomize = false;
+                (
+                    pipelineElementConfig.payload as InvocablePipelineElementUnion
+                ).configured = true;
+                this.currentPipelineModel = this.objectProvider.makePipeline(
+                    this.rawPipelineModel,
+                );
+                this.objectProvider
+                    .updatePipeline(this.currentPipelineModel)
+                    .subscribe(pm => {
+                        this.modifyPipeline(pm);
+                        // if (!(pipelineElementConfig.payload instanceof DataSinkInvocation)) {
+                        //   this.JsplumbBridge.activateEndpoint('out-' + pipelineElementConfig.payload.dom, pipelineElementConfig.settings.completed);
+                        // }
+                        this.triggerPipelineCacheUpdate();
+                        this.announceConfiguredElement(pipelineElementConfig);
+                        if (this.previewModeActive) {
+                            this.deletePipelineElementPreview(true);
+                        }
+                        this.validatePipeline();
+                    });
+            } else {
+                this.validatePipeline();
+            }
+        });
+    }
+
+    announceConfiguredElement(pe: PipelineElementConfig) {
+        this.editorService.announceConfiguredElement(pe.payload.dom);
+    }
+
+    initiatePipelineElementPreview() {
+        if (!this.previewModeActive) {
+            const pipeline = this.objectProvider.makePipeline(
+                this.rawPipelineModel,
+            );
+            this.editorService
+                .initiatePipelinePreview(pipeline)
+                .subscribe(response => {
+                    this.pipelinePreview = response;
+                    this.previewModeActive = true;
+                });
+        } else {
+            this.deletePipelineElementPreview(false);
+        }
+    }
+
+    deletePipelineElementPreview(resume: boolean) {
+        if (this.previewModeActive) {
+            this.editorService
+                .deletePipelinePreviewRequest(this.pipelinePreview.previewId)
+                .subscribe(() => {
+                    this.previewModeActive = false;
+                    if (resume) {
+                        this.initiatePipelineElementPreview();
+                    }
+                });
         }
-      });
     }
-  }
 
-  triggerPipelineModification() {
-    this.currentPipelineModel = this.objectProvider.makePipeline(this.rawPipelineModel);
-    this.objectProvider.updatePipeline(this.currentPipelineModel).subscribe(pm => this.modifyPipeline(pm));
-  }
+    triggerPipelineModification() {
+        this.currentPipelineModel = this.objectProvider.makePipeline(
+            this.rawPipelineModel,
+        );
+        this.objectProvider
+            .updatePipeline(this.currentPipelineModel)
+            .subscribe(pm => this.modifyPipeline(pm));
+    }
 }
diff --git a/ui/src/app/editor/constants/editor.constants.ts b/ui/src/app/editor/constants/editor.constants.ts
index bfac71a08..8eca685a2 100644
--- a/ui/src/app/editor/constants/editor.constants.ts
+++ b/ui/src/app/editor/constants/editor.constants.ts
@@ -17,9 +17,12 @@
  */
 
 export class EditorConstants {
-
-  static readonly DATA_STREAM_IDENTIFIER = 'org.apache.streampipes.model.SpDataStream';
-  static readonly DATA_SET_IDENTIFIER = 'org.apache.streampipes.model.SpDataSet';
-  static readonly DATA_PROCESSOR_IDENTIFIER = 'org.apache.streampipes.model.graph.DataProcessorInvocation';
-  static readonly DATA_SINK_IDENTIFIER = 'org.apache.streampipes.model.graph.DataSinkInvocation';
+    static readonly DATA_STREAM_IDENTIFIER =
+        'org.apache.streampipes.model.SpDataStream';
+    static readonly DATA_SET_IDENTIFIER =
+        'org.apache.streampipes.model.SpDataSet';
+    static readonly DATA_PROCESSOR_IDENTIFIER =
+        'org.apache.streampipes.model.graph.DataProcessorInvocation';
+    static readonly DATA_SINK_IDENTIFIER =
+        'org.apache.streampipes.model.graph.DataSinkInvocation';
 }
diff --git a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.html b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.html
index f20d3d542..f00245a4b 100644
--- a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.html
+++ b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.html
@@ -19,15 +19,39 @@
 <div class="sp-dialog-container">
     <div class="sp-dialog-content p-15">
         <div fxFlex="100" fxLayout="column">
-            <div *ngFor="let possibleElement of possibleElements; index as i" (click)="create(possibleElement)">
-                <div fxLayout="row" class="m-10" fxLayoutAlign="start center" [style]="styles[i]" (mouseenter)="changeStyle(i, true)" (mouseleave)="changeStyle(i, false)"
-                     [attr.data-cy]="'sp-compatible-elements-' + possibleElement.name.toLowerCase().replaceAll(' ', '_')">
-                    <div class="draggable-icon-preview {{isDataProcessor(possibleElement) ? 'sepa' : 'action'}}">
-                        <pipeline-element [pipelineElement]="possibleElement" [iconSize]="true"></pipeline-element>
+            <div
+                *ngFor="let possibleElement of possibleElements; index as i"
+                (click)="create(possibleElement)"
+            >
+                <div
+                    fxLayout="row"
+                    class="m-10"
+                    fxLayoutAlign="start center"
+                    [style]="styles[i]"
+                    (mouseenter)="changeStyle(i, true)"
+                    (mouseleave)="changeStyle(i, false)"
+                    [attr.data-cy]="
+                        'sp-compatible-elements-' +
+                        possibleElement.name.toLowerCase().replaceAll(' ', '_')
+                    "
+                >
+                    <div
+                        class="draggable-icon-preview {{
+                            isDataProcessor(possibleElement) ? 'sepa' : 'action'
+                        }}"
+                    >
+                        <sp-pipeline-element
+                            [pipelineElement]="possibleElement"
+                            [iconSize]="true"
+                        ></sp-pipeline-element>
                     </div>
                     <div fxLayout="column" fxLayoutAlign="center start">
-                        <div class="element-name">{{ possibleElement.name }}</div>
-                        <div class="element-description">{{ possibleElement.description }}</div>
+                        <div class="element-name">
+                            {{ possibleElement.name }}
+                        </div>
+                        <div class="element-description">
+                            {{ possibleElement.description }}
+                        </div>
                     </div>
                 </div>
                 <mat-divider></mat-divider>
@@ -36,9 +60,8 @@
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions">
-
         <button mat-button mat-raised-button class="mat-basic" (click)="hide()">
             Cancel
         </button>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.scss b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.scss
index 8ef9d15ce..a7fa1d497 100644
--- a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.scss
+++ b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.scss
@@ -18,23 +18,16 @@
 
 @import '../../../../scss/sp/sp-dialog.scss';
 
-
-
 .element-name {
-
 }
 
 .element-description {
-
 }
 
 .m-10 {
-  padding-top:10px;
-  padding-bottom:10px;
+    padding-top: 10px;
+    padding-bottom: 10px;
 }
 
-
-
 .list-item {
-
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
index 9c7a88e14..b9651c032 100644
--- a/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
+++ b/ui/src/app/editor/dialog/compatible-elements/compatible-elements.component.ts
@@ -20,73 +20,81 @@ import { Component, Input, OnInit } from '@angular/core';
 import { DialogRef } from '@streampipes/shared-ui';
 import { JsplumbService } from '../../services/jsplumb.service';
 import { DataProcessorInvocation } from '@streampipes/platform-services';
-import { PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import {
+    PipelineElementConfig,
+    PipelineElementUnion,
+} from '../../model/editor.model';
 
 @Component({
-  selector: 'compatible-elements',
-  templateUrl: './compatible-elements.component.html',
-  styleUrls: ['./compatible-elements.component.scss']
+    selector: 'sp-compatible-elements',
+    templateUrl: './compatible-elements.component.html',
+    styleUrls: ['./compatible-elements.component.scss'],
 })
 export class CompatibleElementsComponent implements OnInit {
-
-  @Input()
-  rawPipelineModel: PipelineElementConfig[];
-
-  @Input()
-  pipelineElementDomId: any;
-
-  @Input()
-  possibleElements: PipelineElementUnion[];
-
-  styles: any[] = [];
-
-
-  constructor(private dialogRef: DialogRef<CompatibleElementsComponent>,
-              private JsPlumbService: JsplumbService) {
-    // this.ElementIconText = ElementIconText;
-  }
-
-  ngOnInit() {
-    this.possibleElements.sort((a, b) => a.name.localeCompare(b.name));
-    this.possibleElements.forEach(pe => {
-      this.styles.push(this.makeStandardStyle());
-    });
-  }
-
-  create(possibleElement) {
-    this.JsPlumbService.createElement(this.rawPipelineModel, possibleElement, this.pipelineElementDomId);
-    this.hide();
-  }
-
-  iconText(elementId) {
-    // return this.ElementIconText.getElementIconText(elementId);
-  }
-
-  hide() {
-    // this.$mdDialog.hide();
-    this.dialogRef.close();
-  }
-
-  isDataProcessor(possibleElement: PipelineElementUnion) {
-    return possibleElement instanceof DataProcessorInvocation;
-  }
-
-  makeStandardStyle() {
-    return {
-      background: 'var(--color-bg-dialog)',
-      cursor: 'auto'
-    };
-  }
-
-  makeHoverStyle() {
-    return {
-      background: 'var(--color-bg-1)',
-      cursor: 'pointer'
-    };
-  }
-
-  changeStyle(index: number, hover: boolean) {
-    hover ? this.styles[index] = this.makeHoverStyle() : this.styles[index] = this.makeStandardStyle();
-  }
-
+    @Input()
+    rawPipelineModel: PipelineElementConfig[];
+
+    @Input()
+    pipelineElementDomId: any;
+
+    @Input()
+    possibleElements: PipelineElementUnion[];
+
+    styles: any[] = [];
+
+    constructor(
+        private dialogRef: DialogRef<CompatibleElementsComponent>,
+        private JsPlumbService: JsplumbService,
+    ) {
+        // this.ElementIconText = ElementIconText;
+    }
+
+    ngOnInit() {
+        this.possibleElements.sort((a, b) => a.name.localeCompare(b.name));
+        this.possibleElements.forEach(pe => {
+            this.styles.push(this.makeStandardStyle());
+        });
+    }
+
+    create(possibleElement) {
+        this.JsPlumbService.createElement(
+            this.rawPipelineModel,
+            possibleElement,
+            this.pipelineElementDomId,
+        );
+        this.hide();
+    }
+
+    iconText(elementId) {
+        // return this.ElementIconText.getElementIconText(elementId);
+    }
+
+    hide() {
+        // this.$mdDialog.hide();
+        this.dialogRef.close();
+    }
+
+    isDataProcessor(possibleElement: PipelineElementUnion) {
+        return possibleElement instanceof DataProcessorInvocation;
+    }
+
+    makeStandardStyle() {
+        return {
+            background: 'var(--color-bg-dialog)',
+            cursor: 'auto',
+        };
+    }
+
+    makeHoverStyle() {
+        return {
+            background: 'var(--color-bg-1)',
+            cursor: 'pointer',
+        };
+    }
+
+    changeStyle(index: number, hover: boolean) {
+        hover
+            ? (this.styles[index] = this.makeHoverStyle())
+            : (this.styles[index] = this.makeStandardStyle());
+    }
 }
diff --git a/ui/src/app/editor/dialog/customize/customize.component.html b/ui/src/app/editor/dialog/customize/customize.component.html
index 9e5e04f3c..63b16d91c 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.html
+++ b/ui/src/app/editor/dialog/customize/customize.component.html
@@ -19,69 +19,124 @@
 <div class="sp-dialog-container">
     <div class="sp-dialog-content">
         <div fxFlex="100" fxLayout="column">
-            <div style="border-bottom:1px solid #ccc;padding:10px;" fxLayout="row" class="sp-tab-bg">
-                <div fxFlex fxLayoutAlign="start center" *ngIf="availableTemplates && availableTemplates.length > 0">
-                    <mat-form-field class="form-field" floatLabel="never" color="accent">
+            <div
+                style="border-bottom: 1px solid #ccc; padding: 10px"
+                fxLayout="row"
+                class="sp-tab-bg"
+            >
+                <div
+                    fxFlex
+                    fxLayoutAlign="start center"
+                    *ngIf="availableTemplates && availableTemplates.length > 0"
+                >
+                    <mat-form-field
+                        class="form-field"
+                        floatLabel="never"
+                        color="accent"
+                    >
                         <mat-label>Use template</mat-label>
-                        <mat-select (selectionChange)="loadTemplate($event)"
-                                    [(value)]="selectedTemplate">
+                        <mat-select
+                            (selectionChange)="loadTemplate($event)"
+                            [(value)]="selectedTemplate"
+                        >
                             <mat-option>--</mat-option>
-                            <mat-option [value]="template" *ngFor="let template of availableTemplates">
-                                {{template.templateName}}
+                            <mat-option
+                                [value]="template"
+                                *ngFor="let template of availableTemplates"
+                            >
+                                {{ template.templateName }}
                             </mat-option>
                         </mat-select>
                     </mat-form-field>
                 </div>
                 <div fxFlex fxLayout="row" fxLayoutAlign="end center">
-                    <mat-slide-toggle [(ngModel)]="showDocumentation"
-                                      color="accent"
-                                      [disabled]="!pipelineElement.payload.includesAssets">
+                    <mat-slide-toggle
+                        [(ngModel)]="showDocumentation"
+                        color="accent"
+                        [disabled]="!pipelineElement.payload.includesAssets"
+                    >
                         Show documentation
                     </mat-slide-toggle>
                     <span>&nbsp;</span>
-                    <mat-slide-toggle [(ngModel)]="displayRecommended" color="accent">
+                    <mat-slide-toggle
+                        [(ngModel)]="displayRecommended"
+                        color="accent"
+                    >
                         Show only recommended settings
                     </mat-slide-toggle>
                 </div>
             </div>
             <div fxFlex="100" fxLayout="row">
-                <div fxFlex="{{_showDocumentation ? 50: 100}}">
+                <div fxFlex="{{ _showDocumentation ? 50 : 100 }}">
                     <div fxLayout="column" *ngIf="!templateMode">
-                        <div fxFlex="100" fxLayout="column" class="customize-section p-15">
+                        <div
+                            fxFlex="100"
+                            fxLayout="column"
+                            class="customize-section p-15"
+                        >
                             <form [formGroup]="parentForm" fxFlex="100">
-                                <app-static-property *ngFor="let config of cachedPipelineElement.staticProperties"
-                                                     [staticProperty]="config"
-                                                     [pipelineElement]="cachedPipelineElement"
-                                                     [displayRecommended]="displayRecommended"
-                                                     [staticProperties]="cachedPipelineElement.staticProperties"
-                                                     [eventSchemas]="eventSchemas"
-                                                     [parentForm]="parentForm"
-                                                     [fieldName]="config.internalName"
-                                                     [completedStaticProperty]="completedStaticProperty"
-                                                     (updateEmitter)="triggerUpdate($event)"
-                                                     (validateEmitter)="validConfiguration($event)">
+                                <app-static-property
+                                    *ngFor="
+                                        let config of cachedPipelineElement.staticProperties
+                                    "
+                                    [staticProperty]="config"
+                                    [pipelineElement]="cachedPipelineElement"
+                                    [displayRecommended]="displayRecommended"
+                                    [staticProperties]="
+                                        cachedPipelineElement.staticProperties
+                                    "
+                                    [eventSchemas]="eventSchemas"
+                                    [parentForm]="parentForm"
+                                    [fieldName]="config.internalName"
+                                    [completedStaticProperty]="
+                                        completedStaticProperty
+                                    "
+                                    (updateEmitter)="triggerUpdate($event)"
+                                    (validateEmitter)="
+                                        validConfiguration($event)
+                                    "
+                                >
                                 </app-static-property>
                                 <div *ngIf="isDataProcessor">
-                                    <output-strategy
-                                            *ngFor="let outputStrategy of cachedPipelineElement.outputStrategies"
-                                            [parentForm]="parentForm"
-                                            [outputStrategy]="outputStrategy"
-                                            [selectedElement]="cachedPipelineElement">
-                                    </output-strategy>
+                                    <sp-output-strategy
+                                        *ngFor="
+                                            let outputStrategy of cachedPipelineElement.outputStrategies
+                                        "
+                                        [parentForm]="parentForm"
+                                        [outputStrategy]="outputStrategy"
+                                        [selectedElement]="
+                                            cachedPipelineElement
+                                        "
+                                    >
+                                    </sp-output-strategy>
                                 </div>
                             </form>
                         </div>
                     </div>
                     <div fxLayout="column" *ngIf="templateMode">
-                        <pipeline-element-template-config [staticProperties]="cachedPipelineElement.staticProperties"
-                        [template]="template" [templateConfigs]="templateConfigs" [appId]="cachedPipelineElement.appId">
+                        <pipeline-element-template-config
+                            [staticProperties]="
+                                cachedPipelineElement.staticProperties
+                            "
+                            [template]="template"
+                            [templateConfigs]="templateConfigs"
+                            [appId]="cachedPipelineElement.appId"
+                        >
                         </pipeline-element-template-config>
                     </div>
                 </div>
-                <div fxFlex="50" *ngIf="showDocumentation"
-                     style="padding-left:10px;border-left: 2px solid rgb(204, 204, 204);">
-                    <pipeline-element-documentation [useStyling]="false"
-                                                    [appId]="pipelineElement.payload.appId"></pipeline-element-documentation>
+                <div
+                    fxFlex="50"
+                    *ngIf="showDocumentation"
+                    style="
+                        padding-left: 10px;
+                        border-left: 2px solid rgb(204, 204, 204);
+                    "
+                >
+                    <sp-pipeline-element-documentation
+                        [useStyling]="false"
+                        [appId]="pipelineElement.payload.appId"
+                    ></sp-pipeline-element-documentation>
                 </div>
             </div>
         </div>
@@ -89,26 +144,55 @@
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions">
         <div fxLayout="row" *ngIf="!templateMode">
-            <button mat-button mat-raised-button color="accent" (click)="save()" style="margin-right:10px;"
-                    [disabled]="!(formValid)"
-            data-cy="sp-element-configuration-save">
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                (click)="save()"
+                style="margin-right: 10px"
+                [disabled]="!formValid"
+                data-cy="sp-element-configuration-save"
+            >
                 <i class="material-icons">save</i><span>&nbsp;Save</span>
             </button>
-            <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+            <button
+                mat-button
+                mat-raised-button
+                class="mat-basic"
+                (click)="close()"
+            >
                 Cancel
             </button>
             <div fxFlex></div>
-            <button mat-button mat-raised-button color="accent" [disabled]="!(formValid)"
-                    (click)="triggerTemplateMode()">
-                <i class="material-icons">add_circle_outline</i><span>&nbsp;Create template</span>
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                [disabled]="!formValid"
+                (click)="triggerTemplateMode()"
+            >
+                <i class="material-icons">add_circle_outline</i
+                ><span>&nbsp;Create template</span>
             </button>
         </div>
         <div fxLayout="row" *ngIf="templateMode">
-            <button mat-button mat-raised-button color="accent" (click)="saveTemplate()" style="margin-right:10px;"
-                    [disabled]="!(formValid)">
-                <i class="material-icons">save</i><span>&nbsp;Save template</span>
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                (click)="saveTemplate()"
+                style="margin-right: 10px"
+                [disabled]="!formValid"
+            >
+                <i class="material-icons">save</i
+                ><span>&nbsp;Save template</span>
             </button>
-            <button mat-button mat-raised-button class="mat-basic" (click)="cancelTemplateMode()">
+            <button
+                mat-button
+                mat-raised-button
+                class="mat-basic"
+                (click)="cancelTemplateMode()"
+            >
                 Cancel
             </button>
         </div>
diff --git a/ui/src/app/editor/dialog/customize/customize.component.scss b/ui/src/app/editor/dialog/customize/customize.component.scss
index d613b95a3..6802b6687 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.scss
+++ b/ui/src/app/editor/dialog/customize/customize.component.scss
@@ -19,12 +19,9 @@
 @import '../../../../scss/sp/sp-dialog.scss';
 
 .form-field .mat-form-field-wrapper {
-  margin-bottom: -1.25em;
+    margin-bottom: -1.25em;
 }
 
-
 .form-field .mat-form-field-infix {
-  border-top: 0;
+    border-top: 0;
 }
-
-
diff --git a/ui/src/app/editor/dialog/customize/customize.component.ts b/ui/src/app/editor/dialog/customize/customize.component.ts
index 88e3795cb..5ba51d280 100644
--- a/ui/src/app/editor/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor/dialog/customize/customize.component.ts
@@ -16,20 +16,28 @@
  *
  */
 
-import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
 import {
-  InvocablePipelineElementUnion,
-  PipelineElementConfig,
-  PipelineElementConfigurationStatus
+    AfterViewInit,
+    ChangeDetectorRef,
+    Component,
+    Input,
+    OnInit,
+    ViewEncapsulation,
+} from '@angular/core';
+import {
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+    PipelineElementConfigurationStatus,
 } from '../../model/editor.model';
 import { DialogRef } from '@streampipes/shared-ui';
 import { JsplumbService } from '../../services/jsplumb.service';
 import {
-  DataProcessorInvocation, DataSinkInvocation,
-  EventSchema,
-  PipelineElementTemplate,
-  PipelineElementTemplateConfig,
-  PipelineElementTemplateService
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    EventSchema,
+    PipelineElementTemplate,
+    PipelineElementTemplateConfig,
+    PipelineElementTemplateService,
 } from '@streampipes/platform-services';
 import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
@@ -37,174 +45,195 @@ import { ConfigurationInfo } from '../../../connect/model/ConfigurationInfo';
 import { PipelineStyleService } from '../../services/pipeline-style.service';
 
 @Component({
-  selector: 'customize-pipeline-element',
-  templateUrl: './customize.component.html',
-  styleUrls: ['./customize.component.scss'],
-  encapsulation: ViewEncapsulation.None
+    selector: 'sp-customize-pipeline-element',
+    templateUrl: './customize.component.html',
+    styleUrls: ['./customize.component.scss'],
+    encapsulation: ViewEncapsulation.None,
 })
 export class CustomizeComponent implements OnInit, AfterViewInit {
+    @Input()
+    pipelineElement: PipelineElementConfig;
+
+    cachedPipelineElement: InvocablePipelineElementUnion;
+    eventSchemas: EventSchema[] = [];
+
+    displayRecommended = true;
+    _showDocumentation = false;
+
+    selection: any;
+    matchingSelectionLeft: any;
+    matchingSelectionRight: any;
+    invalid: any;
+    helpDialogVisible: any;
+    validationErrors: any;
+
+    sourceEndpoint: any;
+    sepa: any;
+
+    parentForm: UntypedFormGroup;
+    formValid: boolean;
+    viewInitialized = false;
+
+    isDataProcessor = false;
+    originalDialogWidth: string | number;
+    completedStaticProperty: ConfigurationInfo;
+
+    availableTemplates: PipelineElementTemplate[];
+    selectedTemplate: any = false;
+    templateMode = false;
+    template: PipelineElementTemplate;
+    templateConfigs: Map<string, any> = new Map();
+
+    constructor(
+        private dialogRef: DialogRef<CustomizeComponent>,
+        private jsPlumbService: JsplumbService,
+        private shepherdService: ShepherdService,
+        private fb: UntypedFormBuilder,
+        private changeDetectorRef: ChangeDetectorRef,
+        private pipelineElementTemplateService: PipelineElementTemplateService,
+        private pipelineStyleService: PipelineStyleService,
+    ) {}
+
+    ngOnInit(): void {
+        this.originalDialogWidth = this.dialogRef.currentConfig().width;
+        this.cachedPipelineElement = this.jsPlumbService.clone(
+            this.pipelineElement.payload,
+        ) as InvocablePipelineElementUnion;
+        this.isDataProcessor =
+            this.cachedPipelineElement instanceof DataProcessorInvocation;
+        this.cachedPipelineElement.inputStreams.forEach(is => {
+            this.eventSchemas = this.eventSchemas.concat(is.eventSchema);
+        });
+        this.formValid =
+            this.pipelineElement.settings.completed ===
+            PipelineElementConfigurationStatus.OK;
 
-  @Input()
-  pipelineElement: PipelineElementConfig;
-
-  cachedPipelineElement: InvocablePipelineElementUnion;
-  eventSchemas: EventSchema[] = [];
-
-  displayRecommended = true;
-  _showDocumentation = false;
-
-  selection: any;
-  matchingSelectionLeft: any;
-  matchingSelectionRight: any;
-  invalid: any;
-  helpDialogVisible: any;
-  validationErrors: any;
-
-  sourceEndpoint: any;
-  sepa: any;
-
-  parentForm: UntypedFormGroup;
-  formValid: boolean;
-  viewInitialized = false;
-
-  isDataProcessor = false;
-  originalDialogWidth: string | number;
-  completedStaticProperty: ConfigurationInfo;
-
-  availableTemplates: PipelineElementTemplate[];
-  selectedTemplate: any = false;
-  templateMode = false;
-  template: PipelineElementTemplate;
-  templateConfigs: Map<string, any> = new Map();
-
-  constructor(private dialogRef: DialogRef<CustomizeComponent>,
-              private jsPlumbService: JsplumbService,
-              private shepherdService: ShepherdService,
-              private fb: UntypedFormBuilder,
-              private changeDetectorRef: ChangeDetectorRef,
-              private pipelineElementTemplateService: PipelineElementTemplateService,
-              private pipelineStyleService: PipelineStyleService) {
-
-  }
-
-  ngOnInit(): void {
-    this.originalDialogWidth = this.dialogRef.currentConfig().width;
-    this.cachedPipelineElement = this.jsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
-    this.isDataProcessor = this.cachedPipelineElement instanceof DataProcessorInvocation;
-    this.cachedPipelineElement.inputStreams.forEach(is => {
-      this.eventSchemas = this.eventSchemas.concat(is.eventSchema);
-    });
-    this.formValid = this.pipelineElement.settings.completed === PipelineElementConfigurationStatus.OK;
-
-    this.parentForm = this.fb.group({});
-
-    this.parentForm.valueChanges.subscribe(v => {
-    });
-
-    this.parentForm.statusChanges.subscribe((status) => {
-      this.formValid = this.viewInitialized && this.parentForm.valid;
-    });
-    if (this.shepherdService.isTourActive()) {
-      this.shepherdService.trigger('customize-' + this.pipelineElement.type);
-    }
-    this.loadPipelineElementTemplates();
-  }
-
-  loadPipelineElementTemplates() {
-    this.pipelineElementTemplateService
-        .getPipelineElementTemplates(this.cachedPipelineElement.appId)
-        .subscribe(templates => {
-          this.availableTemplates = templates;
+        this.parentForm = this.fb.group({});
+
+        this.parentForm.valueChanges.subscribe(v => {});
+
+        this.parentForm.statusChanges.subscribe(status => {
+            this.formValid = this.viewInitialized && this.parentForm.valid;
         });
-  }
-
-  close() {
-    this.dialogRef.close();
-  }
-
-  save() {
-    this.pipelineElement.payload = this.cachedPipelineElement;
-    this.pipelineStyleService.updatePeConfigurationStatus(this.pipelineElement, PipelineElementConfigurationStatus.OK);
-    this.pipelineElement.payload.configured = true;
-    if (this.shepherdService.isTourActive()) {
-      this.shepherdService.trigger('save-' + this.pipelineElement.type);
+        if (this.shepherdService.isTourActive()) {
+            this.shepherdService.trigger(
+                'customize-' + this.pipelineElement.type,
+            );
+        }
+        this.loadPipelineElementTemplates();
     }
-    this.dialogRef.close(this.pipelineElement);
-  }
 
-  validConfiguration(event: any) {
+    loadPipelineElementTemplates() {
+        this.pipelineElementTemplateService
+            .getPipelineElementTemplates(this.cachedPipelineElement.appId)
+            .subscribe(templates => {
+                this.availableTemplates = templates;
+            });
+    }
 
-  }
+    close() {
+        this.dialogRef.close();
+    }
 
-  set showDocumentation(value: boolean) {
-    if (value) {
-      this.dialogRef.changeDialogSize({width: '90vw'});
-    } else {
-      this.dialogRef.changeDialogSize({width: this.originalDialogWidth});
+    save() {
+        this.pipelineElement.payload = this.cachedPipelineElement;
+        this.pipelineStyleService.updatePeConfigurationStatus(
+            this.pipelineElement,
+            PipelineElementConfigurationStatus.OK,
+        );
+        this.pipelineElement.payload.configured = true;
+        if (this.shepherdService.isTourActive()) {
+            this.shepherdService.trigger('save-' + this.pipelineElement.type);
+        }
+        this.dialogRef.close(this.pipelineElement);
     }
-    this._showDocumentation = value;
-  }
-
-  get showDocumentation(): boolean {
-    return this._showDocumentation;
-  }
-
-  ngAfterViewInit(): void {
-    this.viewInitialized = true;
-    this.formValid = this.viewInitialized && this.parentForm.valid;
-    this.changeDetectorRef.detectChanges();
-  }
-
-  triggerUpdate(configurationInfo: ConfigurationInfo) {
-    this.completedStaticProperty = {...configurationInfo};
-  }
-
-  triggerTemplateMode() {
-    this.template = new PipelineElementTemplate();
-    this.templateMode = true;
-  }
-
-  saveTemplate() {
-    this.template.templateConfigs = this.convert(this.templateConfigs);
-    this.pipelineElementTemplateService.storePipelineElementTemplate(this.template).subscribe(result => {
-      this.loadPipelineElementTemplates();
-      this.templateMode = false;
-    });
-  }
-
-  convert(templateConfigs: Map<string, any>): any {
-    const configs: { [index: string]: PipelineElementTemplateConfig } = {};
-    templateConfigs.forEach((value, key) => {
-      configs[key] = new PipelineElementTemplateConfig();
-      configs[key].editable = value.editable;
-      configs[key].displayed = value.displayed;
-      configs[key].value = value.value;
-    });
-    return configs;
-  }
-
-  cancelTemplateMode() {
-    this.templateMode = false;
-  }
-
-  loadTemplate(event: any) {
-    if (!event.value) {
-      this.cachedPipelineElement = this.jsPlumbService.clone(this.pipelineElement.payload) as InvocablePipelineElementUnion;
-      this.selectedTemplate = false;
-    } else {
-      this.selectedTemplate = event.value;
-      if (this.cachedPipelineElement instanceof DataProcessorInvocation) {
-        this.pipelineElementTemplateService.getConfiguredDataProcessorForTemplate(event.value._id, this.cachedPipelineElement)
-            .subscribe(pe => {
-          this.cachedPipelineElement = pe as InvocablePipelineElementUnion;
-        });
-      } else {
-        this.pipelineElementTemplateService.getConfiguredDataSinkForTemplate(event.value._id,
-            this.cachedPipelineElement as DataSinkInvocation)
-            .subscribe(pe => {
-          this.cachedPipelineElement = pe as InvocablePipelineElementUnion;
+
+    validConfiguration(event: any) {}
+
+    set showDocumentation(value: boolean) {
+        if (value) {
+            this.dialogRef.changeDialogSize({ width: '90vw' });
+        } else {
+            this.dialogRef.changeDialogSize({
+                width: this.originalDialogWidth,
+            });
+        }
+        this._showDocumentation = value;
+    }
+
+    get showDocumentation(): boolean {
+        return this._showDocumentation;
+    }
+
+    ngAfterViewInit(): void {
+        this.viewInitialized = true;
+        this.formValid = this.viewInitialized && this.parentForm.valid;
+        this.changeDetectorRef.detectChanges();
+    }
+
+    triggerUpdate(configurationInfo: ConfigurationInfo) {
+        this.completedStaticProperty = { ...configurationInfo };
+    }
+
+    triggerTemplateMode() {
+        this.template = new PipelineElementTemplate();
+        this.templateMode = true;
+    }
+
+    saveTemplate() {
+        this.template.templateConfigs = this.convert(this.templateConfigs);
+        this.pipelineElementTemplateService
+            .storePipelineElementTemplate(this.template)
+            .subscribe(result => {
+                this.loadPipelineElementTemplates();
+                this.templateMode = false;
+            });
+    }
+
+    convert(templateConfigs: Map<string, any>): any {
+        const configs: { [index: string]: PipelineElementTemplateConfig } = {};
+        templateConfigs.forEach((value, key) => {
+            configs[key] = new PipelineElementTemplateConfig();
+            configs[key].editable = value.editable;
+            configs[key].displayed = value.displayed;
+            configs[key].value = value.value;
         });
-      }
+        return configs;
+    }
+
+    cancelTemplateMode() {
+        this.templateMode = false;
+    }
+
+    loadTemplate(event: any) {
+        if (!event.value) {
+            this.cachedPipelineElement = this.jsPlumbService.clone(
+                this.pipelineElement.payload,
+            ) as InvocablePipelineElementUnion;
+            this.selectedTemplate = false;
+        } else {
+            this.selectedTemplate = event.value;
+            if (this.cachedPipelineElement instanceof DataProcessorInvocation) {
+                this.pipelineElementTemplateService
+                    .getConfiguredDataProcessorForTemplate(
+                        event.value._id,
+                        this.cachedPipelineElement,
+                    )
+                    .subscribe(pe => {
+                        this.cachedPipelineElement =
+                            pe as InvocablePipelineElementUnion;
+                    });
+            } else {
+                this.pipelineElementTemplateService
+                    .getConfiguredDataSinkForTemplate(
+                        event.value._id,
+                        this.cachedPipelineElement as DataSinkInvocation,
+                    )
+                    .subscribe(pe => {
+                        this.cachedPipelineElement =
+                            pe as InvocablePipelineElementUnion;
+                    });
+            }
+        }
     }
-  }
 }
diff --git a/ui/src/app/editor/dialog/help/help.component.html b/ui/src/app/editor/dialog/help/help.component.html
index a39ace505..b17cd1f4b 100644
--- a/ui/src/app/editor/dialog/help/help.component.html
+++ b/ui/src/app/editor/dialog/help/help.component.html
@@ -18,56 +18,92 @@
 
 <div class="sp-dialog-container">
     <div class="sp-dialog-content p-15">
-        <h4>{{pipelineElement.name}}</h4>
+        <h4>{{ pipelineElement.name }}</h4>
         <p>
-            {{pipelineElement.description}}
+            {{ pipelineElement.description }}
         </p>
 
-        <mat-tab-group color="accent"
-                       [selectedIndex]="selectedIndex"
-                       (selectedIndexChange)="selectedIndex=$event">
-            <mat-tab *ngFor="let tab of tabs"
-                     label="{{tab.title}}">
+        <mat-tab-group
+            color="accent"
+            [selectedIndex]="selectedIndex"
+            (selectedIndexChange)="selectedIndex = $event"
+        >
+            <mat-tab *ngFor="let tab of tabs" label="{{ tab.title }}">
             </mat-tab>
         </mat-tab-group>
-        <div style="margin-top:15px;">
-            <div *ngIf="selectedIndex == 0 && streamMode">
+        <div style="margin-top: 15px">
+            <div *ngIf="selectedIndex === 0 && streamMode">
                 <h5>Field Names</h5>
 
                 <div>
                     <table class="dataTable row-border hover preview-table">
                         <thead>
-                        <tr class="preview-row">
-                            <th>Field Name</th>
-                            <th>Description</th>
-                            <th>Runtime Name</th>
-                            <th>Type</th>
-                        </tr>
+                            <tr class="preview-row">
+                                <th>Field Name</th>
+                                <th>Description</th>
+                                <th>Runtime Name</th>
+                                <th>Type</th>
+                            </tr>
                         </thead>
                         <tbody id="preview-data-rows-id">
-                        <tr *ngFor="let property of pipelineElement.eventSchema.eventProperties" class="preview-row">
-                            <td>{{property.label ? property.label : "(n/a)"}}</td>
-                            <td>{{property.description ? property.description : "(n/a)"}}</td>
-                            <td>{{property.runtimeName}}</td>
-                            <td>{{getFriendlyRuntimeType(property.runtimeType)}}</td>
-                        </tr>
+                            <tr
+                                *ngFor="
+                                    let property of pipelineElement.eventSchema
+                                        .eventProperties
+                                "
+                                class="preview-row"
+                            >
+                                <td>
+                                    {{
+                                        property.label
+                                            ? property.label
+                                            : '(n/a)'
+                                    }}
+                                </td>
+                                <td>
+                                    {{
+                                        property.description
+                                            ? property.description
+                                            : '(n/a)'
+                                    }}
+                                </td>
+                                <td>{{ property.runtimeName }}</td>
+                                <td>
+                                    {{
+                                        getFriendlyRuntimeType(
+                                            property.runtimeType
+                                        )
+                                    }}
+                                </td>
+                            </tr>
                         </tbody>
                     </table>
                 </div>
             </div>
-            <div *ngIf="selectedIndex == 1 && streamMode">
+            <div *ngIf="selectedIndex === 1 && streamMode">
                 <div>
-                    <sp-pipeline-element-runtime-info [streamDescription]="pipelineElement" [pollingActive]="pollingActive"></sp-pipeline-element-runtime-info>
+                    <sp-pipeline-element-runtime-info
+                        [streamDescription]="pipelineElement"
+                        [pollingActive]="pollingActive"
+                    ></sp-pipeline-element-runtime-info>
                 </div>
             </div>
-            <div *ngIf="selectedTab == 2 || !(streamMode)">
-                <pipeline-element-documentation [useStyling]="false" [appId]="pipelineElement.appId"></pipeline-element-documentation>
+            <div *ngIf="selectedTab === 2 || !streamMode">
+                <sp-pipeline-element-documentation
+                    [useStyling]="false"
+                    [appId]="pipelineElement.appId"
+                ></sp-pipeline-element-documentation>
             </div>
         </div>
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions actions-align-right">
-        <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic"
+            (click)="close()"
+        >
             Close
         </button>
     </div>
diff --git a/ui/src/app/editor/dialog/help/help.component.scss b/ui/src/app/editor/dialog/help/help.component.scss
index 497653847..3e7522f22 100644
--- a/ui/src/app/editor/dialog/help/help.component.scss
+++ b/ui/src/app/editor/dialog/help/help.component.scss
@@ -18,11 +18,11 @@
 
 @import '../../../../scss/sp/sp-dialog.scss';
 
-.preview-row, .preview-table {
-  background: var(--color-bg-dialog);
+.preview-row,
+.preview-table {
+    background: var(--color-bg-dialog);
 }
 
 .dataTable tbody tr:hover {
-  background: var(--color-bg-1);
+    background: var(--color-bg-1);
 }
-
diff --git a/ui/src/app/editor/dialog/help/help.component.ts b/ui/src/app/editor/dialog/help/help.component.ts
index 41196b4ee..c713ad436 100644
--- a/ui/src/app/editor/dialog/help/help.component.ts
+++ b/ui/src/app/editor/dialog/help/help.component.ts
@@ -18,96 +18,99 @@
 
 import { Component, Input, OnInit } from '@angular/core';
 import { PipelineElementUnion } from '../../model/editor.model';
-import { PipelineElementService, SpDataStream } from '@streampipes/platform-services';
+import {
+    PipelineElementService,
+    SpDataStream,
+} from '@streampipes/platform-services';
 import { DialogRef } from '@streampipes/shared-ui';
 import { PipelineElementTypeUtils } from '../../utils/editor.utils';
 
 @Component({
-  selector: 'pipeline-element-help',
-  templateUrl: './help.component.html',
-  styleUrls: ['./help.component.scss']
+    selector: 'sp-pipeline-element-help',
+    templateUrl: './help.component.html',
+    styleUrls: ['./help.component.scss'],
 })
 export class HelpComponent implements OnInit {
-
-  selectedTab = 0;
-  pollingActive: boolean;
-
-  selectedIndex = 0;
-
-  nsPrefix = 'http://www.w3.org/2001/XMLSchema#';
-  availableTabs = [
-    {
-      title: 'Fields',
-      type: 'fields',
-      targets: ['set', 'stream']
-    },
-    {
-      title: 'Values',
-      type: 'values',
-      targets: ['set', 'stream']
-    },
-    {
-      title: 'Documentation',
-      type: 'documentation',
-      targets: ['set', 'stream', 'sepa', 'action']
+    selectedTab = 0;
+    pollingActive: boolean;
+
+    selectedIndex = 0;
+
+    nsPrefix = 'http://www.w3.org/2001/XMLSchema#';
+    availableTabs = [
+        {
+            title: 'Fields',
+            type: 'fields',
+            targets: ['set', 'stream'],
+        },
+        {
+            title: 'Values',
+            type: 'values',
+            targets: ['set', 'stream'],
+        },
+        {
+            title: 'Documentation',
+            type: 'documentation',
+            targets: ['set', 'stream', 'sepa', 'action'],
+        },
+    ];
+
+    tabs: any[] = [];
+    streamMode: boolean;
+
+    @Input()
+    pipelineElement: PipelineElementUnion;
+
+    constructor(
+        private pipelineElementService: PipelineElementService,
+        private dialogRef: DialogRef<HelpComponent>,
+    ) {
+        this.pollingActive = true;
     }
-  ];
-
-  tabs: any[] = [];
-  streamMode: boolean;
 
-  @Input()
-  pipelineElement: PipelineElementUnion;
-
-  constructor(private pipelineElementService: PipelineElementService,
-              private dialogRef: DialogRef<HelpComponent>) {
-    this.pollingActive = true;
-  }
-
-  ngOnInit() {
-    if (this.pipelineElement instanceof SpDataStream) {
-      this.tabs = this.availableTabs;
-      this.streamMode = true;
-    } else {
-      this.tabs.push(this.availableTabs[2]);
-      this.streamMode = false;
+    ngOnInit() {
+        if (this.pipelineElement instanceof SpDataStream) {
+            this.tabs = this.availableTabs;
+            this.streamMode = true;
+        } else {
+            this.tabs.push(this.availableTabs[2]);
+            this.streamMode = false;
+        }
     }
-  }
 
-  getFriendlyRuntimeType(runtimeType) {
-    if (this.isNumber(runtimeType)) {
-      return 'Number';
-    } else if (this.isBoolean(runtimeType)) {
-      return 'Boolean';
-    } else {
-      return 'Text';
+    getFriendlyRuntimeType(runtimeType) {
+        if (this.isNumber(runtimeType)) {
+            return 'Number';
+        } else if (this.isBoolean(runtimeType)) {
+            return 'Boolean';
+        } else {
+            return 'Text';
+        }
     }
-  }
-
-  isNumber(runtimeType) {
-    return (runtimeType === (this.nsPrefix + 'float')) ||
-        (runtimeType === (this.nsPrefix + 'integer')) ||
-        (runtimeType === (this.nsPrefix + 'long')) ||
-        (runtimeType === (this.nsPrefix + 'double'));
-  }
-
-  isBoolean(runtimeType) {
-    return runtimeType === this.nsPrefix + 'boolean';
-  }
-
-  close() {
-    this.pollingActive = false;
-    setTimeout(() => {
-      this.dialogRef.close();
-    });
-  }
 
+    isNumber(runtimeType) {
+        return (
+            runtimeType === this.nsPrefix + 'float' ||
+            runtimeType === this.nsPrefix + 'integer' ||
+            runtimeType === this.nsPrefix + 'long' ||
+            runtimeType === this.nsPrefix + 'double'
+        );
+    }
 
-  filterTab(tab) {
-    const type = PipelineElementTypeUtils.fromType(this.pipelineElement);
-    const cssShortHand = PipelineElementTypeUtils.toCssShortHand(type);
-    return tab.targets.indexOf(cssShortHand) !== -1;
-  }
+    isBoolean(runtimeType) {
+        return runtimeType === this.nsPrefix + 'boolean';
+    }
 
+    close() {
+        this.pollingActive = false;
+        setTimeout(() => {
+            this.dialogRef.close();
+        });
+    }
 
+    filterTab(tab) {
+        const type = PipelineElementTypeUtils.fromType(this.pipelineElement);
+        const cssShortHand = PipelineElementTypeUtils.toCssShortHand(type);
+        return tab.targets.indexOf(cssShortHand) !== -1;
+    }
 }
diff --git a/ui/src/app/editor/dialog/matching-error/matching-error.component.html b/ui/src/app/editor/dialog/matching-error/matching-error.component.html
index e0a7fa8b0..c68c6ed8e 100644
--- a/ui/src/app/editor/dialog/matching-error/matching-error.component.html
+++ b/ui/src/app/editor/dialog/matching-error/matching-error.component.html
@@ -20,23 +20,35 @@
     <div class="sp-dialog-content p-15">
         <div>
             <h4>These elements can't be connected.</h4>
-            <h4>The input data stream does not satisfy the requirements specified by the data processor.</h4>
-            <button mat-button (click)="toggleStatusDetailsVisible()" type="button" class="md-accent">
+            <h4>
+                The input data stream does not satisfy the requirements
+                specified by the data processor.
+            </h4>
+            <button
+                mat-button
+                (click)="toggleStatusDetailsVisible()"
+                type="button"
+                class="md-accent"
+            >
                 <div *ngIf="!statusDetailsVisible">Show Details</div>
                 <div *ngIf="statusDetailsVisible">Hide Details</div>
             </button>
             <div *ngIf="statusDetailsVisible">
                 <div *ngFor="let entry of notifications">
-                    <div fxFlex="100" class="md-whiteframe-z1" style="margin-bottom:10px;">
+                    <div
+                        fxFlex="100"
+                        class="md-whiteframe-z1"
+                        style="margin-bottom: 10px"
+                    >
                         <div fxFlex fxLayout="column" class="md-padding">
-<!--                            <div>-->
-<!--                                <i class="material-icons" *ngIf="entry.matchingResultMessage">done</i>-->
-<!--                                <i class="material-icons" *ngIf="entry.matchingSuccessful">warning</i>-->
-<!--                                <b>{{entry.title}} </b>-->
-<!--                            </div>-->
+                            <!--                            <div>-->
+                            <!--                                <i class="material-icons" *ngIf="entry.matchingResultMessage">done</i>-->
+                            <!--                                <i class="material-icons" *ngIf="entry.matchingSuccessful">warning</i>-->
+                            <!--                                <b>{{entry.title}} </b>-->
+                            <!--                            </div>-->
                             <div fxFlex="column">
-                                {{entry.title}}<br/>
-                                {{entry.description}}
+                                {{ entry.title }}<br />
+                                {{ entry.description }}
                             </div>
                         </div>
                     </div>
@@ -46,7 +58,12 @@
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions actions-align-right">
-        <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic"
+            (click)="close()"
+        >
             Close
         </button>
     </div>
diff --git a/ui/src/app/editor/dialog/matching-error/matching-error.component.scss b/ui/src/app/editor/dialog/matching-error/matching-error.component.scss
index 0a776e5ff..fddade7bf 100644
--- a/ui/src/app/editor/dialog/matching-error/matching-error.component.scss
+++ b/ui/src/app/editor/dialog/matching-error/matching-error.component.scss
@@ -16,4 +16,4 @@
  *
  */
 
-@import '../../../../scss/sp/sp-dialog.scss';
\ No newline at end of file
+@import '../../../../scss/sp/sp-dialog.scss';
diff --git a/ui/src/app/editor/dialog/matching-error/matching-error.component.ts b/ui/src/app/editor/dialog/matching-error/matching-error.component.ts
index d0ab5f37e..931b6929c 100644
--- a/ui/src/app/editor/dialog/matching-error/matching-error.component.ts
+++ b/ui/src/app/editor/dialog/matching-error/matching-error.component.ts
@@ -21,27 +21,24 @@ import { DialogRef } from '@streampipes/shared-ui';
 import { Notification } from '@streampipes/platform-services';
 
 @Component({
-  selector: 'matching-error',
-  templateUrl: './matching-error.component.html',
-  styleUrls: ['./matching-error.component.scss']
+    selector: 'sp-matching-error',
+    templateUrl: './matching-error.component.html',
+    styleUrls: ['./matching-error.component.scss'],
 })
 export class MatchingErrorComponent {
+    @Input()
+    notifications: Notification[];
 
-  @Input()
-  notifications: Notification[];
+    msg: any;
+    statusDetailsVisible: any;
 
-  msg: any;
-  statusDetailsVisible: any;
+    constructor(private dialogRef: DialogRef<MatchingErrorComponent>) {}
 
-  constructor(private dialogRef: DialogRef<MatchingErrorComponent>) {
+    close() {
+        this.dialogRef.close();
+    }
 
-  }
-
-  close() {
-    this.dialogRef.close();
-  }
-
-  toggleStatusDetailsVisible() {
-    this.statusDetailsVisible = !(this.statusDetailsVisible);
-  }
+    toggleStatusDetailsVisible() {
+        this.statusDetailsVisible = !this.statusDetailsVisible;
+    }
 }
diff --git a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.html b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.html
index c80e76c26..4b78c097f 100644
--- a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.html
+++ b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.html
@@ -20,18 +20,32 @@
     <div class="sp-dialog-content p-15">
         <div fxFlex="100" fxLayout="column">
             <div fxFlex="100" fxLayout="column">
-                <h4>The tutorial requires pipeline elements that are not yet installed.</h4>
-                <h5>Install the following pipeline elements and start the tutorial again:</h5>
+                <h4>
+                    The tutorial requires pipeline elements that are not yet
+                    installed.
+                </h4>
+                <h5>
+                    Install the following pipeline elements and start the
+                    tutorial again:
+                </h5>
                 <div *ngFor="let missingElement of missingElementsForTutorial">
-                    <li><b>{{missingElement.name}}</b> <i>({{missingElement.appId}})</i></li>
+                    <li>
+                        <b>{{ missingElement.name }}</b>
+                        <i>({{ missingElement.appId }})</i>
+                    </li>
                 </div>
             </div>
         </div>
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions actions-align-right">
-        <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic"
+            (click)="close()"
+        >
             Close
         </button>
     </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.scss b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.scss
index 0a776e5ff..fddade7bf 100644
--- a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.scss
+++ b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.scss
@@ -16,4 +16,4 @@
  *
  */
 
-@import '../../../../scss/sp/sp-dialog.scss';
\ No newline at end of file
+@import '../../../../scss/sp/sp-dialog.scss';
diff --git a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.ts b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.ts
index fe05455aa..18ed7dd96 100644
--- a/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.ts
+++ b/ui/src/app/editor/dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component.ts
@@ -20,21 +20,19 @@ import { Component, Input } from '@angular/core';
 import { DialogRef } from '@streampipes/shared-ui';
 
 @Component({
-  selector: 'missing-elements-for-tutorial',
-  templateUrl: './missing-elements-for-tutorial.component.html',
-  styleUrls: ['./missing-elements-for-tutorial.component.scss']
+    selector: 'sp-missing-elements-for-tutorial',
+    templateUrl: './missing-elements-for-tutorial.component.html',
+    styleUrls: ['./missing-elements-for-tutorial.component.scss'],
 })
 export class MissingElementsForTutorialComponent {
+    @Input()
+    missingElementsForTutorial: any[];
 
+    constructor(
+        private dialogRef: DialogRef<MissingElementsForTutorialComponent>,
+    ) {}
 
-  @Input()
-  missingElementsForTutorial: any[];
-
-  constructor(private dialogRef: DialogRef<MissingElementsForTutorialComponent>) {
-
-  }
-
-  close() {
-    this.dialogRef.close();
-  }
+    close() {
+        this.dialogRef.close();
+    }
 }
diff --git a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.html b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.html
index 602c28233..b21358d1f 100644
--- a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.html
+++ b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.html
@@ -19,18 +19,38 @@
 <div class="sp-dialog-container">
     <div class="sp-dialog-content p-15">
         <div fxFlex="100" fxLayout="column">
-            <div *ngFor="let currentElement of currentElements; index as i" (click)="create(currentElement)">
-                <div fxLayout="row" class="m-10" fxLayoutAlign="start center"
-                     [style]="styles[i]"
-                     (mouseenter)="changeStyle(i, true)"
-                     (mouseleave)="changeStyle(i, false)"
-                     [attr.data-cy]="currentElement.name.toLowerCase().replaceAll(' ', '_')">
-                    <div class="draggable-icon-preview {{currentElementStyle(currentElement)}}">
-                        <pipeline-element [pipelineElement]="currentElement" [iconSize]="true"></pipeline-element>
+            <div
+                *ngFor="let currentElement of currentElements; index as i"
+                (click)="create(currentElement)"
+            >
+                <div
+                    fxLayout="row"
+                    class="m-10"
+                    fxLayoutAlign="start center"
+                    [style]="styles[i]"
+                    (mouseenter)="changeStyle(i, true)"
+                    (mouseleave)="changeStyle(i, false)"
+                    [attr.data-cy]="
+                        currentElement.name.toLowerCase().replaceAll(' ', '_')
+                    "
+                >
+                    <div
+                        class="draggable-icon-preview {{
+                            currentElementStyle(currentElement)
+                        }}"
+                    >
+                        <sp-pipeline-element
+                            [pipelineElement]="currentElement"
+                            [iconSize]="true"
+                        ></sp-pipeline-element>
                     </div>
                     <div fxLayout="column" fxLayoutAlign="center start">
-                        <div class="element-name">{{ currentElement.name }}</div>
-                        <div class="element-description">{{ currentElement.description }}</div>
+                        <div class="element-name">
+                            {{ currentElement.name }}
+                        </div>
+                        <div class="element-description">
+                            {{ currentElement.description }}
+                        </div>
                     </div>
                 </div>
                 <mat-divider></mat-divider>
@@ -39,7 +59,6 @@
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions">
-
         <button mat-button mat-raised-button class="mat-basic" (click)="hide()">
             Cancel
         </button>
diff --git a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.scss b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.scss
index 31ebd4267..0945c5cb6 100644
--- a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.scss
+++ b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.scss
@@ -19,6 +19,6 @@
 @import '../../../../scss/sp/sp-dialog.scss';
 
 .m-10 {
-  padding-top:10px;
-  padding-bottom:10px;
+    padding-top: 10px;
+    padding-bottom: 10px;
 }
diff --git a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.ts b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.ts
index 513b08d02..edf8fce9b 100644
--- a/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.ts
+++ b/ui/src/app/editor/dialog/pipeline-element-discovery/pipeline-element-discovery.component.ts
@@ -20,79 +20,85 @@ import { Component, Input, OnInit } from '@angular/core';
 import { DialogRef } from '@streampipes/shared-ui';
 import { JsplumbService } from '../../services/jsplumb.service';
 import {
-  DataProcessorInvocation,
-  DataSinkInvocation,
-  SpDataSet,
-  SpDataStream
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    SpDataSet,
+    SpDataStream,
 } from '@streampipes/platform-services';
-import { PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import {
+    PipelineElementConfig,
+    PipelineElementUnion,
+} from '../../model/editor.model';
 
 @Component({
-  selector: 'sp-pipeline-element-discovery',
-  templateUrl: './pipeline-element-discovery.component.html',
-  styleUrls: ['./pipeline-element-discovery.component.scss']
+    selector: 'sp-pipeline-element-discovery',
+    templateUrl: './pipeline-element-discovery.component.html',
+    styleUrls: ['./pipeline-element-discovery.component.scss'],
 })
 export class PipelineElementDiscoveryComponent implements OnInit {
+    @Input()
+    rawPipelineModel: PipelineElementConfig[];
 
-  @Input()
-  rawPipelineModel: PipelineElementConfig[];
-
-  @Input()
-  currentElements: PipelineElementUnion[];
-
-  styles: any[] = [];
+    @Input()
+    currentElements: PipelineElementUnion[];
 
-  constructor(private dialogRef: DialogRef<PipelineElementDiscoveryComponent>,
-              private JsPlumbService: JsplumbService) {
+    styles: any[] = [];
 
-  }
+    constructor(
+        private dialogRef: DialogRef<PipelineElementDiscoveryComponent>,
+        private JsPlumbService: JsplumbService,
+    ) {}
 
-  ngOnInit() {
-    this.currentElements.sort((a, b) => a.name.localeCompare(b.name));
-    this.currentElements.forEach(pe => {
-      this.styles.push(this.makeStandardStyle());
-    });
-  }
+    ngOnInit() {
+        this.currentElements.sort((a, b) => a.name.localeCompare(b.name));
+        this.currentElements.forEach(pe => {
+            this.styles.push(this.makeStandardStyle());
+        });
+    }
 
-  create(selectedElement) {
-    this.JsPlumbService.createElementWithoutConnection(this.rawPipelineModel,
-        selectedElement,
-        200,
-        100);
-    this.hide();
-  }
+    create(selectedElement) {
+        this.JsPlumbService.createElementWithoutConnection(
+            this.rawPipelineModel,
+            selectedElement,
+            200,
+            100,
+        );
+        this.hide();
+    }
 
-  hide() {
-    this.dialogRef.close();
-  }
+    hide() {
+        this.dialogRef.close();
+    }
 
-  currentElementStyle(possibleElement: PipelineElementUnion) {
-    if (possibleElement instanceof DataProcessorInvocation) {
-      return 'sepa';
-    } else if (possibleElement instanceof DataSinkInvocation) {
-      return 'action';
-    } else if (possibleElement instanceof SpDataSet) {
-      return 'set';
-    } else if (possibleElement instanceof SpDataStream) {
-      return 'stream';
+    currentElementStyle(possibleElement: PipelineElementUnion) {
+        if (possibleElement instanceof DataProcessorInvocation) {
+            return 'sepa';
+        } else if (possibleElement instanceof DataSinkInvocation) {
+            return 'action';
+        } else if (possibleElement instanceof SpDataSet) {
+            return 'set';
+        } else if (possibleElement instanceof SpDataStream) {
+            return 'stream';
+        }
     }
-  }
 
-  makeStandardStyle() {
-    return {
-      background: 'white',
-      cursor: 'auto'
-    };
-  }
+    makeStandardStyle() {
+        return {
+            background: 'white',
+            cursor: 'auto',
+        };
+    }
 
-  makeHoverStyle() {
-    return {
-      background: 'lightgrey',
-      cursor: 'pointer'
-    };
-  }
+    makeHoverStyle() {
+        return {
+            background: 'lightgrey',
+            cursor: 'pointer',
+        };
+    }
 
-  changeStyle(index: number, hover: boolean) {
-    hover ? this.styles[index] = this.makeHoverStyle() : this.styles[index] = this.makeStandardStyle();
-  }
+    changeStyle(index: number, hover: boolean) {
+        hover
+            ? (this.styles[index] = this.makeHoverStyle())
+            : (this.styles[index] = this.makeStandardStyle());
+    }
 }
diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.html b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.html
index 607638976..bfc222978 100644
--- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.html
+++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.html
@@ -19,11 +19,28 @@
 <div class="sp-dialog-container">
     <div class="sp-dialog-content padding-20">
         <div fxFlex="100" fxLayout="column">
-            <div fxFlex="100" fxLayout="column" *ngIf="!saved && !saving && !storageError">
-                <div id="overwriteCheckbox" class="checkbox" *ngIf="currentModifiedPipelineId">
-                    <mat-radio-group [(ngModel)]="updateMode" fxLayout="column" color="accent" class="pipeline-radio-group">
-                        <mat-radio-button [value]="'update'" class="mb-10" style="padding-left: 0;">
-                            Update pipeline <b>{{currentPipelineName}}</b>
+            <div
+                fxFlex="100"
+                fxLayout="column"
+                *ngIf="!saved && !saving && !storageError"
+            >
+                <div
+                    id="overwriteCheckbox"
+                    class="checkbox"
+                    *ngIf="currentModifiedPipelineId"
+                >
+                    <mat-radio-group
+                        [(ngModel)]="updateMode"
+                        fxLayout="column"
+                        color="accent"
+                        class="pipeline-radio-group"
+                    >
+                        <mat-radio-button
+                            [value]="'update'"
+                            class="mb-10"
+                            style="padding-left: 0"
+                        >
+                            Update pipeline <b>{{ currentPipelineName }}</b>
                         </mat-radio-button>
                         <mat-radio-button [value]="'clone'" class="mb-10">
                             Create new pipeline
@@ -31,55 +48,112 @@
                     </mat-radio-group>
                 </div>
                 <form [formGroup]="submitPipelineForm">
-                <div fxFlex="100" fxLayout="column" *ngIf="!currentModifiedPipelineId || updateMode=='clone'">
-                    <mat-form-field fxFlex color="accent">
-                        <mat-label>Pipeline Name</mat-label>
-                        <input [formControlName]="'pipelineName'"
+                    <div
+                        fxFlex="100"
+                        fxLayout="column"
+                        *ngIf="
+                            !currentModifiedPipelineId || updateMode === 'clone'
+                        "
+                    >
+                        <mat-form-field fxFlex color="accent">
+                            <mat-label>Pipeline Name</mat-label>
+                            <input
+                                [formControlName]="'pipelineName'"
                                 data-cy="sp-editor-pipeline-name"
-                                matInput name="pipelineName"/>
-<!--                        <span ng-show="submitPipelineForm.pipelineName.$touched && submitPipelineForm.pipelineName.$error.required">Please provide a pipeline name.</span>-->
-<!--                        <span ng-show="submitPipelineForm.pipelineName.$error.maxlength">Please provide a shorter pipeline name.</span>-->
-                    </mat-form-field>
-                    <mat-form-field fxFlex color="accent">
-                        <mat-label>Description</mat-label>
-                        <input [formControlName]="'pipelineDescription'" matInput/>
-<!--                        <span ng-show="submitPipelineForm.pipelineDescription.$error.maxlength">Please provide a shorter description.</span>-->
-                    </mat-form-field>
-                </div>
+                                matInput
+                                name="pipelineName"
+                            />
+                            <!--                        <span ng-show="submitPipelineForm.pipelineName.$touched && submitPipelineForm.pipelineName.$error.required">Please provide a pipeline name.</span>-->
+                            <!--                        <span ng-show="submitPipelineForm.pipelineName.$error.maxlength">Please provide a shorter pipeline name.</span>-->
+                        </mat-form-field>
+                        <mat-form-field fxFlex color="accent">
+                            <mat-label>Description</mat-label>
+                            <input
+                                [formControlName]="'pipelineDescription'"
+                                matInput
+                            />
+                            <!--                        <span ng-show="submitPipelineForm.pipelineDescription.$error.maxlength">Please provide a shorter description.</span>-->
+                        </mat-form-field>
+                    </div>
                 </form>
-                <mat-checkbox (click)="triggerTutorial()"
-                              [(ngModel)]="startPipelineAfterStorage"
-                              color="accent"
-                              data-cy="sp-editor-checkbox-start-immediately">
+                <mat-checkbox
+                    (click)="triggerTutorial()"
+                    [(ngModel)]="startPipelineAfterStorage"
+                    color="accent"
+                    data-cy="sp-editor-checkbox-start-immediately"
+                >
                     Start pipeline immediately
                 </mat-checkbox>
             </div>
-            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="saving">
-                <mat-spinner [mode]="'indeterminate'" [diameter]="50" color="accent"></mat-spinner>
+            <div
+                fxFlex="100"
+                fxLayout="column"
+                fxLayoutAlign="center center"
+                *ngIf="saving"
+            >
+                <mat-spinner
+                    [mode]="'indeterminate'"
+                    [diameter]="50"
+                    color="accent"
+                ></mat-spinner>
                 <span class="status-text">Saving pipeline...</span>
             </div>
-            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="saved">
-                <mat-icon color="accent" style="font-size:50pt;height:60px;width:60px;">check_circle</mat-icon>
+            <div
+                fxFlex="100"
+                fxLayout="column"
+                fxLayoutAlign="center center"
+                *ngIf="saved"
+            >
+                <mat-icon
+                    color="accent"
+                    style="font-size: 50pt; height: 60px; width: 60px"
+                    >check_circle</mat-icon
+                >
                 <span class="status-text">Pipeline successfully stored.</span>
             </div>
-            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="storageError">
-                <mat-icon color="accent" style="font-size:50pt;height:60px;width:60px;">error</mat-icon>
-                <span class="status-text">Your pipeline could not be stored.</span>
-                <span class="status-subtext">{{errorMessage}}</span>
+            <div
+                fxFlex="100"
+                fxLayout="column"
+                fxLayoutAlign="center center"
+                *ngIf="storageError"
+            >
+                <mat-icon
+                    color="accent"
+                    style="font-size: 50pt; height: 60px; width: 60px"
+                    >error</mat-icon
+                >
+                <span class="status-text"
+                    >Your pipeline could not be stored.</span
+                >
+                <span class="status-subtext">{{ errorMessage }}</span>
             </div>
         </div>
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions">
-        <button [disabled]="!submitPipelineForm.valid || saving || saved" mat-button mat-raised-button color="accent" (click)="savePipeline(false)" style="margin-right:10px;">
+        <button
+            [disabled]="!submitPipelineForm.valid || saving || saved"
+            mat-button
+            mat-raised-button
+            color="accent"
+            (click)="savePipeline(false)"
+            style="margin-right: 10px"
+        >
             Save
         </button>
-        <button [disabled]="!submitPipelineForm.valid || saving || saved" mat-button mat-raised-button color="accent" (click)="savePipeline(true)" style="margin-right:10px;"
-                data-cy="sp-editor-save">
+        <button
+            [disabled]="!submitPipelineForm.valid || saving || saved"
+            mat-button
+            mat-raised-button
+            color="accent"
+            (click)="savePipeline(true)"
+            style="margin-right: 10px"
+            data-cy="sp-editor-save"
+        >
             Save and go to pipeline view
         </button>
         <button mat-button mat-raised-button class="mat-basic" (click)="hide()">
-            {{saved ? 'Close' : 'Cancel'}}
+            {{ saved ? 'Close' : 'Cancel' }}
         </button>
     </div>
 </div>
diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.scss b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.scss
index c5dce8d4d..5b19b8215 100644
--- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.scss
+++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.scss
@@ -19,28 +19,28 @@
 @import '../../../../scss/sp/sp-dialog.scss';
 
 .customize-section {
-  display:flex;
-  flex: 1 1 auto;
-  padding: 20px;
+    display: flex;
+    flex: 1 1 auto;
+    padding: 20px;
 }
 
 .padding-20 {
-  padding: 20px;
+    padding: 20px;
 }
 
 .mb-10 {
-  margin-bottom: 10px;
+    margin-bottom: 10px;
 }
 
 ::ng-deep .pipeline-radio-group .mat-radio-label {
-  padding: 0;
+    padding: 0;
 }
 
 .status-text {
-  font-size: 14pt;
-  margin-top:10px;
+    font-size: 14pt;
+    margin-top: 10px;
 }
 
 .status-subtext {
-  font-size: 12pt;
-}
\ No newline at end of file
+    font-size: 12pt;
+}
diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.ts b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.ts
index 907be7193..f9f12f1bc 100644
--- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.ts
+++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline.component.ts
@@ -18,171 +18,207 @@
 
 import { Component, Input, OnInit } from '@angular/core';
 import { DialogRef } from '@streampipes/shared-ui';
-import { Message, Pipeline, PipelineCanvasMetadata, PipelineService, PipelineCanvasMetadataService } from '@streampipes/platform-services';
+import {
+    Message,
+    Pipeline,
+    PipelineCanvasMetadata,
+    PipelineService,
+    PipelineCanvasMetadataService,
+} from '@streampipes/platform-services';
 import { ObjectProvider } from '../../services/object-provider.service';
 import { EditorService } from '../../services/editor.service';
 import { ShepherdService } from '../../../services/tour/shepherd.service';
-import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
+import {
+    UntypedFormControl,
+    UntypedFormGroup,
+    Validators,
+} from '@angular/forms';
 import { Router } from '@angular/router';
-import { InvocablePipelineElementUnion } from "../../model/editor.model";
-import { JsplumbService } from "../../services/jsplumb.service";
+import { InvocablePipelineElementUnion } from '../../model/editor.model';
+import { JsplumbService } from '../../services/jsplumb.service';
 
 @Component({
-  selector: 'save-pipeline',
-  templateUrl: './save-pipeline.component.html',
-  styleUrls: ['./save-pipeline.component.scss']
+    selector: 'sp-save-pipeline',
+    templateUrl: './save-pipeline.component.html',
+    styleUrls: ['./save-pipeline.component.scss'],
 })
 export class SavePipelineComponent implements OnInit {
+    pipelineCategories: any;
+    startPipelineAfterStorage: any;
+    updateMode: any;
 
-  pipelineCategories: any;
-  startPipelineAfterStorage: any;
-  updateMode: any;
+    submitPipelineForm: UntypedFormGroup = new UntypedFormGroup({});
 
-  submitPipelineForm: UntypedFormGroup = new UntypedFormGroup({});
+    @Input()
+    pipeline: Pipeline;
 
-  @Input()
-  pipeline: Pipeline;
+    @Input()
+    modificationMode: string;
 
-  @Input()
-  modificationMode: string;
+    @Input()
+    currentModifiedPipelineId: string;
 
-  @Input()
-  currentModifiedPipelineId: string;
+    @Input()
+    pipelineCanvasMetadata: PipelineCanvasMetadata;
 
-  @Input()
-  pipelineCanvasMetadata: PipelineCanvasMetadata;
+    saving = false;
+    saved = false;
 
-  saving = false;
-  saved = false;
+    storageError = false;
+    errorMessage = '';
 
-  storageError = false;
-  errorMessage = '';
+    currentPipelineName: string;
 
-  currentPipelineName: string;
-
-  constructor(private editorService: EditorService,
-              private dialogRef: DialogRef<SavePipelineComponent>,
-              private jsplumbService: JsplumbService,
-              private objectProvider: ObjectProvider,
-              private pipelineService: PipelineService,
-              private router: Router,
-              private shepherdService: ShepherdService,
-              private pipelineCanvasService: PipelineCanvasMetadataService) {
-    this.pipelineCategories = [];
-    this.updateMode = 'update';
-  }
-
-  ngOnInit() {
-    this.getPipelineCategories();
-    if (this.currentModifiedPipelineId) {
-      this.currentPipelineName = this.pipeline.name;
+    constructor(
+        private editorService: EditorService,
+        private dialogRef: DialogRef<SavePipelineComponent>,
+        private jsplumbService: JsplumbService,
+        private objectProvider: ObjectProvider,
+        private pipelineService: PipelineService,
+        private router: Router,
+        private shepherdService: ShepherdService,
+        private pipelineCanvasService: PipelineCanvasMetadataService,
+    ) {
+        this.pipelineCategories = [];
+        this.updateMode = 'update';
     }
 
-    this.submitPipelineForm.addControl('pipelineName', new UntypedFormControl(this.pipeline.name,
-        [Validators.required,
-          Validators.maxLength(40)]));
-    this.submitPipelineForm.addControl('pipelineDescription', new UntypedFormControl(this.pipeline.description,
-        [Validators.maxLength(80)]));
-
-    this.submitPipelineForm.controls['pipelineName'].valueChanges.subscribe(value => {
-      this.pipeline.name = value;
-    });
-
-    this.submitPipelineForm.controls['pipelineDescription'].valueChanges.subscribe(value => {
-      this.pipeline.description = value;
-    });
+    ngOnInit() {
+        this.getPipelineCategories();
+        if (this.currentModifiedPipelineId) {
+            this.currentPipelineName = this.pipeline.name;
+        }
+
+        this.submitPipelineForm.addControl(
+            'pipelineName',
+            new UntypedFormControl(this.pipeline.name, [
+                Validators.required,
+                Validators.maxLength(40),
+            ]),
+        );
+        this.submitPipelineForm.addControl(
+            'pipelineDescription',
+            new UntypedFormControl(this.pipeline.description, [
+                Validators.maxLength(80),
+            ]),
+        );
+
+        this.submitPipelineForm.controls['pipelineName'].valueChanges.subscribe(
+            value => {
+                this.pipeline.name = value;
+            },
+        );
+
+        this.submitPipelineForm.controls[
+            'pipelineDescription'
+        ].valueChanges.subscribe(value => {
+            this.pipeline.description = value;
+        });
 
-    if (this.shepherdService.isTourActive()) {
-      this.shepherdService.trigger('enter-pipeline-name');
+        if (this.shepherdService.isTourActive()) {
+            this.shepherdService.trigger('enter-pipeline-name');
+        }
     }
 
-  }
-
-  triggerTutorial() {
-    if (this.shepherdService.isTourActive()) {
-      this.shepherdService.trigger('save-pipeline-dialog');
+    triggerTutorial() {
+        if (this.shepherdService.isTourActive()) {
+            this.shepherdService.trigger('save-pipeline-dialog');
+        }
     }
-  }
-
-  displayErrors(data?: string) {
-    this.storageError = true;
-    this.errorMessage = data;
-  }
-
-  getPipelineCategories() {
-    this.pipelineService.getPipelineCategories().subscribe(pipelineCategories => {
-      this.pipelineCategories = pipelineCategories;
-    });
-  }
-
-
-  savePipeline(switchTab) {
-    let storageRequest;
-    const updateMode = this.currentModifiedPipelineId && this.updateMode === 'update';
-
-    if (updateMode) {
-      storageRequest = this.pipelineService.updatePipeline(this.pipeline);
-    } else {
-      if (this.currentModifiedPipelineId) {
-        this.pipeline.actions.forEach(element => this.updateId(element));
-        this.pipeline.sepas.forEach(element => this.updateId(element));
-      }
-      this.pipeline._id = undefined;
-      storageRequest = this.pipelineService.storePipeline(this.pipeline);
+
+    displayErrors(data?: string) {
+        this.storageError = true;
+        this.errorMessage = data;
     }
 
-    storageRequest
-        .subscribe(statusMessage => {
-          if (statusMessage.success) {
-            const pipelineId: string = statusMessage.notifications[1].description;
-            this.storePipelineCanvasMetadata(pipelineId, updateMode);
-            this.afterStorage(statusMessage, switchTab, pipelineId);
-          } else {
-            this.displayErrors(statusMessage.notifications[0]);
-          }
-        }, data => {
-          this.displayErrors();
-        });
-  }
-
-  updateId(entity: InvocablePipelineElementUnion) {
-    const lastIdIndex = entity.elementId.lastIndexOf(':');
-    const newElementId = entity.elementId.substring(0, lastIdIndex + 1) + this.jsplumbService.makeId(5);
-    entity.elementId = newElementId;
-    entity.uri = newElementId;
-  }
-
-  storePipelineCanvasMetadata(pipelineId: string,
-                              updateMode: boolean) {
-    let request;
-    this.pipelineCanvasMetadata.pipelineId = pipelineId;
-    if (updateMode) {
-      request = this.pipelineCanvasService.updatePipelineCanvasMetadata(this.pipelineCanvasMetadata);
-    } else {
-      this.pipelineCanvasMetadata._id = undefined;
-      this.pipelineCanvasMetadata._rev = undefined;
-      request = this.pipelineCanvasService.addPipelineCanvasMetadata(this.pipelineCanvasMetadata);
+    getPipelineCategories() {
+        this.pipelineService
+            .getPipelineCategories()
+            .subscribe(pipelineCategories => {
+                this.pipelineCategories = pipelineCategories;
+            });
     }
 
-    request.subscribe();
-  }
+    savePipeline(switchTab) {
+        let storageRequest;
+        const updateMode =
+            this.currentModifiedPipelineId && this.updateMode === 'update';
+
+        if (updateMode) {
+            storageRequest = this.pipelineService.updatePipeline(this.pipeline);
+        } else {
+            if (this.currentModifiedPipelineId) {
+                this.pipeline.actions.forEach(element =>
+                    this.updateId(element),
+                );
+                this.pipeline.sepas.forEach(element => this.updateId(element));
+            }
+            this.pipeline._id = undefined;
+            storageRequest = this.pipelineService.storePipeline(this.pipeline);
+        }
+
+        storageRequest.subscribe(
+            statusMessage => {
+                if (statusMessage.success) {
+                    const pipelineId: string =
+                        statusMessage.notifications[1].description;
+                    this.storePipelineCanvasMetadata(pipelineId, updateMode);
+                    this.afterStorage(statusMessage, switchTab, pipelineId);
+                } else {
+                    this.displayErrors(statusMessage.notifications[0]);
+                }
+            },
+            data => {
+                this.displayErrors();
+            },
+        );
+    }
 
-  afterStorage(statusMessage: Message, switchTab, pipelineId?: string) {
-    this.hide();
-    this.editorService.makePipelineAssemblyEmpty(true);
-    this.editorService.removePipelineFromCache().subscribe();
-    if (this.shepherdService.isTourActive()) {
-      this.shepherdService.hideCurrentStep();
+    updateId(entity: InvocablePipelineElementUnion) {
+        const lastIdIndex = entity.elementId.lastIndexOf(':');
+        const newElementId =
+            entity.elementId.substring(0, lastIdIndex + 1) +
+            this.jsplumbService.makeId(5);
+        entity.elementId = newElementId;
+        entity.uri = newElementId;
     }
-    if (switchTab && !this.startPipelineAfterStorage) {
-      this.router.navigate(['pipelines']);
+
+    storePipelineCanvasMetadata(pipelineId: string, updateMode: boolean) {
+        let request;
+        this.pipelineCanvasMetadata.pipelineId = pipelineId;
+        if (updateMode) {
+            request = this.pipelineCanvasService.updatePipelineCanvasMetadata(
+                this.pipelineCanvasMetadata,
+            );
+        } else {
+            this.pipelineCanvasMetadata._id = undefined;
+            this.pipelineCanvasMetadata._rev = undefined;
+            request = this.pipelineCanvasService.addPipelineCanvasMetadata(
+                this.pipelineCanvasMetadata,
+            );
+        }
+
+        request.subscribe();
     }
-    if (this.startPipelineAfterStorage) {
-      this.router.navigate(['pipelines'], { queryParams: {pipeline: pipelineId}});
+
+    afterStorage(statusMessage: Message, switchTab, pipelineId?: string) {
+        this.hide();
+        this.editorService.makePipelineAssemblyEmpty(true);
+        this.editorService.removePipelineFromCache().subscribe();
+        if (this.shepherdService.isTourActive()) {
+            this.shepherdService.hideCurrentStep();
+        }
+        if (switchTab && !this.startPipelineAfterStorage) {
+            this.router.navigate(['pipelines']);
+        }
+        if (this.startPipelineAfterStorage) {
+            this.router.navigate(['pipelines'], {
+                queryParams: { pipeline: pipelineId },
+            });
+        }
     }
-  }
 
-  hide() {
-    this.dialogRef.close();
-  }
+    hide() {
+        this.dialogRef.close();
+    }
 }
diff --git a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.html b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.html
index 1bd25ee80..458863dbd 100644
--- a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.html
+++ b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.html
@@ -20,25 +20,54 @@
     <div class="sp-dialog-content p-15" fxLayout="column">
         <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
             <b><h2 class="welcome-animation">Hello!</h2></b>
-            <b><h3>Thank you for using {{appConstants.APP_NAME}}.</h3></b>
+            <b
+                ><h3>Thank you for using {{ appConstants.APP_NAME }}.</h3></b
+            >
         </div>
-        <div><img src="assets/img/sp-pipeline-white-small.png"
-                  style="margin-left:auto;margin-right:auto;display:block;">
+        <div>
+            <img
+                src="assets/img/sp-pipeline-white-small.png"
+                style="margin-left: auto; margin-right: auto; display: block"
+            />
         </div>
         <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
             <div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
-                <b>{{appConstants.APP_NAME}} is your self-service toolbox for real-time analytics.</b>
-                <p>If you are using {{appConstants.APP_NAME}} for the first time, we recommend taking the interactive tour!</p>
+                <b
+                    >{{ appConstants.APP_NAME }} is your self-service toolbox
+                    for real-time analytics.</b
+                >
+                <p>
+                    If you are using {{ appConstants.APP_NAME }} for the first
+                    time, we recommend taking the interactive tour!
+                </p>
             </div>
-            <button mat-button mat-raised-button color="accent" (click)="startCreatePipelineTour()">Start Tour</button>
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                (click)="startCreatePipelineTour()"
+            >
+                Start Tour
+            </button>
         </div>
     </div>
     <mat-divider></mat-divider>
     <div class="sp-dialog-actions actions-align-right" fxLayout="row">
-        <button mat-button mat-raised-button class="mat-basic" (click)="hideTourForever()" style="margin-right:10px;">
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic"
+            (click)="hideTourForever()"
+            style="margin-right: 10px"
+        >
             Do not show again
         </button>
-        <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic"
+            (click)="close()"
+        >
             Close
         </button>
     </div>
diff --git a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.scss b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.scss
index b0978136d..564502677 100644
--- a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.scss
+++ b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.scss
@@ -19,23 +19,23 @@
 @import '../../../../scss/sp/sp-dialog.scss';
 
 .welcome-animation {
-  font-family: Arial;
-  border-right: .1em solid black;
-  width: 5ch;
-  white-space: nowrap;
-  overflow: hidden;
-  -webkit-animation: typing 1s steps(5, end),
-  blink-caret .5s step-end infinite alternate;
+    font-family: Arial;
+    border-right: 0.1em solid black;
+    width: 5ch;
+    white-space: nowrap;
+    overflow: hidden;
+    -webkit-animation: typing 1s steps(5, end),
+        blink-caret 0.5s step-end infinite alternate;
 }
 
 @keyframes typing {
-  from {
-    width: 0;
-  }
+    from {
+        width: 0;
+    }
 }
 
 @keyframes blink-caret {
-  50% {
-    border-color: transparent;
-  }
-}
\ No newline at end of file
+    50% {
+        border-color: transparent;
+    }
+}
diff --git a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
index 14bc15fd4..8690b4785 100644
--- a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
+++ b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
@@ -25,45 +25,48 @@ import { UserAccount, UserInfo } from '@streampipes/platform-services';
 import { ProfileService } from '../../../profile/profile.service';
 
 @Component({
-  selector: 'welcome-tour',
-  templateUrl: './welcome-tour.component.html',
-  styleUrls: ['./welcome-tour.component.scss']
+    selector: 'sp-welcome-tour',
+    templateUrl: './welcome-tour.component.html',
+    styleUrls: ['./welcome-tour.component.scss'],
 })
 export class WelcomeTourComponent implements OnInit {
+    @Input()
+    userInfo: UserInfo;
 
-  @Input()
-  userInfo: UserInfo;
+    currentUser: UserAccount;
 
-  currentUser: UserAccount;
+    constructor(
+        private authService: AuthService,
+        private dialogRef: DialogRef<WelcomeTourComponent>,
+        private profileService: ProfileService,
+        private shepherdService: ShepherdService,
+        public appConstants: AppConstants,
+    ) {}
 
-  constructor(private authService: AuthService,
-              private dialogRef: DialogRef<WelcomeTourComponent>,
-              private profileService: ProfileService,
-              private shepherdService: ShepherdService,
-              public appConstants: AppConstants) {
-  }
+    ngOnInit(): void {
+        this.profileService
+            .getUserProfile(this.userInfo.username)
+            .subscribe(data => {
+                this.currentUser = data;
+            });
+    }
 
-  ngOnInit(): void {
-    this.profileService.getUserProfile(this.userInfo.username).subscribe(data => {
-      this.currentUser = data;
-    });
-  }
+    startCreatePipelineTour() {
+        this.shepherdService.startCreatePipelineTour();
+        this.close();
+    }
 
-  startCreatePipelineTour() {
-    this.shepherdService.startCreatePipelineTour();
-    this.close();
-  }
-
-  hideTourForever() {
-    this.currentUser.hideTutorial = true;
-    this.profileService.updateUserProfile(this.currentUser).subscribe(data => {
-      this.authService.updateTokenAndUserInfo();
-      this.close();
-    });
-  }
-
-  close() {
-    this.dialogRef.close();
-  }
+    hideTourForever() {
+        this.currentUser.hideTutorial = true;
+        this.profileService
+            .updateUserProfile(this.currentUser)
+            .subscribe(data => {
+                this.authService.updateTokenAndUserInfo();
+                this.close();
+            });
+    }
 
+    close() {
+        this.dialogRef.close();
+    }
 }
diff --git a/ui/src/app/editor/editor.component.html b/ui/src/app/editor/editor.component.html
index 0a2528145..ddd45dd0e 100644
--- a/ui/src/app/editor/editor.component.html
+++ b/ui/src/app/editor/editor.component.html
@@ -19,23 +19,42 @@
 <div fxLayout="column" class="page-container">
     <div class="fixed-height" fxLayout="row" fxFlex="100">
         <div fxFlex="250px">
-            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="!allElementsLoaded">
-                <mat-spinner [diameter]="30" color="accent" mode="indeterminate"></mat-spinner>
+            <div
+                fxFlex="100"
+                fxLayout="column"
+                fxLayoutAlign="center center"
+                *ngIf="!allElementsLoaded"
+            >
+                <mat-spinner
+                    [diameter]="30"
+                    color="accent"
+                    mode="indeterminate"
+                ></mat-spinner>
                 <p>Loading pipeline elements...</p>
             </div>
-            <div id="shepherd-test"
-                 style="padding:0px;border-bottom:1px solid #ffffff;margin-right: 5px;">
-                <pipeline-element-icon-stand
-                        [allElements]="allElements"
-                        *ngIf="allElementsLoaded"
-                        (startTourEmitter)="startCreatePipelineTour()">
-                </pipeline-element-icon-stand>
+            <div
+                id="shepherd-test"
+                style="
+                    padding: 0px;
+                    border-bottom: 1px solid #ffffff;
+                    margin-right: 5px;
+                "
+            >
+                <sp-pipeline-element-icon-stand
+                    [allElements]="allElements"
+                    *ngIf="allElementsLoaded"
+                    (startTourEmitter)="startCreatePipelineTour()"
+                >
+                </sp-pipeline-element-icon-stand>
             </div>
         </div>
-        <pipeline-assembly fxFlex="100" style="margin-left: 10px;"
-                           [rawPipelineModel]="rawPipelineModel"
-                           [allElements]="allElements"
-                           [currentModifiedPipelineId]="currentModifiedPipelineId">
-        </pipeline-assembly>
+        <sp-pipeline-assembly
+            fxFlex="100"
+            style="margin-left: 10px"
+            [rawPipelineModel]="rawPipelineModel"
+            [allElements]="allElements"
+            [currentModifiedPipelineId]="currentModifiedPipelineId"
+        >
+        </sp-pipeline-assembly>
     </div>
 </div>
diff --git a/ui/src/app/editor/editor.component.scss b/ui/src/app/editor/editor.component.scss
index 58b8fb3d8..7eb1f8c3e 100644
--- a/ui/src/app/editor/editor.component.scss
+++ b/ui/src/app/editor/editor.component.scss
@@ -19,18 +19,18 @@
 @import '../../scss/variables';
 
 .text-color {
-  color: var(--color-accent);
+    color: var(--color-accent);
 }
 
 .page-container {
-  border: 0;
+    border: 0;
 }
 
 .border {
-  border: 1px solid var(--color-bg-2);
+    border: 1px solid var(--color-bg-2);
 }
 
 .editor-canvas-options {
-  padding: 0;
-  background-color: var(--color-bg-1);
+    padding: 0;
+    background-color: var(--color-bg-1);
 }
diff --git a/ui/src/app/editor/editor.component.ts b/ui/src/app/editor/editor.component.ts
index ddebcef2d..1085451e2 100644
--- a/ui/src/app/editor/editor.component.ts
+++ b/ui/src/app/editor/editor.component.ts
@@ -19,12 +19,17 @@
 import { Component, OnInit } from '@angular/core';
 import { EditorService } from './services/editor.service';
 import { PipelineElementService } from '@streampipes/platform-services';
-import { PipelineElementConfig, PipelineElementUnion } from './model/editor.model';
-import { DialogService, PanelType, SpBreadcrumbService } from '@streampipes/shared-ui';
-import { WelcomeTourComponent } from './dialog/welcome-tour/welcome-tour.component';
 import {
-  MissingElementsForTutorialComponent
-} from './dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component';
+    PipelineElementConfig,
+    PipelineElementUnion,
+} from './model/editor.model';
+import {
+    DialogService,
+    PanelType,
+    SpBreadcrumbService,
+} from '@streampipes/shared-ui';
+import { WelcomeTourComponent } from './dialog/welcome-tour/welcome-tour.component';
+import { MissingElementsForTutorialComponent } from './dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component';
 import { ShepherdService } from '../services/tour/shepherd.service';
 import { ActivatedRoute } from '@angular/router';
 import { AuthService } from '../services/auth.service';
@@ -33,127 +38,152 @@ import { AppConstants } from '../services/app.constants';
 import { SpPipelineRoutes } from '../pipelines/pipelines.routes';
 
 @Component({
-  selector: 'editor',
-  templateUrl: './editor.component.html',
-  styleUrls: ['./editor.component.scss']
+    selector: 'sp-editor',
+    templateUrl: './editor.component.html',
+    styleUrls: ['./editor.component.scss'],
 })
 export class EditorComponent implements OnInit {
-
-  allElements: PipelineElementUnion[] = [];
-
-  rawPipelineModel: PipelineElementConfig[] = [];
-  currentModifiedPipelineId: string;
-
-  allElementsLoaded = false;
-
-  requiredStreamForTutorialAppId: any = 'org.apache.streampipes.sources.simulator.flowrate1';
-  requiredProcessorForTutorialAppId: any = 'org.apache.streampipes.processors.filters.jvm.numericalfilter';
-  requiredSinkForTutorialAppId: any = 'org.apache.streampipes.sinks.internal.jvm.datalake';
-  missingElementsForTutorial: any = [];
-
-  isTutorialOpen = false;
-
-  constructor(private editorService: EditorService,
-              private pipelineElementService: PipelineElementService,
-              private authService: AuthService,
-              private dialogService: DialogService,
-              private shepherdService: ShepherdService,
-              private activatedRoute: ActivatedRoute,
-              private appConstants: AppConstants,
-              private breadcrumbService: SpBreadcrumbService) {
-  }
-
-  ngOnInit() {
-    this.activatedRoute.params.subscribe(params => {
-      if (params.pipelineId) {
-        this.currentModifiedPipelineId = params.pipelineId;
-      } else {
-        this.breadcrumbService.updateBreadcrumb([SpPipelineRoutes.BASE, {label: 'New Pipeline'}]);
-      }
-    });
-    zip(this.pipelineElementService.getDataStreams(),
-      this.pipelineElementService.getDataProcessors(),
-      this.pipelineElementService.getDataSinks()).subscribe(response => {
-      this.allElements = this.allElements
-        .concat(response[0])
-        .concat(response[1])
-        .concat(response[2])
-        .sort((a, b) => {
-          return a.name.localeCompare(b.name);
+    allElements: PipelineElementUnion[] = [];
+
+    rawPipelineModel: PipelineElementConfig[] = [];
+    currentModifiedPipelineId: string;
+
+    allElementsLoaded = false;
+
+    requiredStreamForTutorialAppId: any =
+        'org.apache.streampipes.sources.simulator.flowrate1';
+    requiredProcessorForTutorialAppId: any =
+        'org.apache.streampipes.processors.filters.jvm.numericalfilter';
+    requiredSinkForTutorialAppId: any =
+        'org.apache.streampipes.sinks.internal.jvm.datalake';
+    missingElementsForTutorial: any = [];
+
+    isTutorialOpen = false;
+
+    constructor(
+        private editorService: EditorService,
+        private pipelineElementService: PipelineElementService,
+        private authService: AuthService,
+        private dialogService: DialogService,
+        private shepherdService: ShepherdService,
+        private activatedRoute: ActivatedRoute,
+        private appConstants: AppConstants,
+        private breadcrumbService: SpBreadcrumbService,
+    ) {}
+
+    ngOnInit() {
+        this.activatedRoute.params.subscribe(params => {
+            if (params.pipelineId) {
+                this.currentModifiedPipelineId = params.pipelineId;
+            } else {
+                this.breadcrumbService.updateBreadcrumb([
+                    SpPipelineRoutes.BASE,
+                    { label: 'New Pipeline' },
+                ]);
+            }
         });
-      this.allElementsLoaded = true;
-      this.checkForTutorial();
-    });
-  }
-
-  checkForTutorial() {
-    const currentUser = this.authService.getCurrentUser();
-    if (currentUser.showTutorial && !this.isTutorialOpen) {
-      if (this.requiredPipelineElementsForTourPresent()) {
-        this.isTutorialOpen = true;
-        this.dialogService.open(WelcomeTourComponent, {
-          panelType: PanelType.STANDARD_PANEL,
-          title: 'Welcome to ' + this.appConstants.APP_NAME,
-          data: {
-            'userInfo': currentUser
-          }
+        zip(
+            this.pipelineElementService.getDataStreams(),
+            this.pipelineElementService.getDataProcessors(),
+            this.pipelineElementService.getDataSinks(),
+        ).subscribe(response => {
+            this.allElements = this.allElements
+                .concat(response[0])
+                .concat(response[1])
+                .concat(response[2])
+                .sort((a, b) => {
+                    return a.name.localeCompare(b.name);
+                });
+            this.allElementsLoaded = true;
+            this.checkForTutorial();
         });
-      }
     }
-  }
-
-  startCreatePipelineTour() {
-    if (this.requiredPipelineElementsForTourPresent()) {
-      this.shepherdService.startCreatePipelineTour();
-    } else {
-      this.missingElementsForTutorial = [];
-      if (!this.requiredStreamForTourPresent()) {
-        this.missingElementsForTutorial.push({'name': 'Flow Rate 1', 'appId': this.requiredStreamForTutorialAppId});
-      }
-      if (!this.requiredProcessorForTourPresent()) {
-        this.missingElementsForTutorial.push({
-          'name': 'Numerical Filter',
-          'appId': this.requiredProcessorForTutorialAppId
-        });
-      }
-      if (!this.requiredSinkForTourPresent()) {
-        this.missingElementsForTutorial.push({'name': 'Dashboard Sink', 'appId': this.requiredSinkForTutorialAppId});
-      }
-
-      this.dialogService.open(MissingElementsForTutorialComponent, {
-        panelType: PanelType.STANDARD_PANEL,
-        title: 'Tutorial requires pipeline elements',
-        data: {
-          'missingElementsForTutorial': this.missingElementsForTutorial
+
+    checkForTutorial() {
+        const currentUser = this.authService.getCurrentUser();
+        if (currentUser.showTutorial && !this.isTutorialOpen) {
+            if (this.requiredPipelineElementsForTourPresent()) {
+                this.isTutorialOpen = true;
+                this.dialogService.open(WelcomeTourComponent, {
+                    panelType: PanelType.STANDARD_PANEL,
+                    title: 'Welcome to ' + this.appConstants.APP_NAME,
+                    data: {
+                        userInfo: currentUser,
+                    },
+                });
+            }
         }
-      });
     }
-  }
-
-  requiredPipelineElementsForTourPresent() {
-    return this.requiredStreamForTourPresent() &&
-      this.requiredProcessorForTourPresent() &&
-      this.requiredSinkForTourPresent();
-  }
-
-  requiredStreamForTourPresent() {
-    return this.requiredPeForTourPresent(this.allElements,
-      this.requiredStreamForTutorialAppId);
-  }
-
-  requiredProcessorForTourPresent() {
-    return this.requiredPeForTourPresent(this.allElements,
-      this.requiredProcessorForTutorialAppId);
-  }
-
-  requiredSinkForTourPresent() {
-    return this.requiredPeForTourPresent(this.allElements,
-      this.requiredSinkForTutorialAppId);
-  }
-
-  requiredPeForTourPresent(list, appId) {
-    return list && list.some(el => {
-      return el.appId === appId;
-    });
-  }
+
+    startCreatePipelineTour() {
+        if (this.requiredPipelineElementsForTourPresent()) {
+            this.shepherdService.startCreatePipelineTour();
+        } else {
+            this.missingElementsForTutorial = [];
+            if (!this.requiredStreamForTourPresent()) {
+                this.missingElementsForTutorial.push({
+                    name: 'Flow Rate 1',
+                    appId: this.requiredStreamForTutorialAppId,
+                });
+            }
+            if (!this.requiredProcessorForTourPresent()) {
+                this.missingElementsForTutorial.push({
+                    name: 'Numerical Filter',
+                    appId: this.requiredProcessorForTutorialAppId,
+                });
+            }
+            if (!this.requiredSinkForTourPresent()) {
+                this.missingElementsForTutorial.push({
+                    name: 'Dashboard Sink',
+                    appId: this.requiredSinkForTutorialAppId,
+                });
+            }
+
+            this.dialogService.open(MissingElementsForTutorialComponent, {
+                panelType: PanelType.STANDARD_PANEL,
+                title: 'Tutorial requires pipeline elements',
+                data: {
+                    missingElementsForTutorial: this.missingElementsForTutorial,
+                },
+            });
+        }
+    }
+
+    requiredPipelineElementsForTourPresent() {
+        return (
+            this.requiredStreamForTourPresent() &&
+            this.requiredProcessorForTourPresent() &&
+            this.requiredSinkForTourPresent()
+        );
+    }
+
+    requiredStreamForTourPresent() {
+        return this.requiredPeForTourPresent(
+            this.allElements,
+            this.requiredStreamForTutorialAppId,
+        );
+    }
+
+    requiredProcessorForTourPresent() {
+        return this.requiredPeForTourPresent(
+            this.allElements,
+            this.requiredProcessorForTutorialAppId,
+        );
+    }
+
+    requiredSinkForTourPresent() {
+        return this.requiredPeForTourPresent(
+            this.allElements,
+            this.requiredSinkForTutorialAppId,
+        );
+    }
+
+    requiredPeForTourPresent(list, appId) {
+        return (
+            list &&
+            list.some(el => {
+                return el.appId === appId;
+            })
+        );
+    }
 }
diff --git a/ui/src/app/editor/editor.module.ts b/ui/src/app/editor/editor.module.ts
index 284ce1faa..fb96615f3 100644
--- a/ui/src/app/editor/editor.module.ts
+++ b/ui/src/app/editor/editor.module.ts
@@ -63,7 +63,6 @@ import { PipelineElementTypeFilterPipe } from './services/pipeline-element-type-
 import { PipelineElementNameFilterPipe } from './services/pipeline-element-name-filter.pipe';
 import { PipelineElementGroupFilterPipe } from './services/pipeline-element-group-filter.pipe';
 
-
 @NgModule({
     imports: [
         CoreUiModule,
@@ -109,21 +108,11 @@ import { PipelineElementGroupFilterPipe } from './services/pipeline-element-grou
         PropertySelectionComponent,
         SavePipelineComponent,
         SafeCss,
-        WelcomeTourComponent
-    ],
-    providers: [
-        SemanticTypeUtilsService,
-        SafeCss,
+        WelcomeTourComponent,
     ],
-    exports: [
-        EditorComponent,
-        PipelineComponent,
-        PipelineElementComponent
-    ]
+    providers: [SemanticTypeUtilsService, SafeCss],
+    exports: [EditorComponent, PipelineComponent, PipelineElementComponent],
 })
 export class EditorModule {
-
-  constructor() {
-  }
-
+    constructor() {}
 }
diff --git a/ui/src/app/editor/filter/enabled-pipeline-element.filter.ts b/ui/src/app/editor/filter/enabled-pipeline-element.filter.ts
index 36b1a5de7..02730ebad 100644
--- a/ui/src/app/editor/filter/enabled-pipeline-element.filter.ts
+++ b/ui/src/app/editor/filter/enabled-pipeline-element.filter.ts
@@ -20,14 +20,17 @@ import { Pipe, PipeTransform } from '@angular/core';
 import { PipelineElementConfig } from '../model/editor.model';
 
 @Pipe({
-  name: 'enabledPipelineElement',
-  pure: false
+    name: 'enabledPipelineElement',
+    pure: false,
 })
 export class EnabledPipelineElementFilter implements PipeTransform {
-  transform(items: PipelineElementConfig[]): any {
-    if (!items) {
-      return items;
+    transform(items: PipelineElementConfig[]): any {
+        if (!items) {
+            return items;
+        }
+        return items.filter(
+            item =>
+                item.settings.disabled === undefined || !item.settings.disabled,
+        );
     }
-    return items.filter(item => item.settings.disabled === undefined || !item.settings.disabled);
-  }
 }
diff --git a/ui/src/app/editor/model/editor.model.ts b/ui/src/app/editor/model/editor.model.ts
index 45945be6b..61c651a99 100644
--- a/ui/src/app/editor/model/editor.model.ts
+++ b/ui/src/app/editor/model/editor.model.ts
@@ -16,79 +16,87 @@
  *
  */
 
-import { DataProcessorInvocation, DataSinkInvocation, SpDataSet, SpDataStream } from '@streampipes/platform-services';
+import {
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    SpDataSet,
+    SpDataStream,
+} from '@streampipes/platform-services';
 import { InjectionToken } from '@angular/core';
 
 export interface PipelineElementHolder {
-  [key: string]: PipelineElementUnion[];
+    [key: string]: PipelineElementUnion[];
 }
 
 export interface PipelineElementPosition {
-  x: number;
-  y: number;
+    x: number;
+    y: number;
 }
 
 export enum PipelineElementConfigurationStatus {
-  OK = 1,
-  MODIFIED,
-  INCOMPLETE,
+    OK = 1,
+    MODIFIED,
+    INCOMPLETE,
 }
 
 export interface PipelineElementConfig {
-  type: string;
-  settings: {
-    openCustomize: boolean,
-    preview: boolean,
-    displaySettings: string,
-    connectable: string,
-    disabled: boolean,
-    loadingStatus: boolean,
-    completed: PipelineElementConfigurationStatus
-    position: {
-      x: number,
-      y: number
-    }
-  };
-  payload: PipelineElementUnion;
+    type: string;
+    settings: {
+        openCustomize: boolean;
+        preview: boolean;
+        displaySettings: string;
+        connectable: string;
+        disabled: boolean;
+        loadingStatus: boolean;
+        completed: PipelineElementConfigurationStatus;
+        position: {
+            x: number;
+            y: number;
+        };
+    };
+    payload: PipelineElementUnion;
 }
 
 export interface PipelineElementRecommendationLayout {
-  skewStyle: any;
-  unskewStyle: any;
-  unskewStyleLabel: any;
-  type: string;
+    skewStyle: any;
+    unskewStyle: any;
+    unskewStyleLabel: any;
+    type: string;
 }
 
 export enum PipelineElementType {
-  DataSet,
-  DataStream,
-  DataProcessor,
-  DataSink
+    DataSet,
+    DataStream,
+    DataProcessor,
+    DataSink,
 }
 
 export interface TabsModel {
-  title: string;
-  type: PipelineElementIdentifier;
-  shorthand: string;
+    title: string;
+    type: PipelineElementIdentifier;
+    shorthand: string;
 }
 
 export type PipelineElementUnion =
-    SpDataSet
+    | SpDataSet
     | SpDataStream
     | DataProcessorInvocation
     | DataSinkInvocation;
 
-export type InvocablePipelineElementUnion = DataProcessorInvocation | DataSinkInvocation;
+export type InvocablePipelineElementUnion =
+    | DataProcessorInvocation
+    | DataSinkInvocation;
 
 export const PIPELINE_ELEMENT_TOKEN = new InjectionToken<{}>('pipelineElement');
 
-export type PipelineElementIdentifier = 'org.apache.streampipes.model.SpDataStream'
+export type PipelineElementIdentifier =
+    | 'org.apache.streampipes.model.SpDataStream'
     | 'org.apache.streampipes.model.SpDataSet'
     | 'org.apache.streampipes.model.graph.DataProcessorInvocation'
     | 'org.apache.streampipes.model.graph.DataSinkInvocation';
 
 export interface PeCategory {
-  code: string;
-  label: string;
-  description: string;
+    code: string;
+    label: string;
+    description: string;
 }
diff --git a/ui/src/app/editor/model/jsplumb.model.ts b/ui/src/app/editor/model/jsplumb.model.ts
index 4b46941d7..5c9a55e72 100644
--- a/ui/src/app/editor/model/jsplumb.model.ts
+++ b/ui/src/app/editor/model/jsplumb.model.ts
@@ -17,10 +17,10 @@
  */
 
 export interface JsplumbSettings {
-  dotRadius: number;
-  lineWidth: number;
-  arrowWidth: number;
-  arrowLength: number;
-  arrowLineWidth: number;
-  curviness: number;
+    dotRadius: number;
+    lineWidth: number;
+    arrowWidth: number;
+    arrowLength: number;
+    arrowLineWidth: number;
+    curviness: number;
 }
diff --git a/ui/src/app/editor/services/editor.service.ts b/ui/src/app/editor/services/editor.service.ts
index 99c19e397..6aef9e793 100644
--- a/ui/src/app/editor/services/editor.service.ts
+++ b/ui/src/app/editor/services/editor.service.ts
@@ -19,114 +19,164 @@
 import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import {
-  DataProcessorInvocation,
-  DataSetModificationMessage,
-  DataSinkInvocation,
-  Pipeline,
-  PipelineCanvasMetadata,
-  PipelineElementRecommendationMessage,
-  PipelineModificationMessage,
-  PipelinePreviewModel,
-  PlatformServicesCommons,
-  SpDataSet,
-  SpDataStream
+    DataProcessorInvocation,
+    DataSetModificationMessage,
+    DataSinkInvocation,
+    Pipeline,
+    PipelineCanvasMetadata,
+    PipelineElementRecommendationMessage,
+    PipelineModificationMessage,
+    PipelinePreviewModel,
+    PlatformServicesCommons,
+    SpDataSet,
+    SpDataStream,
 } from '@streampipes/platform-services';
 import { Observable, Subject } from 'rxjs';
-import { PeCategory, PipelineElementConfig, PipelineElementUnion } from '../model/editor.model';
+import {
+    PeCategory,
+    PipelineElementConfig,
+    PipelineElementUnion,
+} from '../model/editor.model';
 import { DialogService, PanelType } from '@streampipes/shared-ui';
 import { HelpComponent } from '../dialog/help/help.component';
 import { map } from 'rxjs/operators';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class EditorService {
-
     private pipelineElementConfigured = new Subject<string>();
 
-    public pipelineElementConfigured$ = this.pipelineElementConfigured.asObservable();
+    public pipelineElementConfigured$ =
+        this.pipelineElementConfigured.asObservable();
 
     pipelineAssemblyEmpty = true;
 
-    constructor(private http: HttpClient,
-                private platformServicesCommons: PlatformServicesCommons,
-                private dialogService: DialogService) {
-    }
+    constructor(
+        private http: HttpClient,
+        private platformServicesCommons: PlatformServicesCommons,
+        private dialogService: DialogService,
+    ) {}
 
     get apiBasePath() {
-      return this.platformServicesCommons.apiBasePath;
+        return this.platformServicesCommons.apiBasePath;
     }
 
-    recommendPipelineElement(pipeline: Pipeline,
-                             currentDomId: string): Observable<PipelineElementRecommendationMessage> {
-        return this.http.post(this.pipelinesResourceUrl + '/recommend/' + currentDomId, pipeline)
-            .pipe(map(data => PipelineElementRecommendationMessage.fromData(data as any)));
+    recommendPipelineElement(
+        pipeline: Pipeline,
+        currentDomId: string,
+    ): Observable<PipelineElementRecommendationMessage> {
+        return this.http
+            .post(
+                this.pipelinesResourceUrl + '/recommend/' + currentDomId,
+                pipeline,
+            )
+            .pipe(
+                map(data =>
+                    PipelineElementRecommendationMessage.fromData(data as any),
+                ),
+            );
     }
 
     updatePartialPipeline(pipeline): Observable<PipelineModificationMessage> {
-        return this.http.post(this.pipelinesResourceUrl + '/update', pipeline)
-            .pipe(map(data => {
-                return PipelineModificationMessage.fromData(data as any);
-            }));
+        return this.http
+            .post(this.pipelinesResourceUrl + '/update', pipeline)
+            .pipe(
+                map(data => {
+                    return PipelineModificationMessage.fromData(data as any);
+                }),
+            );
+    }
+
+    updateDataSet(dataSet): Observable<DataSetModificationMessage> {
+        return this.http
+            .post(
+                this.platformServicesCommons.apiBasePath +
+                    '/pipelines/update/dataset',
+                dataSet,
+            )
+            .pipe(
+                map(data =>
+                    DataSetModificationMessage.fromData(
+                        data as DataSetModificationMessage,
+                    ),
+                ),
+            );
     }
 
-  updateDataSet(dataSet): Observable<DataSetModificationMessage> {
-    return this.http.post(this.platformServicesCommons.apiBasePath + '/pipelines/update/dataset', dataSet)
-        .pipe(map(data => DataSetModificationMessage.fromData(data as DataSetModificationMessage)));
-  }
-
     getCachedPipeline(): Observable<PipelineElementConfig[]> {
-        return this.http.get(this.apiBasePath + '/pipeline-cache')
-            .pipe(map(result => {
-              if (result === null) {
-                return [];
-              } else {
-                const configs: PipelineElementConfig[] = result as PipelineElementConfig[];
-                configs.map(config => config.payload = this.convert(config.payload));
-                return configs;
-              }
-            }));
+        return this.http.get(this.apiBasePath + '/pipeline-cache').pipe(
+            map(result => {
+                if (result === null) {
+                    return [];
+                } else {
+                    const configs: PipelineElementConfig[] =
+                        result as PipelineElementConfig[];
+                    configs.map(
+                        config =>
+                            (config.payload = this.convert(config.payload)),
+                    );
+                    return configs;
+                }
+            }),
+        );
     }
 
     getCachedPipelineCanvasMetadata(): Observable<PipelineCanvasMetadata> {
-      return this.http.get(this.apiBasePath + '/pipeline-canvas-cache')
-          .pipe(map(response => {
-            return PipelineCanvasMetadata.fromData(response as any);
-      }));
+        return this.http.get(this.apiBasePath + '/pipeline-canvas-cache').pipe(
+            map(response => {
+                return PipelineCanvasMetadata.fromData(response as any);
+            }),
+        );
     }
 
     convert(payload: any) {
-      if (payload['@class'] === 'org.apache.streampipes.model.SpDataSet') {
-        return SpDataSet.fromData(payload as SpDataSet);
-      } else if (payload['@class'] === 'org.apache.streampipes.model.SpDataStream') {
-        return SpDataStream.fromData(payload as SpDataStream);
-      } else if (payload['@class'] === 'org.apache.streampipes.model.graph.DataProcessorInvocation') {
-        return DataProcessorInvocation.fromData(payload as DataProcessorInvocation);
-      } else {
-        return DataSinkInvocation.fromData(payload as DataSinkInvocation);
-      }
+        if (payload['@class'] === 'org.apache.streampipes.model.SpDataSet') {
+            return SpDataSet.fromData(payload as SpDataSet);
+        } else if (
+            payload['@class'] === 'org.apache.streampipes.model.SpDataStream'
+        ) {
+            return SpDataStream.fromData(payload as SpDataStream);
+        } else if (
+            payload['@class'] ===
+            'org.apache.streampipes.model.graph.DataProcessorInvocation'
+        ) {
+            return DataProcessorInvocation.fromData(
+                payload as DataProcessorInvocation,
+            );
+        } else {
+            return DataSinkInvocation.fromData(payload as DataSinkInvocation);
+        }
     }
 
     getEpCategories(): Observable<PeCategory[]> {
-        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/ep')
-          .pipe(map(response => response as PeCategory[]));
+        return this.http
+            .get(this.platformServicesCommons.apiBasePath + '/categories/ep')
+            .pipe(map(response => response as PeCategory[]));
     }
 
     getEpaCategories(): Observable<PeCategory[]> {
-        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/epa')
-          .pipe(map(response => response as PeCategory[]));
+        return this.http
+            .get(this.platformServicesCommons.apiBasePath + '/categories/epa')
+            .pipe(map(response => response as PeCategory[]));
     }
 
     getEcCategories(): Observable<PeCategory[]> {
-        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/ec')
-          .pipe(map(response => response as PeCategory[]));
+        return this.http
+            .get(this.platformServicesCommons.apiBasePath + '/categories/ec')
+            .pipe(map(response => response as PeCategory[]));
     }
 
     updateCachedPipeline(rawPipelineModel: any) {
-        return this.http.post(this.apiBasePath + '/pipeline-cache', rawPipelineModel);
+        return this.http.post(
+            this.apiBasePath + '/pipeline-cache',
+            rawPipelineModel,
+        );
     }
 
     updateCachedCanvasMetadata(pipelineCanvasMetadata: PipelineCanvasMetadata) {
-      return this.http.post(this.platformServicesCommons.apiBasePath
-          + '/pipeline-canvas-cache', pipelineCanvasMetadata);
+        return this.http.post(
+            this.platformServicesCommons.apiBasePath + '/pipeline-canvas-cache',
+            pipelineCanvasMetadata,
+        );
     }
 
     removePipelineFromCache() {
@@ -134,7 +184,7 @@ export class EditorService {
     }
 
     removeCanvasMetadataFromCache() {
-      return this.http.delete(this.apiBasePath + '/pipeline-canvas-cache');
+        return this.http.delete(this.apiBasePath + '/pipeline-canvas-cache');
     }
 
     private get pipelinesResourceUrl() {
@@ -155,28 +205,40 @@ export class EditorService {
             title: pipelineElement.name,
             width: '70vw',
             data: {
-                'pipelineElement': pipelineElement
-            }
+                pipelineElement: pipelineElement,
+            },
         });
     }
 
-    initiatePipelinePreview(pipeline: Pipeline): Observable<PipelinePreviewModel> {
-      return this.http.post(this.pipelinePreviewBasePath, pipeline)
-          .pipe(map(response => PipelinePreviewModel.fromData(response as any)));
+    initiatePipelinePreview(
+        pipeline: Pipeline,
+    ): Observable<PipelinePreviewModel> {
+        return this.http
+            .post(this.pipelinePreviewBasePath, pipeline)
+            .pipe(
+                map(response => PipelinePreviewModel.fromData(response as any)),
+            );
     }
 
-  deletePipelinePreviewRequest(previewId: string): Observable<any> {
-      return this.http.delete(this.pipelinePreviewBasePath + '/' + previewId);
-  }
+    deletePipelinePreviewRequest(previewId: string): Observable<any> {
+        return this.http.delete(this.pipelinePreviewBasePath + '/' + previewId);
+    }
 
-  getPipelinePreviewResult(previewId: string, pipelineElementDomId: string): Observable<any> {
-      return this.http.get(this.pipelinePreviewBasePath
-          + '/'
-          + previewId
-          + '/' + pipelineElementDomId, {headers: { ignoreLoadingBar: '' }});
-  }
+    getPipelinePreviewResult(
+        previewId: string,
+        pipelineElementDomId: string,
+    ): Observable<any> {
+        return this.http.get(
+            this.pipelinePreviewBasePath +
+                '/' +
+                previewId +
+                '/' +
+                pipelineElementDomId,
+            { headers: { ignoreLoadingBar: '' } },
+        );
+    }
 
-  get pipelinePreviewBasePath() {
-      return this.apiBasePath + '/pipeline-element-preview';
-  }
+    get pipelinePreviewBasePath() {
+        return this.apiBasePath + '/pipeline-element-preview';
+    }
 }
diff --git a/ui/src/app/editor/services/jsplumb-bridge.service.ts b/ui/src/app/editor/services/jsplumb-bridge.service.ts
index 4652d8508..bed379230 100644
--- a/ui/src/app/editor/services/jsplumb-bridge.service.ts
+++ b/ui/src/app/editor/services/jsplumb-bridge.service.ts
@@ -20,16 +20,18 @@ import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui';
 import { EndpointSelection, SelectOptions } from '@jsplumb/core';
 
 export class JsplumbBridge {
-
-    constructor(private jsPlumbInstance: BrowserJsPlumbInstance) {
-    }
+    constructor(private jsPlumbInstance: BrowserJsPlumbInstance) {}
 
     activateEndpoint(endpointId: string, endpointEnabled: boolean) {
         const endpoint = this.getEndpointById(endpointId);
         endpoint.enabled = endpointEnabled;
     }
 
-    activateEndpointWithType(endpointId: string, endpointEnabled: boolean, endpointType: string) {
+    activateEndpointWithType(
+        endpointId: string,
+        endpointEnabled: boolean,
+        endpointType: string,
+    ) {
         this.activateEndpoint(endpointId, endpointEnabled);
         this.setEndpointType(endpointId, endpointType);
     }
@@ -69,7 +71,7 @@ export class JsplumbBridge {
         return this.jsPlumbInstance.bind(event, fn);
     }
 
-    selectEndpoints(endpoint?): EndpointSelection  {
+    selectEndpoints(endpoint?): EndpointSelection {
         if (endpoint === undefined) {
             return this.jsPlumbInstance.selectEndpoints();
         } else {
@@ -78,11 +80,15 @@ export class JsplumbBridge {
     }
 
     getTargetEndpoint(id: string): EndpointSelection {
-        return this.jsPlumbInstance.selectEndpoints({target: document.getElementById(id)});
+        return this.jsPlumbInstance.selectEndpoints({
+            target: document.getElementById(id),
+        });
     }
 
     getEndpointCount(id: string): number {
-        return this.jsPlumbInstance.selectEndpoints({element: document.getElementById(id)}).length;
+        return this.jsPlumbInstance.selectEndpoints({
+            element: document.getElementById(id),
+        }).length;
     }
 
     detach(connection) {
@@ -93,10 +99,12 @@ export class JsplumbBridge {
         return this.jsPlumbInstance.getConnections(filter);
     }
 
-    addEndpoint(pipelineElementDomId: string,
-                options: any) {
+    addEndpoint(pipelineElementDomId: string, options: any) {
         options.cssClass = 'sp-no-pan';
-        return this.jsPlumbInstance.addEndpoint(document.getElementById(pipelineElementDomId), options);
+        return this.jsPlumbInstance.addEndpoint(
+            document.getElementById(pipelineElementDomId),
+            options,
+        );
     }
 
     connect(connection) {
@@ -104,7 +112,9 @@ export class JsplumbBridge {
     }
 
     removeAllEndpoints(element) {
-        this.jsPlumbInstance.removeAllEndpoints(document.getElementById(element));
+        this.jsPlumbInstance.removeAllEndpoints(
+            document.getElementById(element),
+        );
     }
 
     registerEndpointTypes(typeInfo) {
diff --git a/ui/src/app/editor/services/jsplumb-config.service.ts b/ui/src/app/editor/services/jsplumb-config.service.ts
index 76d0f38d9..b86a44fcd 100644
--- a/ui/src/app/editor/services/jsplumb-config.service.ts
+++ b/ui/src/app/editor/services/jsplumb-config.service.ts
@@ -22,158 +22,166 @@ import { BezierConnector } from '@jsplumb/connector-bezier';
 import { EndpointTypeDescriptor } from '@jsplumb/core';
 import { ArrowOverlayOptions } from '@jsplumb/common';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class JsplumbConfigService {
-
-  constructor() {
-  }
-
-  getEditorConfig() {
-    return this.makeConfig(this.makeSettings(12, 5, 30, 30, 2, 80));
-  }
-
-  getPreviewConfig() {
-    return this.makeConfig(this.makeSettings(6, 2, 15, 15, 1, 40));
-  }
-
-  getEndpointTypeConfig(): Record<string, EndpointTypeDescriptor> {
-    return {
-      'empty': {
-        paintStyle: {
-          fill: 'white',
-          stroke: '#9E9E9E',
-          strokeWidth: 1,
-        }
-      },
-      'token': {
-        paintStyle: {
-          fill: '#BDBDBD',
-          stroke: '#9E9E9E',
-          strokeWidth: 1
-        },
-        hoverPaintStyle: {
-          fill: '#9E9E9E',
-          stroke: '#9E9E9E',
-          strokeWidth: 2,
-        }
-      },
-      'highlight': {
-        paintStyle: {
-          fill: 'white',
-          stroke: '#4CAF50',
-          strokeWidth: 2
-        }
-      }
-    };
-  }
-
-  getConnectorStyleSuccess() {
-    return {
-      stroke: '#6ab26c',
-      outlineStroke: '#6ab26c',
-      strokeWidth: 5
-    };
-  }
-
-  getConnectorStyleError() {
-    return {
-      stroke: '#b74e4e',
-      outlineStroke: '#b74e4e',
-      strokeWidth: 5
-    };
-  }
-
-  getConnectorStyleWarning() {
-    return {
-      outlineStroke: '#d3c545',
-      stroke: '#d3c545',
-      strokeWidth: 5
-    };
-  }
-
-  getDefaultConnectorStyle(settings) {
-    return {stroke: '#BDBDBD', outlineStroke: '#BDBDBD', strokeWidth: settings.lineWidth};
-  }
-
-  getDefaultConnector(settings) {
-    return {type: BezierConnector.type, options: {curviness: settings.curviness}};
-  }
-
-  getDefaultEndpoint(settings) {
-    return {type: 'Dot', options: {radius: settings.dotRadius}};
-  }
-
-  makeConfig(settings: JsplumbSettings) {
-    const config = {} as any;
-    config.streamEndpointOptions = this.makeStreamEndpointOptions(settings);
-    config.sepaEndpointOptions = this.makeSepaEndpointOptions(settings);
-    config.leftTargetPointOptions = this.makeLeftTargetPointOptions(settings);
-    return config;
-  }
-
-  makeSettings(dotRadius: number,
-               lineWidth: number,
-               arrowWidth: number,
-               arrowLength: number,
-               arrowLineWidth: number,
-               curviness: number) {
-    const settings = {} as JsplumbSettings;
-    settings.dotRadius = dotRadius;
-    settings.lineWidth = lineWidth;
-    settings.arrowWidth = arrowWidth;
-    settings.arrowLength = arrowLength;
-    settings.arrowLineWidth = arrowLineWidth;
-    settings.curviness = curviness;
-    return settings;
-  }
-
-  makeStreamEndpointOptions(settings: JsplumbSettings) {
-    return {
-      ...this.makeDefaultOutputPortOptions(settings),
-      type: 'token',
-    };
-  }
-
-  makeSepaEndpointOptions(settings) {
-    return {
-      ...this.makeDefaultOutputPortOptions(settings),
-      type: 'token',
-      parameters: {
-        endpointType: 'output'
-      }
-    };
-  }
-
-  makeDefaultOutputPortOptions(settings) {
-    return {
-      endpoint: this.getDefaultEndpoint(settings),
-      connectorStyle: this.getDefaultConnectorStyle(settings),
-      connector: this.getDefaultConnector(settings),
-      source: true,
-      maxConnections: -1,
-      anchor: 'Right',
-      connectorOverlays: [this.defaultConnectorOverlay(settings)],
-    };
-  }
-
-  makeLeftTargetPointOptions(settings) {
-    return {
-      endpoint: {type: 'Dot', options: {radius: settings.dotRadius}},
-      type: 'empty',
-      anchor: 'Left',
-      target: true
-    };
-  }
-
-  defaultConnectorOverlay(settings): ArrowOverlayOptions {
-    return {
-      type: 'Arrow', options: {
-        width: settings.arrowWidth,
-        length: settings.arrowLength,
-        location: 0.5,
-        id: 'arrow'
-      }
-    };
-  }
-
+    constructor() {}
+
+    getEditorConfig() {
+        return this.makeConfig(this.makeSettings(12, 5, 30, 30, 2, 80));
+    }
+
+    getPreviewConfig() {
+        return this.makeConfig(this.makeSettings(6, 2, 15, 15, 1, 40));
+    }
+
+    getEndpointTypeConfig(): Record<string, EndpointTypeDescriptor> {
+        return {
+            empty: {
+                paintStyle: {
+                    fill: 'white',
+                    stroke: '#9E9E9E',
+                    strokeWidth: 1,
+                },
+            },
+            token: {
+                paintStyle: {
+                    fill: '#BDBDBD',
+                    stroke: '#9E9E9E',
+                    strokeWidth: 1,
+                },
+                hoverPaintStyle: {
+                    fill: '#9E9E9E',
+                    stroke: '#9E9E9E',
+                    strokeWidth: 2,
+                },
+            },
+            highlight: {
+                paintStyle: {
+                    fill: 'white',
+                    stroke: '#4CAF50',
+                    strokeWidth: 2,
+                },
+            },
+        };
+    }
+
+    getConnectorStyleSuccess() {
+        return {
+            stroke: '#6ab26c',
+            outlineStroke: '#6ab26c',
+            strokeWidth: 5,
+        };
+    }
+
+    getConnectorStyleError() {
+        return {
+            stroke: '#b74e4e',
+            outlineStroke: '#b74e4e',
+            strokeWidth: 5,
+        };
+    }
+
+    getConnectorStyleWarning() {
+        return {
+            outlineStroke: '#d3c545',
+            stroke: '#d3c545',
+            strokeWidth: 5,
+        };
+    }
+
+    getDefaultConnectorStyle(settings) {
+        return {
+            stroke: '#BDBDBD',
+            outlineStroke: '#BDBDBD',
+            strokeWidth: settings.lineWidth,
+        };
+    }
+
+    getDefaultConnector(settings) {
+        return {
+            type: BezierConnector.type,
+            options: { curviness: settings.curviness },
+        };
+    }
+
+    getDefaultEndpoint(settings) {
+        return { type: 'Dot', options: { radius: settings.dotRadius } };
+    }
+
+    makeConfig(settings: JsplumbSettings) {
+        const config = {} as any;
+        config.streamEndpointOptions = this.makeStreamEndpointOptions(settings);
+        config.sepaEndpointOptions = this.makeSepaEndpointOptions(settings);
+        config.leftTargetPointOptions =
+            this.makeLeftTargetPointOptions(settings);
+        return config;
+    }
+
+    makeSettings(
+        dotRadius: number,
+        lineWidth: number,
+        arrowWidth: number,
+        arrowLength: number,
+        arrowLineWidth: number,
+        curviness: number,
+    ) {
+        const settings = {} as JsplumbSettings;
+        settings.dotRadius = dotRadius;
+        settings.lineWidth = lineWidth;
+        settings.arrowWidth = arrowWidth;
+        settings.arrowLength = arrowLength;
+        settings.arrowLineWidth = arrowLineWidth;
+        settings.curviness = curviness;
+        return settings;
+    }
+
+    makeStreamEndpointOptions(settings: JsplumbSettings) {
+        return {
+            ...this.makeDefaultOutputPortOptions(settings),
+            type: 'token',
+        };
+    }
+
+    makeSepaEndpointOptions(settings) {
+        return {
+            ...this.makeDefaultOutputPortOptions(settings),
+            type: 'token',
+            parameters: {
+                endpointType: 'output',
+            },
+        };
+    }
+
+    makeDefaultOutputPortOptions(settings) {
+        return {
+            endpoint: this.getDefaultEndpoint(settings),
+            connectorStyle: this.getDefaultConnectorStyle(settings),
+            connector: this.getDefaultConnector(settings),
+            source: true,
+            maxConnections: -1,
+            anchor: 'Right',
+            connectorOverlays: [this.defaultConnectorOverlay(settings)],
+        };
+    }
+
+    makeLeftTargetPointOptions(settings) {
+        return {
+            endpoint: { type: 'Dot', options: { radius: settings.dotRadius } },
+            type: 'empty',
+            anchor: 'Left',
+            target: true,
+        };
+    }
+
+    defaultConnectorOverlay(settings): ArrowOverlayOptions {
+        return {
+            type: 'Arrow',
+            options: {
+                width: settings.arrowWidth,
+                length: settings.arrowLength,
+                location: 0.5,
+                id: 'arrow',
+            },
+        };
+    }
 }
diff --git a/ui/src/app/editor/services/jsplumb-endpoint.service.ts b/ui/src/app/editor/services/jsplumb-endpoint.service.ts
index e9786dd8c..01b3ac574 100644
--- a/ui/src/app/editor/services/jsplumb-endpoint.service.ts
+++ b/ui/src/app/editor/services/jsplumb-endpoint.service.ts
@@ -19,45 +19,47 @@
 import { Injectable } from '@angular/core';
 import { JsplumbConfigService } from './jsplumb-config.service';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class JsplumbEndpointService {
+    constructor(private jsplumbConfigService: JsplumbConfigService) {}
 
-  constructor(private jsplumbConfigService: JsplumbConfigService) {
-
-  }
-
-  getJsplumbConfig(preview): any {
-    return preview ? this.jsplumbConfigService.getPreviewConfig() : this.jsplumbConfigService.getEditorConfig();
-  }
-
-  getStreamEndpoint(preview: boolean,
-                    pipelineElementDomId: string) {
-    const jsplumbConfig = this.getJsplumbConfig(preview);
-    const config = jsplumbConfig.streamEndpointOptions;
-    config.uuid = 'out-' + pipelineElementDomId;
-    return config;
-  }
-
-  getInputEndpoint(preview, pipelineElementDomId, index): any {
-    const jsplumbConfig = this.getJsplumbConfig(preview);
-    const inConfig = jsplumbConfig.leftTargetPointOptions;
-    inConfig.uuid = 'in-' + index + '-' + pipelineElementDomId;
-    return inConfig;
-  }
-
-  getOutputEndpoint(preview, pipelineElementDomId): any {
-    const jsplumbConfig = this.getJsplumbConfig(preview);
-    const outConfig = jsplumbConfig.sepaEndpointOptions;
-    outConfig.uuid = 'out-' + pipelineElementDomId;
-    return outConfig;
-  }
-
-  getNewTargetPoint(preview, x, y, pipelineElementDomId, index): any {
-    const inConfig = this.getInputEndpoint(preview, pipelineElementDomId, index);
-    inConfig.type = 'empty';
-    inConfig.anchor = [x, y, -1, 0];
-    inConfig.isTarget = true;
-
-    return inConfig;
-  }
+    getJsplumbConfig(preview): any {
+        return preview
+            ? this.jsplumbConfigService.getPreviewConfig()
+            : this.jsplumbConfigService.getEditorConfig();
+    }
+
+    getStreamEndpoint(preview: boolean, pipelineElementDomId: string) {
+        const jsplumbConfig = this.getJsplumbConfig(preview);
+        const config = jsplumbConfig.streamEndpointOptions;
+        config.uuid = 'out-' + pipelineElementDomId;
+        return config;
+    }
+
+    getInputEndpoint(preview, pipelineElementDomId, index): any {
+        const jsplumbConfig = this.getJsplumbConfig(preview);
+        const inConfig = jsplumbConfig.leftTargetPointOptions;
+        inConfig.uuid = 'in-' + index + '-' + pipelineElementDomId;
+        return inConfig;
+    }
+
+    getOutputEndpoint(preview, pipelineElementDomId): any {
+        const jsplumbConfig = this.getJsplumbConfig(preview);
+        const outConfig = jsplumbConfig.sepaEndpointOptions;
+        outConfig.uuid = 'out-' + pipelineElementDomId;
+        return outConfig;
+    }
+
+    getNewTargetPoint(preview, x, y, pipelineElementDomId, index): any {
+        const inConfig = this.getInputEndpoint(
+            preview,
+            pipelineElementDomId,
+            index,
+        );
+        inConfig.type = 'empty';
+        inConfig.anchor = [x, y, -1, 0];
+        inConfig.isTarget = true;
+
+        return inConfig;
+    }
 }
diff --git a/ui/src/app/editor/services/jsplumb-factory.service.ts b/ui/src/app/editor/services/jsplumb-factory.service.ts
index a895e7215..a7bbef390 100644
--- a/ui/src/app/editor/services/jsplumb-factory.service.ts
+++ b/ui/src/app/editor/services/jsplumb-factory.service.ts
@@ -19,36 +19,45 @@
 import { JsPlumbInstance } from '@jsplumb/core';
 import { JsplumbBridge } from './jsplumb-bridge.service';
 import { Injectable } from '@angular/core';
-import { BrowserJsPlumbInstance, ContainmentType, newInstance } from '@jsplumb/browser-ui';
+import {
+    BrowserJsPlumbInstance,
+    ContainmentType,
+    newInstance,
+} from '@jsplumb/browser-ui';
 import { PipelineElementDraggedService } from './pipeline-element-dragged.service';
 import { JsplumbConfigService } from './jsplumb-config.service';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class JsplumbFactoryService {
-
     pipelineEditorInstance: BrowserJsPlumbInstance;
     pipelinePreviewInstance: BrowserJsPlumbInstance;
 
     pipelineEditorBridge: JsplumbBridge;
     pipelinePreviewBridge: JsplumbBridge;
 
-    constructor(private pipelineElementDraggedService: PipelineElementDraggedService,
-                private jsplumbConfigService: JsplumbConfigService) {
-    }
+    constructor(
+        private pipelineElementDraggedService: PipelineElementDraggedService,
+        private jsplumbConfigService: JsplumbConfigService,
+    ) {}
 
     getJsplumbBridge(previewConfig: boolean): JsplumbBridge {
         if (!previewConfig) {
             if (!this.pipelineEditorBridge) {
                 this.pipelineEditorInstance = this.makePipelineEditorInstance();
                 this.prepareJsplumb(this.pipelineEditorInstance);
-                this.pipelineEditorBridge = new JsplumbBridge(this.pipelineEditorInstance);
+                this.pipelineEditorBridge = new JsplumbBridge(
+                    this.pipelineEditorInstance,
+                );
             }
             return this.pipelineEditorBridge;
         } else {
             if (!this.pipelinePreviewBridge) {
-                this.pipelinePreviewInstance = this.makePipelinePreviewInstance();
+                this.pipelinePreviewInstance =
+                    this.makePipelinePreviewInstance();
                 this.prepareJsplumb(this.pipelinePreviewInstance);
-                this.pipelinePreviewBridge = new JsplumbBridge(this.pipelinePreviewInstance);
+                this.pipelinePreviewBridge = new JsplumbBridge(
+                    this.pipelinePreviewInstance,
+                );
             }
             return this.pipelinePreviewBridge;
         }
@@ -56,13 +65,17 @@ export class JsplumbFactoryService {
 
     makePipelineEditorInstance(): BrowserJsPlumbInstance {
         return newInstance({
-            container: document.getElementById('assembly'), dragOptions: {
+            container: document.getElementById('assembly'),
+            dragOptions: {
                 containment: ContainmentType.parent,
                 cursor: 'pointer',
                 zIndex: 2000,
                 drag: params => {
-                    this.pipelineElementDraggedService.notify({x: params.pos.x, y: params.pos.y});
-                }
+                    this.pipelineElementDraggedService.notify({
+                        x: params.pos.x,
+                        y: params.pos.y,
+                    });
+                },
             },
         });
     }
@@ -70,12 +83,14 @@ export class JsplumbFactoryService {
     makePipelinePreviewInstance(): BrowserJsPlumbInstance {
         return newInstance({
             container: document.getElementById('assembly-preview'),
-            elementsDraggable: false
+            elementsDraggable: false,
         });
     }
 
     prepareJsplumb(jsplumbInstance: JsPlumbInstance) {
-        jsplumbInstance.registerEndpointTypes(this.jsplumbConfigService.getEndpointTypeConfig());
+        jsplumbInstance.registerEndpointTypes(
+            this.jsplumbConfigService.getEndpointTypeConfig(),
+        );
     }
 
     destroy(preview: boolean) {
diff --git a/ui/src/app/editor/services/jsplumb.service.ts b/ui/src/app/editor/services/jsplumb.service.ts
index 127d608f8..719436d07 100644
--- a/ui/src/app/editor/services/jsplumb.service.ts
+++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -20,300 +20,485 @@ import { JsplumbConfigService } from './jsplumb-config.service';
 import { JsplumbBridge } from './jsplumb-bridge.service';
 import { Injectable } from '@angular/core';
 import {
-  InvocablePipelineElementUnion,
-  PipelineElementConfig,
-  PipelineElementConfigurationStatus,
-  PipelineElementUnion
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+    PipelineElementConfigurationStatus,
+    PipelineElementUnion,
 } from '../model/editor.model';
 import { PipelineElementTypeUtils } from '../utils/editor.utils';
 import {
-  DataProcessorInvocation,
-  DataSinkInvocation,
-  Pipeline,
-  SpDataSet,
-  SpDataStream,
-  SpDataStreamUnion
+    DataProcessorInvocation,
+    DataSinkInvocation,
+    Pipeline,
+    SpDataSet,
+    SpDataStream,
+    SpDataStreamUnion,
 } from '@streampipes/platform-services';
 import { JsplumbEndpointService } from './jsplumb-endpoint.service';
 import { JsplumbFactoryService } from './jsplumb-factory.service';
 import { EditorService } from './editor.service';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class JsplumbService {
+    idCounter = 0;
+
+    constructor(
+        private jsplumbConfigService: JsplumbConfigService,
+        private jsplumbFactory: JsplumbFactoryService,
+        private jsplumbEndpointService: JsplumbEndpointService,
+        private editorService: EditorService,
+    ) {}
+
+    isFullyConnected(
+        pipelineElementConfig: PipelineElementConfig,
+        previewConfig: boolean,
+    ) {
+        const jsplumbBridge =
+            this.jsplumbFactory.getJsplumbBridge(previewConfig);
+        const payload =
+            pipelineElementConfig.payload as InvocablePipelineElementUnion;
+        return (
+            payload.inputStreams == null ||
+            jsplumbBridge.getConnections({
+                target: document.getElementById(payload.dom),
+            }).length == payload.inputStreams.length
+        );
+    }
 
-  idCounter = 0;
-
-  constructor(private jsplumbConfigService: JsplumbConfigService,
-              private jsplumbFactory: JsplumbFactoryService,
-              private jsplumbEndpointService: JsplumbEndpointService,
-              private editorService: EditorService) {
-  }
-
-  isFullyConnected(pipelineElementConfig: PipelineElementConfig,
-                   previewConfig: boolean) {
-    const jsplumbBridge = this.jsplumbFactory.getJsplumbBridge(previewConfig);
-    const payload = pipelineElementConfig.payload as InvocablePipelineElementUnion;
-    return payload.inputStreams == null ||
-      jsplumbBridge.getConnections({target: document.getElementById(payload.dom)}).length == payload.inputStreams.length;
-  }
-
-  makeRawPipeline(pipelineModel: Pipeline,
-                  isPreview: boolean) {
-    return pipelineModel
-      .streams
-      .map(s => this.toConfig(s, 'stream', isPreview))
-      .concat(pipelineModel.sepas.map(s => this.toConfig(s, 'sepa', isPreview)))
-      .concat(pipelineModel.actions.map(s => this.toConfig(s, 'action', isPreview)));
-  }
-
-  toConfig(pe: PipelineElementUnion,
-           type: string,
-           isPreview: boolean) {
-    (pe as any).type = type;
-    return this.createNewPipelineElementConfig(pe, {x: 100, y: 100}, isPreview, true);
-  }
-
-  createElementWithoutConnection(pipelineModel: PipelineElementConfig[],
-                                 pipelineElement: PipelineElementUnion,
-                                 x: number,
-                                 y: number) {
-    const pipelineElementConfig = this.createNewPipelineElementConfigAtPosition(x, y, pipelineElement, false);
-    pipelineModel.push(pipelineElementConfig);
-
-    if (pipelineElementConfig.payload instanceof SpDataSet) {
-      this.editorService.updateDataSet(pipelineElement).subscribe(data => {
-        (pipelineElementConfig.payload as SpDataSet).eventGrounding = data.eventGrounding;
-        (pipelineElementConfig.payload as SpDataSet).datasetInvocationId = data.invocationId;
+    makeRawPipeline(pipelineModel: Pipeline, isPreview: boolean) {
+        return pipelineModel.streams
+            .map(s => this.toConfig(s, 'stream', isPreview))
+            .concat(
+                pipelineModel.sepas.map(s =>
+                    this.toConfig(s, 'sepa', isPreview),
+                ),
+            )
+            .concat(
+                pipelineModel.actions.map(s =>
+                    this.toConfig(s, 'action', isPreview),
+                ),
+            );
+    }
 
-        setTimeout(() => {
-          this.elementDropped(pipelineElementConfig.payload.dom,
-            pipelineElementConfig.payload,
+    toConfig(pe: PipelineElementUnion, type: string, isPreview: boolean) {
+        (pe as any).type = type;
+        return this.createNewPipelineElementConfig(
+            pe,
+            { x: 100, y: 100 },
+            isPreview,
             true,
-            false);
-        }, 1);
-      });
-    } else {
-      setTimeout(() => {
-        this.elementDropped(pipelineElementConfig.payload.dom,
-          pipelineElementConfig.payload,
-          true,
-          false);
-        this.getBridge(false).repaintEverything();
-      }, 10);
+        );
     }
 
-  }
+    createElementWithoutConnection(
+        pipelineModel: PipelineElementConfig[],
+        pipelineElement: PipelineElementUnion,
+        x: number,
+        y: number,
+    ) {
+        const pipelineElementConfig =
+            this.createNewPipelineElementConfigAtPosition(
+                x,
+                y,
+                pipelineElement,
+                false,
+            );
+        pipelineModel.push(pipelineElementConfig);
+
+        if (pipelineElementConfig.payload instanceof SpDataSet) {
+            this.editorService
+                .updateDataSet(pipelineElement)
+                .subscribe(data => {
+                    (
+                        pipelineElementConfig.payload as SpDataSet
+                    ).eventGrounding = data.eventGrounding;
+                    (
+                        pipelineElementConfig.payload as SpDataSet
+                    ).datasetInvocationId = data.invocationId;
+
+                    setTimeout(() => {
+                        this.elementDropped(
+                            pipelineElementConfig.payload.dom,
+                            pipelineElementConfig.payload,
+                            true,
+                            false,
+                        );
+                    }, 1);
+                });
+        } else {
+            setTimeout(() => {
+                this.elementDropped(
+                    pipelineElementConfig.payload.dom,
+                    pipelineElementConfig.payload,
+                    true,
+                    false,
+                );
+                this.getBridge(false).repaintEverything();
+            }, 10);
+        }
+    }
 
-  createElement(pipelineModel: PipelineElementConfig[],
-                pipelineElement: InvocablePipelineElementUnion,
-                sourceElementDomId: string) {
-    const sourceElement = $('#' + sourceElementDomId);
+    createElement(
+        pipelineModel: PipelineElementConfig[],
+        pipelineElement: InvocablePipelineElementUnion,
+        sourceElementDomId: string,
+    ) {
+        const sourceElement = $('#' + sourceElementDomId);
+
+        const pipelineElementConfig =
+            this.createNewPipelineElementConfigWithFixedCoordinates(
+                sourceElement,
+                pipelineElement,
+                false,
+            );
+        pipelineModel.push(pipelineElementConfig);
+        setTimeout(() => {
+            this.createAssemblyElement(
+                pipelineElementConfig.payload.dom,
+                pipelineElementConfig.payload as InvocablePipelineElementUnion,
+                sourceElement,
+                false,
+            );
+        });
+    }
 
-    const pipelineElementConfig = this.createNewPipelineElementConfigWithFixedCoordinates(sourceElement, pipelineElement, false);
-    pipelineModel.push(pipelineElementConfig);
-    setTimeout(() => {
-      this.createAssemblyElement(pipelineElementConfig.payload.dom,
-        pipelineElementConfig.payload as InvocablePipelineElementUnion,
+    createAssemblyElement(
+        pipelineElementDomId: string,
+        pipelineElement: InvocablePipelineElementUnion,
         sourceElement,
-        false);
-    });
-  }
-
-  createAssemblyElement(pipelineElementDomId: string,
-                        pipelineElement: InvocablePipelineElementUnion,
-                        sourceElement,
-                        previewConfig: boolean) {
-    let targetElementId;
-    if (pipelineElement instanceof DataProcessorInvocation) {
-      targetElementId = this.dataProcessorDropped(pipelineElementDomId, pipelineElement as DataProcessorInvocation, true, false);
-      this.connectNodes(sourceElement, targetElementId, previewConfig);
-    } else {
-      targetElementId = this.dataSinkDropped(pipelineElementDomId, pipelineElement, true, false);
-      this.connectNodes(sourceElement, targetElementId, previewConfig);
+        previewConfig: boolean,
+    ) {
+        let targetElementId;
+        if (pipelineElement instanceof DataProcessorInvocation) {
+            targetElementId = this.dataProcessorDropped(
+                pipelineElementDomId,
+                pipelineElement as DataProcessorInvocation,
+                true,
+                false,
+            );
+            this.connectNodes(sourceElement, targetElementId, previewConfig);
+        } else {
+            targetElementId = this.dataSinkDropped(
+                pipelineElementDomId,
+                pipelineElement,
+                true,
+                false,
+            );
+            this.connectNodes(sourceElement, targetElementId, previewConfig);
+        }
     }
-  }
-
-  connectNodes(sourceElementSelector,
-               targetElementId,
-               previewConfig: boolean) {
-    let options;
-    const sourceElement = sourceElementSelector.get()[0];
-    const jsplumbBridge = this.getBridge(previewConfig);
-    const jsplumbConfig = this.jsplumbEndpointService.getJsplumbConfig(true);
-    options = sourceElementSelector.hasClass('stream') ?
-      jsplumbConfig.streamEndpointOptions : jsplumbConfig.sepaEndpointOptions;
-    let sourceEndPoint;
-    const selectedEndpoints = jsplumbBridge.selectEndpoints({source: sourceElement});
-    sourceEndPoint = selectedEndpoints.length > 0 ? !(selectedEndpoints.get(0).isFull()) ?
-        jsplumbBridge.selectEndpoints({source: sourceElement}).get(0) :
-        jsplumbBridge.addEndpoint(sourceElement, options) : jsplumbBridge.addEndpoint(sourceElement, options);
-
-    const targetElement = document.getElementById(targetElementId);
-    const targetEndPoint = jsplumbBridge.selectEndpoints({target: targetElement}).get(0);
 
-    jsplumbBridge.connect({source: sourceEndPoint, target: targetEndPoint, detachable: true});
-    jsplumbBridge.repaintEverything();
-  }
+    connectNodes(
+        sourceElementSelector,
+        targetElementId,
+        previewConfig: boolean,
+    ) {
+        let options;
+        const sourceElement = sourceElementSelector.get()[0];
+        const jsplumbBridge = this.getBridge(previewConfig);
+        const jsplumbConfig =
+            this.jsplumbEndpointService.getJsplumbConfig(true);
+        options = sourceElementSelector.hasClass('stream')
+            ? jsplumbConfig.streamEndpointOptions
+            : jsplumbConfig.sepaEndpointOptions;
+        let sourceEndPoint;
+        const selectedEndpoints = jsplumbBridge.selectEndpoints({
+            source: sourceElement,
+        });
+        sourceEndPoint =
+            selectedEndpoints.length > 0
+                ? !selectedEndpoints.get(0).isFull()
+                    ? jsplumbBridge
+                          .selectEndpoints({ source: sourceElement })
+                          .get(0)
+                    : jsplumbBridge.addEndpoint(sourceElement, options)
+                : jsplumbBridge.addEndpoint(sourceElement, options);
+
+        const targetElement = document.getElementById(targetElementId);
+        const targetEndPoint = jsplumbBridge
+            .selectEndpoints({ target: targetElement })
+            .get(0);
+
+        jsplumbBridge.connect({
+            source: sourceEndPoint,
+            target: targetEndPoint,
+            detachable: true,
+        });
+        jsplumbBridge.repaintEverything();
+    }
 
-  createNewPipelineElementConfigWithFixedCoordinates(sourceElement,
-                                                     pipelineElement: InvocablePipelineElementUnion,
-                                                     isPreview): PipelineElementConfig {
-    const x = sourceElement.position().left;
-    const y = sourceElement.position().top;
-    return this.createNewPipelineElementConfigAtPosition(x, y, pipelineElement, isPreview);
-  }
+    createNewPipelineElementConfigWithFixedCoordinates(
+        sourceElement,
+        pipelineElement: InvocablePipelineElementUnion,
+        isPreview,
+    ): PipelineElementConfig {
+        const x = sourceElement.position().left;
+        const y = sourceElement.position().top;
+        return this.createNewPipelineElementConfigAtPosition(
+            x,
+            y,
+            pipelineElement,
+            isPreview,
+        );
+    }
 
-  createNewPipelineElementConfigAtPosition(x: number,
-                                           y: number,
-                                           json: any,
-                                           isPreview: boolean): PipelineElementConfig {
-    const coord = {'x': x + 200, 'y': y};
-    return this.createNewPipelineElementConfig(json, coord, isPreview, false);
-  }
+    createNewPipelineElementConfigAtPosition(
+        x: number,
+        y: number,
+        json: any,
+        isPreview: boolean,
+    ): PipelineElementConfig {
+        const coord = { x: x + 200, y: y };
+        return this.createNewPipelineElementConfig(
+            json,
+            coord,
+            isPreview,
+            false,
+        );
+    }
 
-  createNewPipelineElementConfig(pipelineElement: PipelineElementUnion,
-                                 coordinates,
-                                 isPreview: boolean,
-                                 isCompleted: boolean,
-                                 newElementId?: string): PipelineElementConfig {
-    const displaySettings = isPreview ? 'connectable-preview' : 'connectable-editor';
-    const connectable = 'connectable';
-    const pipelineElementConfig = {} as PipelineElementConfig;
-    pipelineElementConfig.type = PipelineElementTypeUtils
-      .toCssShortHand(PipelineElementTypeUtils.fromType(pipelineElement));
-    pipelineElementConfig.payload = this.clone(pipelineElement, newElementId);
-    pipelineElementConfig.settings = {
-      connectable,
-      openCustomize: !(pipelineElement as any).configured,
-      preview: isPreview,
-      completed: (pipelineElement instanceof SpDataStream || pipelineElement instanceof SpDataSet ||
-          isPreview || isCompleted) ? PipelineElementConfigurationStatus.OK : PipelineElementConfigurationStatus.INCOMPLETE,
-      disabled: false,
-      loadingStatus: false,
-      displaySettings,
-      position: {
-        x: coordinates.x,
-        y: coordinates.y
-      }
-    };
-    if (!pipelineElementConfig.payload.dom) {
-      pipelineElementConfig.payload.dom = 'jsplumb_' + this.idCounter + '_' + this.makeId(4);
-      this.idCounter++;
+    createNewPipelineElementConfig(
+        pipelineElement: PipelineElementUnion,
+        coordinates,
+        isPreview: boolean,
+        isCompleted: boolean,
+        newElementId?: string,
+    ): PipelineElementConfig {
+        const displaySettings = isPreview
+            ? 'connectable-preview'
+            : 'connectable-editor';
+        const connectable = 'connectable';
+        const pipelineElementConfig = {} as PipelineElementConfig;
+        pipelineElementConfig.type = PipelineElementTypeUtils.toCssShortHand(
+            PipelineElementTypeUtils.fromType(pipelineElement),
+        );
+        pipelineElementConfig.payload = this.clone(
+            pipelineElement,
+            newElementId,
+        );
+        pipelineElementConfig.settings = {
+            connectable,
+            openCustomize: !(pipelineElement as any).configured,
+            preview: isPreview,
+            completed:
+                pipelineElement instanceof SpDataStream ||
+                pipelineElement instanceof SpDataSet ||
+                isPreview ||
+                isCompleted
+                    ? PipelineElementConfigurationStatus.OK
+                    : PipelineElementConfigurationStatus.INCOMPLETE,
+            disabled: false,
+            loadingStatus: false,
+            displaySettings,
+            position: {
+                x: coordinates.x,
+                y: coordinates.y,
+            },
+        };
+        if (!pipelineElementConfig.payload.dom) {
+            pipelineElementConfig.payload.dom =
+                'jsplumb_' + this.idCounter + '_' + this.makeId(4);
+            this.idCounter++;
+        }
+
+        return pipelineElementConfig;
     }
 
-    return pipelineElementConfig;
-  }
+    clone(pipelineElement: PipelineElementUnion, newElementId?: string) {
+        if (pipelineElement instanceof SpDataSet) {
+            return SpDataSet.fromData(pipelineElement, new SpDataSet());
+        } else if (pipelineElement instanceof SpDataStream) {
+            const cloned = SpDataStream.fromData(
+                pipelineElement,
+                new SpDataStream(),
+            );
+            return cloned;
+        } else if (pipelineElement instanceof DataProcessorInvocation) {
+            const clonedPe = DataProcessorInvocation.fromData(
+                pipelineElement,
+                new DataProcessorInvocation(),
+            );
+            if (newElementId) {
+                this.updateElementIds(clonedPe, newElementId);
+            }
+            return clonedPe;
+        } else if (pipelineElement instanceof DataSinkInvocation) {
+            const clonedPe = DataSinkInvocation.fromData(
+                pipelineElement as DataSinkInvocation,
+                new DataSinkInvocation(),
+            );
+            if (newElementId) {
+                this.updateElementIds(clonedPe, newElementId);
+            }
+            return clonedPe;
+        }
+    }
 
-  clone(pipelineElement: PipelineElementUnion, newElementId?: string) {
-    if (pipelineElement instanceof SpDataSet) {
-      return SpDataSet.fromData(pipelineElement, new SpDataSet());
-    } else if (pipelineElement instanceof SpDataStream) {
-      const cloned = SpDataStream.fromData(pipelineElement, new SpDataStream());
-      return cloned;
-    } else if (pipelineElement instanceof DataProcessorInvocation) {
-      const clonedPe = DataProcessorInvocation.fromData(pipelineElement, new DataProcessorInvocation());
-      if (newElementId) {
-        this.updateElementIds(clonedPe, newElementId);
-      }
-      return clonedPe;
-    } else if (pipelineElement instanceof DataSinkInvocation) {
-      const clonedPe = DataSinkInvocation.fromData(pipelineElement as DataSinkInvocation, new DataSinkInvocation());
-      if (newElementId) {
-        this.updateElementIds(clonedPe, newElementId);
-      }
-      return clonedPe;
+    updateElementIds(
+        pipelineElement: PipelineElementUnion,
+        newElementId: string,
+    ) {
+        pipelineElement.elementId = newElementId;
+        pipelineElement.uri = newElementId;
     }
-  }
 
-  updateElementIds(pipelineElement: PipelineElementUnion, newElementId: string) {
-    pipelineElement.elementId = newElementId;
-    pipelineElement.uri = newElementId;
-  }
+    makeId(count: number) {
+        let text = '';
+        const possible =
+            'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 
-  makeId(count: number) {
-    let text = '';
-    const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+        for (let i = 0; i < count; i++) {
+            text += possible.charAt(
+                Math.floor(Math.random() * possible.length),
+            );
+        }
 
-    for (let i = 0; i < count; i++) {
-      text += possible.charAt(Math.floor(Math.random() * possible.length));
+        return text;
     }
 
-    return text;
-  }
-
-  elementDropped(pipelineElementDomId: string,
-                 pipelineElement: PipelineElementUnion,
-                 endpoints: boolean,
-                 preview: boolean): string {
-    if (pipelineElement instanceof SpDataStream) {
-      return this.dataStreamDropped(pipelineElementDomId, pipelineElement as SpDataStream, endpoints, preview);
-    } else if (pipelineElement instanceof SpDataSet) {
-      return this.dataSetDropped(pipelineElementDomId, pipelineElement as SpDataSet, endpoints, preview);
-    } else if (pipelineElement instanceof DataProcessorInvocation) {
-      return this.dataProcessorDropped(pipelineElementDomId, pipelineElement, endpoints, preview);
-    } else if (pipelineElement instanceof DataSinkInvocation) {
-      return this.dataSinkDropped(pipelineElementDomId, pipelineElement, endpoints, preview);
+    elementDropped(
+        pipelineElementDomId: string,
+        pipelineElement: PipelineElementUnion,
+        endpoints: boolean,
+        preview: boolean,
+    ): string {
+        if (pipelineElement instanceof SpDataStream) {
+            return this.dataStreamDropped(
+                pipelineElementDomId,
+                pipelineElement as SpDataStream,
+                endpoints,
+                preview,
+            );
+        } else if (pipelineElement instanceof SpDataSet) {
+            return this.dataSetDropped(
+                pipelineElementDomId,
+                pipelineElement as SpDataSet,
+                endpoints,
+                preview,
+            );
+        } else if (pipelineElement instanceof DataProcessorInvocation) {
+            return this.dataProcessorDropped(
+                pipelineElementDomId,
+                pipelineElement,
+                endpoints,
+                preview,
+            );
+        } else if (pipelineElement instanceof DataSinkInvocation) {
+            return this.dataSinkDropped(
+                pipelineElementDomId,
+                pipelineElement,
+                endpoints,
+                preview,
+            );
+        }
     }
-  }
 
-  dataSetDropped(pipelineElementDomId: string,
-                 pipelineElement: SpDataSet,
-                 endpoints: boolean,
-                 preview: boolean) {
-    const jsplumbBridge = this.getBridge(preview);
-    if (endpoints) {
-      const endpointOptions = this.jsplumbEndpointService.getStreamEndpoint(preview, pipelineElementDomId);
-      jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
+    dataSetDropped(
+        pipelineElementDomId: string,
+        pipelineElement: SpDataSet,
+        endpoints: boolean,
+        preview: boolean,
+    ) {
+        const jsplumbBridge = this.getBridge(preview);
+        if (endpoints) {
+            const endpointOptions =
+                this.jsplumbEndpointService.getStreamEndpoint(
+                    preview,
+                    pipelineElementDomId,
+                );
+            jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
+        }
+        return pipelineElementDomId;
     }
-    return pipelineElementDomId;
-  }
 
-
-  dataStreamDropped(pipelineElementDomId: string,
-                    pipelineElement: SpDataStreamUnion,
-                    endpoints: boolean,
-                    preview: boolean) {
-    const jsplumbBridge = this.getBridge(preview);
-    if (endpoints) {
-      const endpointOptions = this.jsplumbEndpointService.getStreamEndpoint(preview, pipelineElementDomId);
-      jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
+    dataStreamDropped(
+        pipelineElementDomId: string,
+        pipelineElement: SpDataStreamUnion,
+        endpoints: boolean,
+        preview: boolean,
+    ) {
+        const jsplumbBridge = this.getBridge(preview);
+        if (endpoints) {
+            const endpointOptions =
+                this.jsplumbEndpointService.getStreamEndpoint(
+                    preview,
+                    pipelineElementDomId,
+                );
+            jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
+        }
+        return pipelineElementDomId;
     }
-    return pipelineElementDomId;
-  }
 
-  dataProcessorDropped(pipelineElementDomId: string,
-                       pipelineElement: DataProcessorInvocation,
-                       endpoints: boolean,
-                       preview: boolean): string {
-    const jsplumbBridge = this.getBridge(preview);
-    this.dataSinkDropped(pipelineElementDomId, pipelineElement, endpoints, preview);
-    if (endpoints) {
-      jsplumbBridge.addEndpoint(pipelineElementDomId,
-        this.jsplumbEndpointService.getOutputEndpoint(preview, pipelineElementDomId));
+    dataProcessorDropped(
+        pipelineElementDomId: string,
+        pipelineElement: DataProcessorInvocation,
+        endpoints: boolean,
+        preview: boolean,
+    ): string {
+        const jsplumbBridge = this.getBridge(preview);
+        this.dataSinkDropped(
+            pipelineElementDomId,
+            pipelineElement,
+            endpoints,
+            preview,
+        );
+        if (endpoints) {
+            jsplumbBridge.addEndpoint(
+                pipelineElementDomId,
+                this.jsplumbEndpointService.getOutputEndpoint(
+                    preview,
+                    pipelineElementDomId,
+                ),
+            );
+        }
+        return pipelineElementDomId;
     }
-    return pipelineElementDomId;
-  }
 
-  dataSinkDropped(pipelineElementDomId: string,
-                  pipelineElement: InvocablePipelineElementUnion,
-                  endpoints: boolean,
-                  preview: boolean): string {
-    const jsplumbBridge = this.getBridge(preview);
-    if (endpoints) {
-      if (pipelineElement.inputStreams.length < 2) { // 1 InputNode
-        jsplumbBridge.addEndpoint(pipelineElementDomId,
-          this.jsplumbEndpointService.getInputEndpoint(preview, pipelineElementDomId, 0));
-      } else {
-        jsplumbBridge.addEndpoint(pipelineElementDomId,
-          this.jsplumbEndpointService.getNewTargetPoint(preview, 0, 0.3, pipelineElementDomId, 0));
-        jsplumbBridge.addEndpoint(pipelineElementDomId,
-          this.jsplumbEndpointService.getNewTargetPoint(preview, 0, 0.7, pipelineElementDomId, 1));
-      }
+    dataSinkDropped(
+        pipelineElementDomId: string,
+        pipelineElement: InvocablePipelineElementUnion,
+        endpoints: boolean,
+        preview: boolean,
+    ): string {
+        const jsplumbBridge = this.getBridge(preview);
+        if (endpoints) {
+            if (pipelineElement.inputStreams.length < 2) {
+                // 1 InputNode
+                jsplumbBridge.addEndpoint(
+                    pipelineElementDomId,
+                    this.jsplumbEndpointService.getInputEndpoint(
+                        preview,
+                        pipelineElementDomId,
+                        0,
+                    ),
+                );
+            } else {
+                jsplumbBridge.addEndpoint(
+                    pipelineElementDomId,
+                    this.jsplumbEndpointService.getNewTargetPoint(
+                        preview,
+                        0,
+                        0.3,
+                        pipelineElementDomId,
+                        0,
+                    ),
+                );
+                jsplumbBridge.addEndpoint(
+                    pipelineElementDomId,
+                    this.jsplumbEndpointService.getNewTargetPoint(
+                        preview,
+                        0,
+                        0.7,
+                        pipelineElementDomId,
+                        1,
+                    ),
+                );
+            }
+        }
+        return pipelineElementDomId;
     }
-    return pipelineElementDomId;
-  }
 
-  getBridge(previewConfig: boolean): JsplumbBridge {
-    return this.jsplumbFactory.getJsplumbBridge(previewConfig);
-  }
+    getBridge(previewConfig: boolean): JsplumbBridge {
+        return this.jsplumbFactory.getJsplumbBridge(previewConfig);
+    }
 }
diff --git a/ui/src/app/editor/services/object-provider.service.ts b/ui/src/app/editor/services/object-provider.service.ts
index 95375edaf..0aad0827f 100644
--- a/ui/src/app/editor/services/object-provider.service.ts
+++ b/ui/src/app/editor/services/object-provider.service.ts
@@ -18,18 +18,21 @@
 
 import { Injectable } from '@angular/core';
 import { RestApi } from '../../services/rest-api.service';
-import { InvocablePipelineElementUnion, PipelineElementConfig } from '../model/editor.model';
+import {
+    InvocablePipelineElementUnion,
+    PipelineElementConfig,
+} from '../model/editor.model';
 import { DataSinkInvocation, Pipeline } from '@streampipes/platform-services';
 import { EditorService } from './editor.service';
 import { JsplumbFactoryService } from './jsplumb-factory.service';
 
-@Injectable({providedIn: 'root'})
+@Injectable({ providedIn: 'root' })
 export class ObjectProvider {
-
-    constructor(private restApi: RestApi,
-                private editorService: EditorService,
-                private jsplumbFactoryService: JsplumbFactoryService) {
-    }
+    constructor(
+        private restApi: RestApi,
+        private editorService: EditorService,
+        private jsplumbFactoryService: JsplumbFactoryService,
+    ) {}
 
     prepareElement(pipelineElement: InvocablePipelineElementUnion) {
         pipelineElement.connectedTo = [];
@@ -57,38 +60,65 @@ export class ObjectProvider {
         return pipeline;
     }
 
-    hasConnectedPipelineElement(pipelineElementDomId: string,
-                                rawPipelineModel: PipelineElementConfig[]) {
-        const pipelineElement = this.findElement(pipelineElementDomId, rawPipelineModel);
+    hasConnectedPipelineElement(
+        pipelineElementDomId: string,
+        rawPipelineModel: PipelineElementConfig[],
+    ) {
+        const pipelineElement = this.findElement(
+            pipelineElementDomId,
+            rawPipelineModel,
+        );
         if (pipelineElement.payload instanceof DataSinkInvocation) {
             return false;
         } else {
-            return rawPipelineModel
-                .filter(pe => !pe.settings.disabled && pe.payload.connectedTo)
-                .find(pe => (pe.payload.connectedTo.indexOf(pipelineElementDomId) > -1))
-                !== undefined;
+            return (
+                rawPipelineModel
+                    .filter(
+                        pe => !pe.settings.disabled && pe.payload.connectedTo,
+                    )
+                    .find(
+                        pe =>
+                            pe.payload.connectedTo.indexOf(
+                                pipelineElementDomId,
+                            ) > -1,
+                    ) !== undefined
+            );
         }
     }
 
-    findElement(elementId, rawPipelineModel: PipelineElementConfig[]): PipelineElementConfig {
-        return rawPipelineModel.find(pe => pe.payload.dom === elementId) || {} as PipelineElementConfig;
+    findElement(
+        elementId,
+        rawPipelineModel: PipelineElementConfig[],
+    ): PipelineElementConfig {
+        return (
+            rawPipelineModel.find(pe => pe.payload.dom === elementId) ||
+            ({} as PipelineElementConfig)
+        );
     }
 
-    addElementNew(pipeline, currentPipelineElements: PipelineElementConfig[]): Pipeline {
-        const JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
+    addElementNew(
+        pipeline,
+        currentPipelineElements: PipelineElementConfig[],
+    ): Pipeline {
+        const JsplumbBridge =
+            this.jsplumbFactoryService.getJsplumbBridge(false);
         currentPipelineElements.forEach(pe => {
-            if (pe.settings.disabled === undefined || !(pe.settings.disabled)) {
+            if (pe.settings.disabled === undefined || !pe.settings.disabled) {
                 if (pe.type === 'sepa' || pe.type === 'action') {
                     let payload = pe.payload;
-                    payload = this.prepareElement(payload as InvocablePipelineElementUnion);
+                    payload = this.prepareElement(
+                        payload as InvocablePipelineElementUnion,
+                    );
                     const connections = JsplumbBridge.getConnections({
-                        target: document.getElementById(payload.dom)
+                        target: document.getElementById(payload.dom),
                     });
                     for (let i = 0; i < connections.length; i++) {
                         payload.connectedTo.push(connections[i].sourceId);
                     }
                     if (payload.connectedTo && payload.connectedTo.length > 0) {
-                        pe.type === 'action' ? pipeline.actions.push(payload) : pipeline.sepas.push(payload);
+                        pe.type === 'action'
+                            ? pipeline.actions.push(payload)
+                            : pipeline.sepas.push(payload);
                     }
                 } else {
                     pipeline.streams.push(pe.payload);
diff --git a/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts b/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts
index 764b1f7de..4c6d23db7 100644
--- a/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts
+++ b/ui/src/app/editor/services/pipeline-canvas-scrolling.service.ts
@@ -19,17 +19,16 @@
 import { Injectable } from '@angular/core';
 import { Subject } from 'rxjs';
... 1212 lines suppressed ...