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

[incubator-streampipes] branch STREAMPIPES-494 created (now e939a0e)

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

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


      at e939a0e  [STREAMPIPES-499] Bump Jsplumb dependency and migrate code

This branch includes the following new commits:

     new e939a0e  [STREAMPIPES-499] Bump Jsplumb dependency and migrate code

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[incubator-streampipes] 01/01: [STREAMPIPES-499] Bump Jsplumb dependency and migrate code

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e939a0e54d3624c8a4ec0cf7a3d0538d9da4f400
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Mon Jan 3 22:06:26 2022 +0100

    [STREAMPIPES-499] Bump Jsplumb dependency and migrate code
---
 ui/package.json                                    |   8 +-
 .../pipeline-assembly.component.html               |   6 +-
 .../pipeline-assembly.component.ts                 |  20 +-
 .../pipeline-element-options.component.ts          |  87 +++---
 .../components/pipeline/pipeline.component.html    |  74 ++---
 .../components/pipeline/pipeline.component.ts      | 198 +++++++------
 .../app/editor/services/jsplumb-bridge.service.ts  |  37 ++-
 .../app/editor/services/jsplumb-config.service.ts  |  87 ++++--
 .../app/editor/services/jsplumb-factory.service.ts | 113 ++++----
 ui/src/app/editor/services/jsplumb.service.ts      |  66 ++---
 .../app/editor/services/object-provider.service.ts |  10 +-
 .../services/pipeline-positioning.service.ts       | 305 +++++++++++----------
 .../editor/services/pipeline-validation.service.ts |  26 +-
 ui/src/scss/main.scss                              |   2 +-
 14 files changed, 521 insertions(+), 518 deletions(-)

diff --git a/ui/package.json b/ui/package.json
index 7da712e..da51b0d 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -39,7 +39,12 @@
     "@fortawesome/fontawesome-free": "5.12.1",
     "@ngx-loading-bar/core": "5.1.2",
     "@ngx-loading-bar/http-client": "5.1.2",
-    "@panzoom/panzoom": "^4.3.2",
+    "@jsplumb/core": "^5.3.1",
+    "@jsplumb/browser-ui": "^5.3.1",
+    "@jsplumb/connector-bezier": "^5.3.1",
+    "@jsplumb/util": "^5.3.1",
+    "@jsplumb/common": "^5.3.1",
+    "@panzoom/panzoom": "^4.4.3",
     "@stomp/ng2-stompjs": "7.2.0",
     "@swimlane/ngx-charts": "16.0.0",
     "angular-datatables": "^12.0.2",
@@ -65,7 +70,6 @@
     "jquery": "2.1.3",
     "jquery-ui-dist": "1.12.1",
     "jshint": "^2.13.1",
-    "jsplumb": "^2.15.5",
     "jszip": "3.2.1",
     "konva": "3.2.4",
     "leaflet": "1.6.0",
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 3463fcb..e32b4d1 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
@@ -121,8 +121,7 @@
                     </div>
                 </div>
             </div>
-            <div id="assembly" class="canvas" #assembly>
-                <pipeline #pipelineComponent
+                <pipeline class="canvas jtk-surface" id="assembly" #pipelineComponent
                           [pipelineValid]="pipelineValid"
                           [canvasId]="'assembly'"
                           [rawPipelineModel]="rawPipelineModel"
@@ -132,9 +131,8 @@
                           [pipelineCanvasMetadata]="pipelineCanvasMetadata"
                           [pipelineCacheRunning]="pipelineCacheRunning"
                           (pipelineCachedChanged)="pipelineCached=$event"
-                          (pipelineCacheRunningChanged)="pipelineCacheRunning=$event">
+                          (pipelineCacheRunningChanged)="pipelineCacheRunning=$event" style="position:absolute;">
                 </pipeline>
-            </div>
         </div>
     </div>
 </div>
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 079d03f..9658e17 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
@@ -16,16 +16,7 @@
  *
  */
 
-import {
-    Component,
-    ElementRef,
-    EventEmitter,
-    Input,
-    NgZone,
-    OnInit,
-    Output,
-    ViewChild,
-} from '@angular/core';
+import { Component, ElementRef, EventEmitter, Input, NgZone, OnInit, Output, ViewChild, } from '@angular/core';
 import { JsplumbBridge } from '../../services/jsplumb-bridge.service';
 import { PipelinePositioningService } from '../../services/pipeline-positioning.service';
 import { PipelineValidationService } from '../../services/pipeline-validation.service';
@@ -116,7 +107,6 @@ export class PipelineAssemblyComponent implements OnInit {
     }
 
     ngOnInit(): void {
-        this.JsplumbBridge = this.JsPlumbFactoryService.getJsplumbBridge(false);
         if (this.currentModifiedPipelineId) {
             this.displayPipelineById();
         } else {
@@ -141,23 +131,21 @@ export class PipelineAssemblyComponent implements OnInit {
     }
 
     ngAfterViewInit() {
+        this.JsplumbBridge = this.JsPlumbFactoryService.getJsplumbBridge(this.preview);
         const elem = document.getElementById('assembly');
         this.panzoom = Panzoom(elem, {
             maxScale: 5,
-            excludeClass: 'jtk-draggable',
+            excludeClass: "sp-no-pan",
             canvas: true,
             contain: 'outside'
         });
     }
 
     autoLayout() {
-        this.PipelinePositioningService.layoutGraph('#assembly', 'span[id^=\'jsplumb\']', 110, false);
+        this.PipelinePositioningService.layoutGraph('#assembly', 'div[id^=\'jsplumb\']', 110, false);
         this.JsplumbBridge.repaintEverything();
     }
 
-    toggleSelectMode() {
-    }
-
     zoomOut() {
         this.doZoom(true);
     }
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 9de810a..1d131a0 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
@@ -16,27 +16,23 @@
  *
  */
 
-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 {PipelineElementRecommendationService} from "../../services/pipeline-element-recommendation.service";
-import {ObjectProvider} from "../../services/object-provider.service";
-import {
-  InvocablePipelineElementUnion,
-  PipelineElementConfig,
-  PipelineElementUnion
-} from "../../model/editor.model";
-import {SpDataStream, WildcardTopicDefinition} from "../../../core-model/gen/streampipes-model";
-import {EditorService} from "../../services/editor.service";
-import {PanelType} from "../../../core-ui/dialog/base-dialog/base-dialog.model";
-import {DialogService} from "../../../core-ui/dialog/base-dialog/base-dialog.service";
-import {CompatibleElementsComponent} from "../../dialog/compatible-elements/compatible-elements.component";
-import {Tuple2} from "../../../core-model/base/Tuple2";
-import { cloneDeep } from "lodash";
-import {Observable, Subscription} from "rxjs";
-import {JsplumbFactoryService} from "../../services/jsplumb-factory.service";
+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 { PipelineElementRecommendationService } from '../../services/pipeline-element-recommendation.service';
+import { ObjectProvider } from '../../services/object-provider.service';
+import { InvocablePipelineElementUnion, PipelineElementConfig, PipelineElementUnion } from '../../model/editor.model';
+import { SpDataStream, WildcardTopicDefinition } from '../../../core-model/gen/streampipes-model';
+import { EditorService } from '../../services/editor.service';
+import { PanelType } from '../../../core-ui/dialog/base-dialog/base-dialog.model';
+import { DialogService } from '../../../core-ui/dialog/base-dialog/base-dialog.service';
+import { CompatibleElementsComponent } from '../../dialog/compatible-elements/compatible-elements.component';
+import { Tuple2 } from '../../../core-model/base/Tuple2';
+import { cloneDeep } from 'lodash';
+import { Subscription } from 'rxjs';
+import { JsplumbFactoryService } from '../../services/jsplumb-factory.service';
 
 @Component({
   selector: 'pipeline-element-options',
@@ -83,25 +79,25 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
 
   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) {
+  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);
+    this.JsplumbBridge = this.jsplumbFactoryService.getJsplumbBridge(false);
   }
 
   ngOnInit() {
-    this.pipelineElementConfiguredObservable = this.EditorService.pipelineElementConfigured$.subscribe(pipelineElementDomId => {
+    this.pipelineElementConfiguredObservable = this.editorService.pipelineElementConfigured$.subscribe(pipelineElementDomId => {
       this.pipelineElement.settings.openCustomize = false;
-      this.RestApi.updateCachedPipeline(this.rawPipelineModel);
+      this.restApi.updateCachedPipeline(this.rawPipelineModel);
       if (pipelineElementDomId === this.pipelineElement.payload.dom) {
         this.initRecs(this.pipelineElement.payload.dom);
       }
@@ -120,39 +116,39 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
   }
 
   customizeElement(pipelineElement: PipelineElementConfig) {
-    let restrictedEditMode = ! (this.isRootElement());
-    let customizeInfo = {a: restrictedEditMode, b: pipelineElement} as Tuple2<Boolean, PipelineElementConfig>;
+    const restrictedEditMode = ! (this.isRootElement());
+    const customizeInfo = {a: restrictedEditMode, b: pipelineElement} as Tuple2<Boolean, PipelineElementConfig>;
     this.customize.emit(customizeInfo);
   }
 
   openHelpDialog() {
-    this.EditorService.openHelpDialog(this.pipelineElement.payload);
+    this.editorService.openHelpDialog(this.pipelineElement.payload);
   }
 
   openCustomizeStreamDialog() {
-    //this.EditorDialogManager.showCustomizeStreamDialog(this.pipelineElement.payload);
+    // this.EditorDialogManager.showCustomizeStreamDialog(this.pipelineElement.payload);
   }
 
   initRecs(pipelineElementDomId) {
-    let clonedModel: PipelineElementConfig[] = cloneDeep(this.rawPipelineModel);
+    const clonedModel: PipelineElementConfig[] = cloneDeep(this.rawPipelineModel);
     clonedModel.forEach(pe => {
       if (pe.payload.dom === pipelineElementDomId && (pe.type !== 'stream'  && pe.type !== 'set')) {
         pe.settings.completed = false;
         (pe.payload as InvocablePipelineElementUnion).configured = false;
       }
-    })
-    var currentPipeline = this.ObjectProvider.makePipeline(clonedModel);
-    this.EditorService.recommendPipelineElement(currentPipeline).subscribe((result) => {
+    });
+    const currentPipeline = this.objectProvider.makePipeline(clonedModel);
+    this.editorService.recommendPipelineElement(currentPipeline).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.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,{
+    const dialogRef = this.dialogService.open(CompatibleElementsComponent, {
       panelType: PanelType.SLIDE_IN_PANEL,
       title: 'Compatible Elements',
       data: {
@@ -173,12 +169,11 @@ export class PipelineElementOptionsComponent implements OnInit, OnDestroy {
   }
 
   isRootElement() {
-    return this.JsplumbBridge.getConnections({source: this.pipelineElement.payload.dom}).length === 0;
+    return this.JsplumbBridge.getConnections({source: document.getElementById(this.pipelineElement.payload.dom)}).length === 0;
   }
 
   isConfigured() {
-    if (this.isDataSource) return true;
-    else {
+    if (this.isDataSource) { return true; } else {
       return (this.pipelineElement.payload as InvocablePipelineElementUnion).configured;
     }
   }
diff --git a/ui/src/app/editor/components/pipeline/pipeline.component.html b/ui/src/app/editor/components/pipeline/pipeline.component.html
index d7cce7f..571ddc9 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.html
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.html
@@ -16,43 +16,45 @@
   ~
   -->
 
-<div style="z-index: 1" [ngStyle]="{width: canvasWidth, height: canvasHeight}" #outerCanvas>
-    <span 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">
-        <span 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-invalid {{pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'}}"
-                 *ngIf="!pipelineElement.settings.completed">
-                <i class="material-icons pipeline-element-configuration-invalid-icon">
+<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-invalid {{pipelineElement.type === 'stream' ? 'pi-stream' : 'pi-processor'}}"
+             *ngIf="!pipelineElement.settings.completed">
+            <i class="material-icons pipeline-element-configuration-invalid-icon">
                 warning
-                </i>
-            </div>
-            <pipeline-element [pipelineElement]="pipelineElement.payload" [preview]="preview"></pipeline-element>
-        </span>
-         <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">
+            </i>
+        </div>
+        <pipeline-element [pipelineElement]="pipelineElement.payload" [preview]="preview"></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>
-    </span>
+    </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 08288fc..f353df0 100644
--- a/ui/src/app/editor/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor/components/pipeline/pipeline.component.ts
@@ -16,17 +16,13 @@
  *
  */
 
-import {PipelineValidationService} from "../../services/pipeline-validation.service";
-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,
-  PipelineElementUnion
-} from "../../model/editor.model";
+import { PipelineValidationService } from '../../services/pipeline-validation.service';
+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, PipelineElementUnion } from '../../model/editor.model';
 import {
   CustomOutputStrategy,
   DataProcessorInvocation,
@@ -36,20 +32,22 @@ import {
   PipelinePreviewModel,
   SpDataSet,
   SpDataStream
-} from "../../../core-model/gen/streampipes-model";
-import {ObjectProvider} from "../../services/object-provider.service";
-import {CustomizeComponent} from "../../dialog/customize/customize.component";
-import {PanelType} from "../../../core-ui/dialog/base-dialog/base-dialog.model";
-import {DialogService} from "../../../core-ui/dialog/base-dialog/base-dialog.service";
-import {EditorService} from "../../services/editor.service";
-import {MatchingResultMessage} from "../../../core-model/gen/streampipes-model-client";
-import {MatchingErrorComponent} from "../../dialog/matching-error/matching-error.component";
-import {Tuple2} from "../../../core-model/base/Tuple2";
-import {ConfirmDialogComponent} from "../../../core-ui/dialog/confirm-dialog/confirm-dialog.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";
+} from '../../../core-model/gen/streampipes-model';
+import { ObjectProvider } from '../../services/object-provider.service';
+import { CustomizeComponent } from '../../dialog/customize/customize.component';
+import { PanelType } from '../../../core-ui/dialog/base-dialog/base-dialog.model';
+import { DialogService } from '../../../core-ui/dialog/base-dialog/base-dialog.service';
+import { EditorService } from '../../services/editor.service';
+import { MatchingResultMessage } from '../../../core-model/gen/streampipes-model-client';
+import { MatchingErrorComponent } from '../../dialog/matching-error/matching-error.component';
+import { Tuple2 } from '../../../core-model/base/Tuple2';
+import { ConfirmDialogComponent } from '../../../core-ui/dialog/confirm-dialog/confirm-dialog.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';
 
 @Component({
   selector: 'pipeline',
@@ -88,21 +86,18 @@ export class PipelineComponent implements OnInit, OnDestroy {
   @Output()
   pipelineCacheRunningChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
 
-  availablePipelineElementCache: PipelineElementUnion[];
-
   plumbReady: boolean;
   currentMouseOverElement: string;
   currentPipelineModel: Pipeline;
   idCounter: any;
   currentZoomLevel: any;
-  TransitionService: any;
 
-  canvasWidth: string = "100%";
-  canvasHeight: string = "100%";
+  canvasWidth = '100%';
+  canvasHeight = '100%';
 
   JsplumbBridge: JsplumbBridge;
 
-  previewModeActive: boolean = false;
+  previewModeActive = false;
   pipelinePreview: PipelinePreviewModel;
 
   constructor(private JsplumbService: JsplumbService,
@@ -115,9 +110,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
               private PipelineValidationService: PipelineValidationService,
               private dialogService: DialogService,
               private dialog: MatDialog,
-              private ngZone: NgZone,) {
+              private ngZone: NgZone, ) {
     this.plumbReady = false;
-    this.currentMouseOverElement = "";
+    this.currentMouseOverElement = '';
     this.currentPipelineModel = new Pipeline();
     this.idCounter = 0;
 
@@ -126,14 +121,10 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   ngOnInit() {
     this.JsplumbBridge = this.JsplumbFactoryService.getJsplumbBridge(this.preview);
-    this.JsplumbBridge.setContainer(this.canvasId);
     this.initAssembly();
     this.initPlumb();
   }
 
-  ngAfterViewInit() {
-  }
-
   validatePipeline() {
     setTimeout(() => {
       this.ngZone.run(() => {
@@ -145,7 +136,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   ngOnDestroy() {
     this.deletePipelineElementPreview(false);
-    this.JsplumbBridge.deleteEveryEndpoint();
+    this.JsplumbFactoryService.destroy(this.preview);
     this.plumbReady = false;
   }
 
@@ -155,23 +146,23 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   updateOptionsClick(elementId) {
     if (this.currentMouseOverElement == elementId) {
-      this.currentMouseOverElement = "";
+      this.currentMouseOverElement = '';
     } else {
       this.currentMouseOverElement = elementId;
     }
   }
 
   getElementCss(currentPipelineElementSettings) {
-    return "position:absolute;"
-        + (this.preview ? "width:75px;" : "width:110px;")
-        + (this.preview ? "height:75px;" : "height:110px;")
-        + "left: " + currentPipelineElementSettings.position.x + "px; "
-        + "top: " + currentPipelineElementSettings.position.y + "px; "
+    return 'position:absolute;'
+        + (this.preview ? 'width:75px;' : 'width:110px;')
+        + (this.preview ? 'height:75px;' : 'height:110px;')
+        + 'left: ' + currentPipelineElementSettings.position.x + 'px; '
+        + 'top: ' + currentPipelineElementSettings.position.y + 'px; ';
   }
 
   getElementCssClasses(currentPipelineElement) {
-    return currentPipelineElement.type + " " + (currentPipelineElement.settings.openCustomize ? "" : "")
-        + currentPipelineElement.settings.connectable + " "
+    return currentPipelineElement.type + ' ' + (currentPipelineElement.settings.openCustomize ? '' : '')
+        + currentPipelineElement.settings.connectable + ' '
         + currentPipelineElement.settings.displaySettings;
   }
 
@@ -191,9 +182,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
     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",
+        'title': 'Currently, it is not possible to mix data streams and data sets in a single pipeline.',
+        'confirmAndCancel': false,
+        'okTitle': 'Ok',
       },
     });
   }
@@ -202,17 +193,16 @@ export class PipelineComponent implements OnInit, OnDestroy {
     return this.allElements.find(a => a.elementId === elementId);
   }
 
-
   initAssembly() {
     ($('#assembly') as any).droppable({
-      tolerance: "fit",
+      tolerance: 'fit',
       drop: (element, ui) => {
-        let pipelineElementId = ui.draggable.data("pe");
-        let pipelineElement: PipelineElementUnion = this.findPipelineElementByElementId(pipelineElementId);
+        const pipelineElementId = ui.draggable.data('pe');
+        const pipelineElement: PipelineElementUnion = this.findPipelineElementByElementId(pipelineElementId);
         if (ui.draggable.hasClass('draggable-icon')) {
           this.EditorService.makePipelineAssemblyEmpty(false);
-          let newElementId = pipelineElement.elementId + ":" + this.JsplumbService.makeId(5);
-          let pipelineElementConfig = this.JsplumbService.createNewPipelineElementConfig(pipelineElement,
+          const newElementId = pipelineElement.elementId + ':' + this.JsplumbService.makeId(5);
+          const pipelineElementConfig = this.JsplumbService.createNewPipelineElementConfig(pipelineElement,
               this.PipelineEditorService.getCoordinates(ui, this.currentZoomLevel),
               false,
               false,
@@ -242,7 +232,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
               }, 10);
             }
             if (this.ShepherdService.isTourActive()) {
-              this.ShepherdService.trigger("drop-" + pipelineElementConfig.type);
+              this.ShepherdService.trigger('drop-' + pipelineElementConfig.type);
             }
           }
         }
@@ -251,7 +241,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
         this.triggerPipelineCacheUpdate();
       }
 
-    }); //End #assembly.droppable()
+    }); // End #assembly.droppable()
   }
 
   checkTopicModel(pipelineElementConfig: PipelineElementConfig) {
@@ -262,12 +252,12 @@ export class PipelineComponent implements OnInit, OnDestroy {
           false);
     }, 10);
 
-    var streamDescription = pipelineElementConfig.payload as SpDataStream;
+    const streamDescription = pipelineElementConfig.payload as SpDataStream;
     if (streamDescription
         .eventGrounding
         .transportProtocols[0]
-        .topicDefinition["@class"] === "org.apache.streampipes.model.grounding.WildcardTopicDefinition") {
-      //this.EditorDialogManager.showCustomizeStreamDialog(streamDescription);
+        .topicDefinition['@class'] === 'org.apache.streampipes.model.grounding.WildcardTopicDefinition') {
+      // this.EditorDialogManager.showCustomizeStreamDialog(streamDescription);
     }
   }
 
@@ -288,54 +278,56 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   initPlumb() {
 
-    //this.JsplumbService.prepareJsplumb();
+    // this.JsplumbService.prepareJsplumb();
 
-    this.JsplumbBridge.unbind("connection");
+    this.JsplumbBridge.unbind(EVENT_CONNECTION);
 
-    this.JsplumbBridge.bind("connectionMoved", (info, originalEvent) => {
-      var pe = this.ObjectProvider.findElement(info.newTargetEndpoint.elementId, this.rawPipelineModel);
-      var oldPe = this.ObjectProvider.findElement(info.originalTargetEndpoint.elementId, this.rawPipelineModel);
+    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("connectionDetached", (info, originalEvent) => {
-      var pe = this.ObjectProvider.findElement(info.targetEndpoint.elementId, this.rawPipelineModel);
+    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");
+      info.targetEndpoint.setType('empty');
+      this.JsplumbBridge.repaintEverything();
       this.validatePipeline();
     });
 
-    this.JsplumbBridge.bind("connectionDrag", connection => {
-      this.JsplumbBridge.selectEndpoints().each(function (endpoint) {
+    this.JsplumbBridge.bind(EVENT_CONNECTION_DRAG, () => {
+      this.JsplumbBridge.selectEndpoints().each(endpoint => {
         if (endpoint.isTarget && endpoint.connections.length === 0) {
-          endpoint.setType("highlight");
+          endpoint.setType('highlight');
         }
       });
-
+      this.JsplumbBridge.repaintEverything();
     });
-    this.JsplumbBridge.bind("connectionAborted", connection => {
+    this.JsplumbBridge.bind(EVENT_CONNECTION_ABORT, () => {
       this.JsplumbBridge.selectEndpoints().each(endpoint => {
         if (endpoint.isTarget && endpoint.connections.length === 0) {
-          endpoint.setType("empty");
+          endpoint.setType('empty');
         }
       });
-    })
+      this.JsplumbBridge.repaintEverything();
+    });
 
-    this.JsplumbBridge.bind("connection", (info, originalEvent) => {
-      var pe = this.ObjectProvider.findElement(info.target.id, this.rawPipelineModel);
+    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;
-              info.targetEndpoint.setType("token");
+              info.targetEndpoint.setType('token');
               this.validatePipeline();
               this.modifyPipeline(pipelineModificationMessage.pipelineModifications);
               if (this.JsplumbService.isFullyConnected(pe, this.preview)) {
-                let payload = pe.payload as InvocablePipelineElementUnion;
+                const payload = pe.payload as InvocablePipelineElementUnion;
                 if ((payload.staticProperties && payload.staticProperties.length > 0) || this.isCustomOutput(pe)) {
                   this.showCustomizeDialog({a: false, b: pe});
                 } else {
@@ -348,7 +340,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
               pe.settings.loadingStatus = false;
               this.JsplumbBridge.detach(info.connection);
               if (Array.isArray(status.error)) {
-                let matchingResultMessage = (status.error as any[]).map(e => MatchingResultMessage.fromData(e as MatchingResultMessage));
+                const matchingResultMessage = (status.error as any[]).map(e => MatchingResultMessage.fromData(e as MatchingResultMessage));
                 this.showMatchingErrorDialog(matchingResultMessage);
               } else {
                 this.showErrorDialog(status.error.title, status.error.description);
@@ -357,7 +349,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
       }
     });
 
-    window.onresize = (event) => {
+    window.onresize = () => {
       this.JsplumbBridge.repaintEverything();
     };
 
@@ -369,9 +361,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
   modifyPipeline(pipelineModifications) {
     if (pipelineModifications) {
       pipelineModifications.forEach(modification => {
-        var id = modification.domId;
-        if (id !== "undefined") {
-          var pe = this.ObjectProvider.findElement(id, this.rawPipelineModel);
+        const id = modification.domId;
+        if (id !== 'undefined') {
+          const pe = this.ObjectProvider.findElement(id, this.rawPipelineModel);
           (pe.payload as InvocablePipelineElementUnion).staticProperties = modification.staticProperties;
           (pe.payload as DataProcessorInvocation).outputStrategies = modification.outputStrategies;
           (pe.payload as InvocablePipelineElementUnion).inputStreams = modification.inputStreams;
@@ -381,7 +373,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
   }
 
   isCustomOutput(pe) {
-    var custom = false;
+    let custom = false;
     pe.payload.outputStrategies.forEach(strategy => {
       if (strategy instanceof CustomOutputStrategy) {
         custom = true;
@@ -395,11 +387,11 @@ export class PipelineComponent implements OnInit, OnDestroy {
       this.pipelineCacheRunning = true;
       this.pipelineCacheRunningChanged.emit(this.pipelineCacheRunning);
       this.PipelinePositioningService.collectPipelineElementPositions(this.pipelineCanvasMetadata, this.rawPipelineModel);
-      let updateCachedPipeline = this.EditorService.updateCachedPipeline(this.rawPipelineModel);
-      let updateCachedCanvasMetadata = this.EditorService.updateCachedCanvasMetadata(this.pipelineCanvasMetadata);
-      forkJoin([updateCachedPipeline, updateCachedCanvasMetadata]).subscribe(msg => {
+      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.pipelineCacheRunningChanged.emit(this.pipelineCacheRunning);
         this.pipelineCached = true;
         this.pipelineCachedChanged.emit(this.pipelineCached);
       });
@@ -410,10 +402,10 @@ export class PipelineComponent implements OnInit, OnDestroy {
     this.dialog.open(ConfirmDialogComponent, {
       width: '500px',
       data: {
-        "title": title,
-        "subtitle": description,
-        "okTitle": "Ok",
-        "confirmAndCancel": false
+        'title': title,
+        'subtitle': description,
+        'okTitle': 'Ok',
+        'confirmAndCancel': false
       },
     });
   }
@@ -421,9 +413,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
   showMatchingErrorDialog(matchingResultMessage: MatchingResultMessage[]) {
     this.dialogService.open(MatchingErrorComponent, {
       panelType: PanelType.STANDARD_PANEL,
-      title: "Invalid Connection",
+      title: 'Invalid Connection',
       data: {
-        "matchingResultMessage": matchingResultMessage
+        'matchingResultMessage': matchingResultMessage
       }
     });
   }
@@ -431,11 +423,11 @@ export class PipelineComponent implements OnInit, OnDestroy {
   showCustomizeDialog(pipelineElementInfo: Tuple2<Boolean, PipelineElementConfig>) {
     const dialogRef = this.dialogService.open(CustomizeComponent, {
       panelType: PanelType.SLIDE_IN_PANEL,
-      title: "Customize " + pipelineElementInfo.b.payload.name,
-      width: "50vw",
+      title: 'Customize ' + pipelineElementInfo.b.payload.name,
+      width: '50vw',
       data: {
-        "pipelineElement": pipelineElementInfo.b,
-        "restrictedEditMode": pipelineElementInfo.a
+        'pipelineElement': pipelineElementInfo.b,
+        'restrictedEditMode': pipelineElementInfo.a
       }
     });
 
@@ -444,9 +436,9 @@ export class PipelineComponent implements OnInit, OnDestroy {
         pipelineElementInfo.b.settings.openCustomize = false;
         (pipelineElementInfo.b.payload as InvocablePipelineElementUnion).configured = true;
         if (!(pipelineElementInfo.b.payload instanceof DataSinkInvocation)) {
-          this.JsplumbBridge.activateEndpoint("out-" + pipelineElementInfo.b.payload.dom, pipelineElementInfo.b.settings.completed);
+          this.JsplumbBridge.activateEndpoint('out-' + pipelineElementInfo.b.payload.dom, pipelineElementInfo.b.settings.completed);
         }
-        this.JsplumbBridge.getSourceEndpoint(pipelineElementInfo.b.payload.dom).setType("token");
+        this.JsplumbBridge.getSourceEndpoint(pipelineElementInfo.b.payload.dom).toggleType('token');
         this.triggerPipelineCacheUpdate();
         this.announceConfiguredElement(pipelineElementInfo.b);
         if (this.previewModeActive) {
@@ -463,7 +455,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   initiatePipelineElementPreview() {
     if (!this.previewModeActive) {
-      let pipeline = this.ObjectProvider.makePipeline(this.rawPipelineModel);
+      const pipeline = this.ObjectProvider.makePipeline(this.rawPipelineModel);
       this.EditorService.initiatePipelinePreview(pipeline).subscribe(response => {
         this.pipelinePreview = response;
         this.previewModeActive = true;
@@ -475,7 +467,7 @@ export class PipelineComponent implements OnInit, OnDestroy {
 
   deletePipelineElementPreview(resume: boolean) {
     if (this.previewModeActive) {
-      this.EditorService.deletePipelinePreviewRequest(this.pipelinePreview.previewId).subscribe(response => {
+      this.EditorService.deletePipelinePreviewRequest(this.pipelinePreview.previewId).subscribe(() => {
         this.previewModeActive = false;
         if (resume) {
           this.initiatePipelineElementPreview();
diff --git a/ui/src/app/editor/services/jsplumb-bridge.service.ts b/ui/src/app/editor/services/jsplumb-bridge.service.ts
index ca94753..6a3eb77 100644
--- a/ui/src/app/editor/services/jsplumb-bridge.service.ts
+++ b/ui/src/app/editor/services/jsplumb-bridge.service.ts
@@ -16,16 +16,17 @@
  *
  */
 
-import {jsPlumbInstance} from 'jsplumb'
+import { BrowserJsPlumbInstance } from '@jsplumb/browser-ui';
+import { SelectOptions } from "@jsplumb/core";
 
 export class JsplumbBridge {
 
-    constructor(private jsPlumbInstance: jsPlumbInstance) {
+    constructor(private jsPlumbInstance: BrowserJsPlumbInstance) {
     }
 
     activateEndpoint(endpointId: string, endpointEnabled: boolean) {
         let endpoint = this.getEndpointById(endpointId);
-        endpoint.setEnabled(endpointEnabled);
+        endpoint.enabled = endpointEnabled;
     }
 
     activateEndpointWithType(endpointId: string, endpointEnabled: boolean, endpointType: string) {
@@ -48,15 +49,17 @@ export class JsplumbBridge {
     }
 
     repaintEverything() {
-        this.jsPlumbInstance.repaintEverything(true);
+        this.jsPlumbInstance.repaintEverything();
     }
 
     deleteEveryEndpoint() {
-        this.jsPlumbInstance.deleteEveryEndpoint();
+        // TODO
+        //this.jsPlumbInstance.destroy();
+        //this.jsPlumbInstance.deleteEveryEndpoint();
     }
 
     setContainer(container) {
-        this.jsPlumbInstance.setContainer(container);
+        this.jsPlumbInstance.setContainer(document.getElementById(container));
     }
 
     unbind(element) {
@@ -94,19 +97,21 @@ export class JsplumbBridge {
 
     getEndpointCount(id) {
         // @ts-ignore
-        return this.jsPlumbInstance.selectEndpoints({element: id}).length;
+        return this.jsPlumbInstance.selectEndpoints({element: document.getElementById(id)}).length;
     }
 
     detach(connection) {
         this.jsPlumbInstance.deleteConnection(connection);
     }
 
-    getConnections(filter) {
-        return this.jsPlumbInstance.getConnections(filter, {});
+    getConnections(filter: SelectOptions<Element>) {
+        return this.jsPlumbInstance.getConnections(filter);
     }
 
-    addEndpoint(element, options) {
-        return this.jsPlumbInstance.addEndpoint(element, options);
+    addEndpoint(pipelineElementDomId: string,
+                options: any) {
+        options.cssClass = "sp-no-pan";
+        return this.jsPlumbInstance.addEndpoint(document.getElementById(pipelineElementDomId), options);
     }
 
     connect(connection) {
@@ -114,17 +119,13 @@ export class JsplumbBridge {
     }
 
     removeAllEndpoints(element) {
-        this.jsPlumbInstance.removeAllEndpoints(element);
+        this.jsPlumbInstance.removeAllEndpoints(document.getElementById(element));
     }
 
     registerEndpointTypes(typeInfo) {
         this.jsPlumbInstance.registerEndpointTypes(typeInfo);
     }
 
-    draggable(element, option) {
-        this.jsPlumbInstance.draggable(element, option);
-    }
-
     // TODO: Overloading Functions?
     setSuspendDrawing(bool1, bool2?) {
         if (bool2 === undefined) {
@@ -135,12 +136,10 @@ export class JsplumbBridge {
     }
 
     getAllConnections() {
-        return this.jsPlumbInstance.getAllConnections();
+        return this.jsPlumbInstance.getConnections();
     }
 
     reset() {
         this.jsPlumbInstance.reset();
     }
 }
-
-//JsplumbBridge.$inject = [];
diff --git a/ui/src/app/editor/services/jsplumb-config.service.ts b/ui/src/app/editor/services/jsplumb-config.service.ts
index 44de61c..2ddacd9 100644
--- a/ui/src/app/editor/services/jsplumb-config.service.ts
+++ b/ui/src/app/editor/services/jsplumb-config.service.ts
@@ -16,8 +16,10 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {JsplumbSettings} from "../model/jsplumb.model";
+import { Injectable } from "@angular/core";
+import { JsplumbSettings } from "../model/jsplumb.model";
+import { BezierConnector } from "@jsplumb/connector-bezier";
+import { EndpointTypeDescriptor } from "@jsplumb/core";
 
 @Injectable()
 export class JsplumbConfigService {
@@ -33,6 +35,37 @@ export class JsplumbConfigService {
         return this.makeConfig(this.makeSettings(6, 2, 15, 15, 1, 40));
     }
 
+    getEndpointTypeConfig(): Record<string, EndpointTypeDescriptor> {
+        return {
+            "empty": {
+                paintStyle: {
+                    fill: "white",
+                    stroke: "#9E9E9E",
+                    strokeWidth: 2,
+                }
+            },
+            "token": {
+                paintStyle: {
+                    fill: "#BDBDBD",
+                    stroke: "#9E9E9E",
+                    strokeWidth: 2
+                },
+                hoverPaintStyle: {
+                    fill: "#BDBDBD",
+                    stroke: "#4CAF50",
+                    strokeWidth: 4,
+                }
+            },
+            "highlight": {
+                paintStyle: {
+                    fill: "white",
+                    stroke: "#4CAF50",
+                    strokeWidth: 4
+                }
+            }
+        }
+    }
+
     makeConfig(settings) {
         let config = {} as any;
         config.streamEndpointOptions = this.makeStreamEndpointOptions(settings);
@@ -59,45 +92,29 @@ export class JsplumbConfigService {
 
     makeStreamEndpointOptions(settings: JsplumbSettings) {
         return {
-            endpoint: ["Dot", {radius: settings.dotRadius}],
+            endpoint: {type: "Dot", options: {radius: settings.dotRadius}},
             connectorStyle: {stroke: "#BDBDBD", outlineStroke: "#BDBDBD", strokeWidth: settings.lineWidth},
-            connector: ["Bezier", {curviness: settings.curviness}],
-            isSource: true,
+            connector: {type: BezierConnector.type, options: {curviness: settings.curviness}},
+            source: true,
+            type: "token",
             maxConnections: -1,
             anchor: "Right",
-            type: "token",
-            connectorOverlays: [
-                ["Arrow", {
-                    width: settings.arrowWidth, length: settings.arrowLength, location: 0.5, id: "arrow", paintStyle: {
-                        fillStyle: "#BDBDBD",
-                        stroke: "#9E9E9E",
-                        strokeWidth: settings.arrowLineWidth
-                    }
-                }],
-            ]
+            connectorOverlays: this.defaultConnectorOverlay(settings)
         }
     }
 
     makeSepaEndpointOptions(settings) {
         return {
-            endpoint: ["Dot", {radius: settings.dotRadius}],
+            endpoint: {type: "Dot", options: {radius: settings.dotRadius}},
             connectorStyle: {
                 stroke: "#BDBDBD", outlineStroke: "#9E9E9E", strokeWidth: settings.lineWidth
             },
-            connector: ["Bezier", {curviness: settings.curviness}],
-            isSource: true,
+            connector: {type: BezierConnector.type, options: {curviness: settings.curviness}},
+            source: true,
             maxConnections: -1,
             anchor: "Right",
             type: "empty",
-            connectorOverlays: [
-                ["Arrow", {
-                    width: settings.arrowWidth, length: settings.arrowLength, location: 0.5, id: "arrow", paintStyle: {
-                        fill: "#BDBDBD",
-                        stroke: "#9E9E9E",
-                        strokeWidth: settings.arrowLineWidth
-                    }
-                }],
-            ],
+            connectorOverlays: this.defaultConnectorOverlay(settings),
             parameters: {
                 endpointType: "output"
             }
@@ -106,11 +123,23 @@ export class JsplumbConfigService {
 
     makeLeftTargetPointOptions(settings) {
         return {
-            endpoint: ["Dot", {radius: settings.dotRadius}],
+            endpoint: {type: "Dot", options: {radius: settings.dotRadius}},
             type: "empty",
             anchor: "Left",
-            isTarget: true
+            target: true
         }
     }
 
+    defaultConnectorOverlay(settings) {
+        return [{
+            type: "Arrow", options: {
+                width: settings.arrowWidth, length: settings.arrowLength, location: 0.5, id: "arrow", paintStyle: {
+                    fillStyle: "#BDBDBD",
+                    stroke: "#9E9E9E",
+                    strokeWidth: settings.arrowLineWidth
+                }
+            }
+        }];
+    }
+
 }
diff --git a/ui/src/app/editor/services/jsplumb-factory.service.ts b/ui/src/app/editor/services/jsplumb-factory.service.ts
index ff16482..6671a82 100644
--- a/ui/src/app/editor/services/jsplumb-factory.service.ts
+++ b/ui/src/app/editor/services/jsplumb-factory.service.ts
@@ -16,70 +16,75 @@
  *
  */
 
-import {jsPlumb, jsPlumbInstance} from "jsplumb";
-import {JsplumbBridge} from "./jsplumb-bridge.service";
-import {Injectable} from "@angular/core";
+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 { PipelineElementDraggedService } from "./pipeline-element-dragged.service";
+import { JsplumbConfigService } from "./jsplumb-config.service";
 
 @Injectable()
 export class JsplumbFactoryService {
 
-  pipelineEditorInstance: jsPlumbInstance;
-  pipelinePreviewInstance: jsPlumbInstance;
+    pipelineEditorInstance: BrowserJsPlumbInstance;
+    pipelinePreviewInstance: BrowserJsPlumbInstance;
 
-  pipelineEditorBridge: JsplumbBridge;
-  pipelinePreviewBridge: JsplumbBridge;
+    pipelineEditorBridge: JsplumbBridge;
+    pipelinePreviewBridge: JsplumbBridge;
 
-  constructor() {
-    this.pipelineEditorInstance = this.makePipelineEditorInstance();
-    this.pipelinePreviewInstance = this.makePipelinePreviewInstance();
+    constructor(private pipelineElementDraggedService: PipelineElementDraggedService,
+                private jsplumbConfigService: JsplumbConfigService) {
+    }
 
-    this.pipelineEditorBridge = new JsplumbBridge(this.pipelineEditorInstance);
-    this.pipelinePreviewBridge = new JsplumbBridge(this.pipelinePreviewInstance);
-
-    this.prepareJsplumb(this.pipelineEditorInstance);
-    this.prepareJsplumb(this.pipelinePreviewInstance);
-  }
+    getJsplumbBridge(previewConfig: boolean): JsplumbBridge {
+        if (!previewConfig) {
+            if (!this.pipelineEditorBridge) {
+                this.pipelineEditorInstance = this.makePipelineEditorInstance();
+                this.prepareJsplumb(this.pipelineEditorInstance);
+                this.pipelineEditorBridge = new JsplumbBridge(this.pipelineEditorInstance);
+            }
+            return this.pipelineEditorBridge;
+        } else {
+            if (!this.pipelinePreviewBridge) {
+                this.pipelinePreviewInstance = this.makePipelinePreviewInstance();
+                this.prepareJsplumb(this.pipelinePreviewInstance);
+                this.pipelinePreviewBridge = new JsplumbBridge(this.pipelinePreviewInstance);
+            }
+            return this.pipelinePreviewBridge;
+        }
+    }
 
-  getJsplumbBridge(previewConfig: boolean): JsplumbBridge {
-    return previewConfig ? this.pipelineEditorBridge : this.pipelinePreviewBridge;
-  }
+    makePipelineEditorInstance(): BrowserJsPlumbInstance {
+        return newInstance({
+            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});
+                }
+            },
+        });
+    }
 
-  makePipelineEditorInstance(): jsPlumbInstance {
-    return jsPlumb.getInstance();
-  }
+    makePipelinePreviewInstance(): BrowserJsPlumbInstance {
+        return newInstance({
+            container: document.getElementById("assembly-preview"),
+            elementsDraggable: false
+        });
+    }
 
-  makePipelinePreviewInstance(): jsPlumbInstance {
-    return jsPlumb.getInstance();
-  }
+    prepareJsplumb(jsplumbInstance: JsPlumbInstance) {
+        jsplumbInstance.registerEndpointTypes(this.jsplumbConfigService.getEndpointTypeConfig());
+    }
 
-  prepareJsplumb(jsplumbInstance: jsPlumbInstance) {
-    jsplumbInstance.registerEndpointTypes({
-      "empty": {
-        paintStyle: {
-          fill: "white",
-          stroke: "#9E9E9E",
-          strokeWidth: 2,
-        }
-      },
-      "token": {
-        paintStyle: {
-          fill: "#BDBDBD",
-          stroke: "#9E9E9E",
-          strokeWidth: 2
-        },
-        hoverPaintStyle: {
-          fill: "#BDBDBD",
-          stroke: "#4CAF50",
-          strokeWidth: 4,
-        }
-      },
-      "highlight": {
-        paintStyle: {
-          fill: "white",
-          stroke: "#4CAF50",
-          strokeWidth: 4
+    destroy(preview: boolean) {
+        if (preview) {
+            this.pipelinePreviewInstance.destroy();
+            this.pipelinePreviewBridge = undefined;
+        } else {
+            this.pipelineEditorInstance.destroy();
+            this.pipelineEditorBridge = undefined;
         }
-      }
-    });
-  }
+    }
 }
diff --git a/ui/src/app/editor/services/jsplumb.service.ts b/ui/src/app/editor/services/jsplumb.service.ts
index 4a30738..7ac0e1c 100644
--- a/ui/src/app/editor/services/jsplumb.service.ts
+++ b/ui/src/app/editor/services/jsplumb.service.ts
@@ -16,15 +16,11 @@
  *
  */
 
-import {JsplumbConfigService} from "./jsplumb-config.service";
-import {JsplumbBridge} from "./jsplumb-bridge.service";
-import {Injectable} from "@angular/core";
-import {
-    InvocablePipelineElementUnion,
-    PipelineElementConfig,
-    PipelineElementUnion
-} from "../model/editor.model";
-import {PipelineElementTypeUtils} from "../utils/editor.utils";
+import { JsplumbConfigService } from "./jsplumb-config.service";
+import { JsplumbBridge } from "./jsplumb-bridge.service";
+import { Injectable } from "@angular/core";
+import { InvocablePipelineElementUnion, PipelineElementConfig, PipelineElementUnion } from "../model/editor.model";
+import { PipelineElementTypeUtils } from "../utils/editor.utils";
 import {
     DataProcessorInvocation,
     DataSinkInvocation,
@@ -33,9 +29,8 @@ import {
     SpDataStream,
     SpDataStreamUnion
 } from "../../core-model/gen/streampipes-model";
-import {PipelineElementDraggedService} from "./pipeline-element-dragged.service";
-import {JsplumbEndpointService} from "./jsplumb-endpoint.service";
-import {JsplumbFactoryService} from "./jsplumb-factory.service";
+import { JsplumbEndpointService } from "./jsplumb-endpoint.service";
+import { JsplumbFactoryService } from "./jsplumb-factory.service";
 import { EditorService } from './editor.service';
 
 @Injectable()
@@ -46,8 +41,7 @@ export class JsplumbService {
     constructor(private JsplumbConfigService: JsplumbConfigService,
                 private JsplumbFactory: JsplumbFactoryService,
                 private jsplumbEndpointService: JsplumbEndpointService,
-                private editorService: EditorService,
-                private pipelineElementDraggedService: PipelineElementDraggedService) {
+                private editorService: EditorService) {
     }
 
     isFullyConnected(pipelineElementConfig: PipelineElementConfig,
@@ -55,7 +49,7 @@ export class JsplumbService {
         let jsplumbBridge = this.JsplumbFactory.getJsplumbBridge(previewConfig);
         let payload = pipelineElementConfig.payload as InvocablePipelineElementUnion;
         return payload.inputStreams == null ||
-          jsplumbBridge.getConnections({target: $("#" +payload.dom)}).length == payload.inputStreams.length;
+          jsplumbBridge.getConnections({target: document.getElementById(payload.dom)}).length == payload.inputStreams.length;
     }
 
     makeRawPipeline(pipelineModel: Pipeline,
@@ -107,7 +101,7 @@ export class JsplumbService {
     createElement(pipelineModel: PipelineElementConfig[],
                   pipelineElement: InvocablePipelineElementUnion,
                   pipelineElementDomId: string) {
-        var pipelineElementDom = $("#" + pipelineElementDomId);
+        let pipelineElementDom = $("#" + pipelineElementDomId);
 
         let pipelineElementConfig = this.createNewPipelineElementConfigWithFixedCoordinates(pipelineElementDom, pipelineElement, false);
         pipelineModel.push(pipelineElementConfig);
@@ -123,7 +117,7 @@ export class JsplumbService {
                           pipelineElement: InvocablePipelineElementUnion,
                           $parentElement,
                           previewConfig: boolean) {
-        var $target;
+        let $target;
         if (pipelineElement instanceof DataProcessorInvocation) {
             $target = this.dataProcessorDropped(pipelineElementDomId, pipelineElement as DataProcessorInvocation, true, false);
             this.connectNodes($parentElement, $target, previewConfig);
@@ -136,7 +130,7 @@ export class JsplumbService {
     connectNodes($parentElement,
                  $target,
                  previewConfig: boolean) {
-        var options;
+        let options;
         let jsplumbBridge = this.getBridge(previewConfig);
         if ($parentElement.hasClass("stream")) {
             // TODO: getJsplumbConfig depends on isPreview. Not implemented yet
@@ -145,7 +139,7 @@ export class JsplumbService {
             // TODO: getJsplumbConfig depends on isPreview. Not implemented yet
             options = this.jsplumbEndpointService.getJsplumbConfig(true).sepaEndpointOptions;
         }
-        var sourceEndPoint;
+        let sourceEndPoint;
         if (jsplumbBridge.selectEndpoints({source: $parentElement}).length > 0) {
             if (!(jsplumbBridge.selectEndpoints({source: $parentElement}).get(0).isFull())) {
                 sourceEndPoint = jsplumbBridge.selectEndpoints({source: $parentElement}).get(0)
@@ -156,15 +150,15 @@ export class JsplumbService {
             sourceEndPoint = jsplumbBridge.addEndpoint($parentElement, options);
         }
 
-        var targetEndPoint = jsplumbBridge.selectEndpoints({target: $target}).get(0);
+        let targetEndPoint = jsplumbBridge.selectEndpoints({target: $target}).get(0);
 
         jsplumbBridge.connect({source: sourceEndPoint, target: targetEndPoint, detachable: true});
         jsplumbBridge.repaintEverything();
     }
 
     createNewPipelineElementConfigWithFixedCoordinates($parentElement, json, isPreview): PipelineElementConfig {
-        var x = $parentElement.position().left;
-        var y = $parentElement.position().top;
+        let x = $parentElement.position().left;
+        let y = $parentElement.position().top;
         return this.createNewPipelineElementConfigAtPosition(x, y, json, isPreview);
     }
 
@@ -232,10 +226,10 @@ export class JsplumbService {
     }
 
     makeId(count: number) {
-        var text = "";
-        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+        let text = "";
+        const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 
-        for (var i = 0; i < count; i++)
+        for (let i = 0; i < count; i++)
             text += possible.charAt(Math.floor(Math.random() * possible.length));
 
         return text;
@@ -253,20 +247,15 @@ export class JsplumbService {
             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) {
-
-
-
         let jsplumbBridge = this.getBridge(preview);
-
         if (endpoints) {
-            this.makeDraggableIfNotPreview(pipelineElementDomId, jsplumbBridge, preview);
             let endpointOptions = this.jsplumbEndpointService.getStreamEndpoint(preview, pipelineElementDomId);
             jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
         }
@@ -280,7 +269,6 @@ export class JsplumbService {
                       preview: boolean) {
         let jsplumbBridge = this.getBridge(preview);
         if (endpoints) {
-            this.makeDraggableIfNotPreview(pipelineElementDomId, jsplumbBridge, preview);
             let endpointOptions = this.jsplumbEndpointService.getStreamEndpoint(preview, pipelineElementDomId);
             jsplumbBridge.addEndpoint(pipelineElementDomId, endpointOptions);
         }
@@ -305,8 +293,6 @@ export class JsplumbService {
                     endpoints: boolean,
                     preview: boolean): string {
         let jsplumbBridge = this.getBridge(preview);
-        this.makeDraggableIfNotPreview(pipelineElementDomId, jsplumbBridge, preview);
-
         if (endpoints) {
             if (pipelineElement.inputStreams.length < 2) { //1 InputNode
                 jsplumbBridge.addEndpoint(pipelineElementDomId,
@@ -324,16 +310,4 @@ export class JsplumbService {
     getBridge(previewConfig: boolean): JsplumbBridge {
         return this.JsplumbFactory.getJsplumbBridge(previewConfig);
     }
-
-    makeDraggableIfNotPreview(pipelineElementDomId: string,
-                              jsplumbBridge: JsplumbBridge,
-                              previewConfig: boolean) {
-        if (!previewConfig) {
-            jsplumbBridge.draggable(pipelineElementDomId, {containment: 'parent',
-                drag: (e => {
-                    this.pipelineElementDraggedService.notify({x: e.pos[0], y: e.pos[1]});
-                })
-            });
-        }
-    }
 }
diff --git a/ui/src/app/editor/services/object-provider.service.ts b/ui/src/app/editor/services/object-provider.service.ts
index ff64406..e644181 100644
--- a/ui/src/app/editor/services/object-provider.service.ts
+++ b/ui/src/app/editor/services/object-provider.service.ts
@@ -71,13 +71,7 @@ export class ObjectProvider {
     }
 
     findElement(elementId, rawPipelineModel: PipelineElementConfig[]): PipelineElementConfig {
-        let result = {} as PipelineElementConfig;
-        rawPipelineModel.forEach(pe => {
-            if (pe.payload.dom === elementId) {
-                result = pe;
-            }
-        });
-        return result;
+        return rawPipelineModel.find(pe => pe.payload.dom === elementId) || {} as PipelineElementConfig;
     }
 
     addElementNew(pipeline, currentPipelineElements: PipelineElementConfig[]): Pipeline {
@@ -88,7 +82,7 @@ export class ObjectProvider {
                     let payload = pe.payload;
                     payload = this.prepareElement(payload as InvocablePipelineElementUnion);
                     let connections = JsplumbBridge.getConnections({
-                        target: $("#" + payload.dom)
+                        target: document.getElementById(payload.dom)
                     });
                     for (let i = 0; i < connections.length; i++) {
                         payload.connectedTo.push(connections[i].sourceId);
diff --git a/ui/src/app/editor/services/pipeline-positioning.service.ts b/ui/src/app/editor/services/pipeline-positioning.service.ts
index bf41d28..8e6b682 100644
--- a/ui/src/app/editor/services/pipeline-positioning.service.ts
+++ b/ui/src/app/editor/services/pipeline-positioning.service.ts
@@ -17,163 +17,186 @@
  */
 
 import * as dagre from "dagre";
-import {JsplumbBridge} from "./jsplumb-bridge.service";
-import {JsplumbConfigService} from "./jsplumb-config.service";
-import {JsplumbService} from "./jsplumb.service";
-import {Injectable} from "@angular/core";
-import {PipelineElementConfig} from "../model/editor.model";
+import { JsplumbBridge } from "./jsplumb-bridge.service";
+import { JsplumbConfigService } from "./jsplumb-config.service";
+import { JsplumbService } from "./jsplumb.service";
+import { Injectable } from "@angular/core";
+import { PipelineElementConfig } from "../model/editor.model";
 import {
-    DataProcessorInvocation,
-    DataSinkInvocation,
-    PipelineCanvasMetadata,
-    PipelineElementMetadata,
-    SpDataStream
+  DataProcessorInvocation,
+  DataSinkInvocation,
+  PipelineCanvasMetadata,
+  PipelineElementMetadata,
+  SpDataStream
 } from "../../core-model/gen/streampipes-model";
-import {JsplumbFactoryService} from "./jsplumb-factory.service";
-import {ObjectProvider} from "./object-provider.service";
+import { JsplumbFactoryService } from "./jsplumb-factory.service";
+import { ObjectProvider } from "./object-provider.service";
+import { Connection } from "@jsplumb/core";
 
 @Injectable()
 export class PipelinePositioningService {
 
-    constructor(private JsplumbService: JsplumbService,
-                private JsplumbConfigService: JsplumbConfigService,
-                private JsplumbFactoryService: JsplumbFactoryService,
-                private ObjectProvider: ObjectProvider) {
-    }
+  constructor(private JsplumbService: JsplumbService,
+              private JsplumbConfigService: JsplumbConfigService,
+              private JsplumbFactoryService: JsplumbFactoryService,
+              private ObjectProvider: ObjectProvider) {
+  }
+
+  collectPipelineElementPositions(pipelineCanvasMetadata: PipelineCanvasMetadata,
+                                  rawPipelineModel: PipelineElementConfig[]): PipelineCanvasMetadata {
+    rawPipelineModel.forEach(pe => {
+      this.collectPipelineElementPosition(pe.payload.dom, pipelineCanvasMetadata);
+    });
+    return pipelineCanvasMetadata;
+  }
 
-    collectPipelineElementPositions(pipelineCanvasMetadata: PipelineCanvasMetadata,
-                                    rawPipelineModel: PipelineElementConfig[]): PipelineCanvasMetadata {
-        rawPipelineModel.forEach(pe => {
-           this.collectPipelineElementPosition(pe.payload.dom, pipelineCanvasMetadata);
-        });
-        return pipelineCanvasMetadata;
+  collectPipelineElementPosition(domId: string,
+                                 pipelineCanvasMetadata: PipelineCanvasMetadata) {
+    let elementRef = $(`#${domId}`);
+    if (elementRef && elementRef.position()) {
+      let leftPos = elementRef.position().left;
+      let topPos = elementRef.position().top;
+      if (!pipelineCanvasMetadata.pipelineElementMetadata) {
+        pipelineCanvasMetadata.pipelineElementMetadata = {};
+      }
+      if (!pipelineCanvasMetadata.pipelineElementMetadata[domId]) {
+        pipelineCanvasMetadata.pipelineElementMetadata[domId] = new PipelineElementMetadata();
+      }
+      pipelineCanvasMetadata.pipelineElementMetadata[domId].position = {
+        x: leftPos,
+        y: topPos
+      };
     }
+  }
 
-    collectPipelineElementPosition(domId: string,
-                                   pipelineCanvasMetadata: PipelineCanvasMetadata) {
-        let elementRef = $(`#${domId}`);
-        if (elementRef && elementRef.position()) {
-            let leftPos = elementRef.position().left;
-            let topPos = elementRef.position().top;
-            if (!pipelineCanvasMetadata.pipelineElementMetadata) {
-                pipelineCanvasMetadata.pipelineElementMetadata = {};
-            }
-            if (!pipelineCanvasMetadata.pipelineElementMetadata[domId]) {
-                pipelineCanvasMetadata.pipelineElementMetadata[domId] = new PipelineElementMetadata();
-            }
-            pipelineCanvasMetadata.pipelineElementMetadata[domId].position = {
-                x: leftPos,
-                y: topPos
-            };
+  displayPipeline(rawPipelineModel: PipelineElementConfig[],
+                  targetCanvas,
+                  previewConfig: boolean,
+                  autoLayout: boolean,
+                  pipelineCanvasMetadata?: PipelineCanvasMetadata) {
+    let jsPlumbBridge = this.JsplumbFactoryService.getJsplumbBridge(previewConfig);
+
+    let jsplumbConfig = previewConfig ?
+      this.JsplumbConfigService.getPreviewConfig() :
+      this.JsplumbConfigService.getEditorConfig();
+
+    rawPipelineModel.forEach(currentPe => {
+      if (!currentPe.settings.disabled) {
+        if (currentPe.type === "stream" || currentPe.type === "set") {
+          this.JsplumbService.dataStreamDropped(
+            currentPe.payload.dom,
+            currentPe.payload as SpDataStream,
+            true,
+            previewConfig
+          );
+        }
+        if (currentPe.type === "sepa") {
+          this.JsplumbService.dataProcessorDropped(
+            currentPe.payload.dom,
+            currentPe.payload as DataProcessorInvocation,
+            true,
+            previewConfig
+          );
+        }
+        if (currentPe.type === "action") {
+          this.JsplumbService.dataSinkDropped(
+            currentPe.payload.dom,
+            currentPe.payload as DataSinkInvocation,
+            true,
+            previewConfig
+          );
         }
+      }
+    });
+
+    this.connectPipelineElements(rawPipelineModel, previewConfig, jsplumbConfig, jsPlumbBridge);
+    if (autoLayout) {
+      this.layoutGraph(
+        targetCanvas,
+        "div[id^='jsplumb']",
+        previewConfig ? 75 : 110,
+        previewConfig
+      );
+    } else if (pipelineCanvasMetadata) {
+      this.layoutGraphFromCanvasMetadata(pipelineCanvasMetadata);
     }
+    jsPlumbBridge.repaintEverything();
+  }
 
-    displayPipeline(rawPipelineModel: PipelineElementConfig[],
-                    targetCanvas,
-                    previewConfig: boolean,
-                    autoLayout: boolean,
-                    pipelineCanvasMetadata?: PipelineCanvasMetadata) {
-        let jsPlumbBridge = this.JsplumbFactoryService.getJsplumbBridge(previewConfig);
-        let jsplumbConfig = previewConfig ? this.JsplumbConfigService.getPreviewConfig() : this.JsplumbConfigService.getEditorConfig();
-        rawPipelineModel.forEach(currentPe => {
-            if (!currentPe.settings.disabled) {
-                if (currentPe.type === "stream" || currentPe.type === "set") {
-                    this.JsplumbService.dataStreamDropped(currentPe.payload.dom,
-                        currentPe.payload as SpDataStream,
-                        true,
-                        previewConfig);
-                }
-                if (currentPe.type === "sepa") {
-                    this.JsplumbService.dataProcessorDropped(currentPe.payload.dom, currentPe.payload as DataProcessorInvocation, true, previewConfig);
-                }
-                if (currentPe.type === "action") {
-                    this.JsplumbService.dataSinkDropped(currentPe.payload.dom, currentPe.payload as DataSinkInvocation, true, previewConfig);
-                }
-            }
-        });
+  layoutGraph(canvasId: string,
+              nodeIdentifier: string,
+              dimension: number,
+              previewConfig: boolean) {
 
-        this.connectPipelineElements(rawPipelineModel, previewConfig, jsplumbConfig, jsPlumbBridge);
-        if (autoLayout) {
-            this.layoutGraph(targetCanvas, "span[id^='jsplumb']", previewConfig ? 75 : 110, previewConfig);
-        } else if (pipelineCanvasMetadata)  {
-            this.layoutGraphFromCanvasMetadata(pipelineCanvasMetadata);
+    let jsPlumbBridge = this.JsplumbFactoryService.getJsplumbBridge(previewConfig);
+    let g = new dagre.graphlib.Graph();
+    g.setGraph({rankdir: "LR", ranksep: previewConfig ? "50" : "100"});
+    g.setDefaultEdgeLabel(function () {
+      return {}
+    });
+    let nodes = $(canvasId).find(nodeIdentifier).get();
+    nodes.forEach((n) => {
+      g.setNode(n.id, {label: n.id, width: dimension, height: dimension});
+    });
+
+    let edges = jsPlumbBridge.getAllConnections() as Connection[];
+    edges.forEach(edge => {
+      g.setEdge(edge.source.id, edge.target.id);
+    });
+
+    dagre.layout(g);
+    g.nodes().forEach(v => {
+      let elementRef = $(`#${v}`);
+      elementRef.css("left", g.node(v).x + "px");
+      elementRef.css("top", g.node(v).y + "px");
+    });
+  }
+
+  layoutGraphFromCanvasMetadata(pipelineCanvasMetadata: PipelineCanvasMetadata) {
+    Object.entries(pipelineCanvasMetadata.pipelineElementMetadata).forEach(
+      ([key, value]) => {
+        let elementRef = $(`#${key}`);
+        if (elementRef) {
+          elementRef.css("left", value.position.x + "px");
+          elementRef.css("top", value.position.y + "px");
         }
-        jsPlumbBridge.repaintEverything();
-    }
+      }
+    );
+  }
 
-    layoutGraph(canvasId: string,
-                nodeIdentifier: string,
-                dimension: number,
-                previewConfig: boolean) {
-        let jsPlumbBridge = this.JsplumbFactoryService.getJsplumbBridge(previewConfig);
-        let g = new dagre.graphlib.Graph();
-        g.setGraph({rankdir: "LR", ranksep: previewConfig ? "50" : "100"});
-        g.setDefaultEdgeLabel(function () {
-            return {};
-        });
-
-        let nodes = $(canvasId).find(nodeIdentifier).get();
-        nodes.forEach((n) => {
-            g.setNode(n.id, {label: n.id, width: dimension, height: dimension});
-        });
-
-        let edges = jsPlumbBridge.getAllConnections();
-        edges.forEach(edge => {
-            g.setEdge(edge.source.id, edge.target.id);
-        });
-
-        dagre.layout(g);
-        g.nodes().forEach(v => {
-            let elementRef = $(`#${v}`);
-            elementRef.css("left", g.node(v).x + "px");
-            elementRef.css("top", g.node(v).y + "px");
-        });
-    }
+  connectPipelineElements(rawPipelineModel: PipelineElementConfig[],
+                          previewConfig: boolean,
+                          jsplumbConfig: any,
+                          jsPlumbBridge: JsplumbBridge) {
+    let source, target;
+    jsPlumbBridge.setSuspendDrawing(true);
+    rawPipelineModel.forEach(pe => {
+      if (pe.type == "sepa" || pe.type == "action") {
+        if (!(pe.settings.disabled) && pe.payload.connectedTo) {
+          pe.payload.connectedTo.forEach((connection, index) => {
+            source = connection;
+            target = pe.payload.dom;
 
-    layoutGraphFromCanvasMetadata(pipelineCanvasMetadata: PipelineCanvasMetadata) {
-        Object.entries(pipelineCanvasMetadata.pipelineElementMetadata).forEach(
-            ([key, value]) => {
-                let elementRef = $(`#${key}`);
-                if (elementRef) {
-                    elementRef.css("left", value.position.x + "px");
-                    elementRef.css("top", value.position.y + "px");
-                }
-            }
-        );
-    }
+            let sourceEndpointId = "out-" + connection;
+            let inTargetEndpointId = "in-" + index + "-" + pe.payload.dom;
+            jsPlumbBridge.connect(
+              {
+                uuids: [sourceEndpointId, inTargetEndpointId],
+                detachable: !previewConfig
+              }
+            );
+            jsPlumbBridge.activateEndpointWithType(sourceEndpointId, true, "token");
+            jsPlumbBridge.activateEndpointWithType(inTargetEndpointId, true, "token");
 
-    connectPipelineElements(rawPipelineModel: PipelineElementConfig[],
-                            previewConfig: boolean,
-                            jsplumbConfig: any,
-                            jsPlumbBridge: JsplumbBridge) {
-        let source, target;
-        jsPlumbBridge.setSuspendDrawing(true);
-        rawPipelineModel.forEach(pe => {
-            if (pe.type == "sepa" || pe.type == "action") {
-                if (!(pe.settings.disabled) && pe.payload.connectedTo) {
-                    pe.payload.connectedTo.forEach((connection, index) => {
-                        source = connection;
-                        target = pe.payload.dom;
-
-                        let sourceEndpointId = "out-" + connection;
-                        let inTargetEndpointId = "in-" + index + "-" + pe.payload.dom;
-                        jsPlumbBridge.connect(
-                            {
-                                uuids: [sourceEndpointId, inTargetEndpointId],
-                                detachable: !previewConfig
-                            }
-                        );
-                        jsPlumbBridge.activateEndpointWithType(sourceEndpointId, true, "token");
-                        jsPlumbBridge.activateEndpointWithType(inTargetEndpointId, true, "token");
-
-                        if (!(pe.payload instanceof DataSinkInvocation) && !(this.ObjectProvider.hasConnectedPipelineElement(pe.payload.dom, rawPipelineModel))) {
-                            let outTargetEndpointId = "out-" + pe.payload.dom;
-                            jsPlumbBridge.activateEndpointWithType(outTargetEndpointId, true, "token");
-                        }
-                    });
-                }
+            if (!(pe.payload instanceof DataSinkInvocation) &&
+              !(this.ObjectProvider.hasConnectedPipelineElement(pe.payload.dom, rawPipelineModel))) {
+              let outTargetEndpointId = "out-" + pe.payload.dom;
+              jsPlumbBridge.activateEndpointWithType(outTargetEndpointId, true, "token");
             }
-        });
-        jsPlumbBridge.setSuspendDrawing(false, true);
-    }
+          });
+        }
+      }
+    });
+    jsPlumbBridge.setSuspendDrawing(false, true);
+  }
 }
diff --git a/ui/src/app/editor/services/pipeline-validation.service.ts b/ui/src/app/editor/services/pipeline-validation.service.ts
index 3ce8951..b3329fe 100644
--- a/ui/src/app/editor/services/pipeline-validation.service.ts
+++ b/ui/src/app/editor/services/pipeline-validation.service.ts
@@ -23,6 +23,7 @@ import { PipelineElementConfig } from '../model/editor.model';
 import { DataProcessorInvocation, DataSinkInvocation } from '../../core-model/gen/streampipes-model';
 import { JsplumbFactoryService } from './jsplumb-factory.service';
 import { UserErrorMessage } from '../../core-model/base/UserErrorMessage';
+import { Connection } from "@jsplumb/core";
 
 @Injectable()
 export class PipelineValidationService {
@@ -31,11 +32,11 @@ export class PipelineValidationService {
     pipelineValid = false;
 
     availableErrorMessages: UserErrorMessage[] = [
-      new UserErrorMessage('Did you add a data stream?', 'Any pipeline needs at least one data stream.'),
-      new UserErrorMessage('Did you add a data sink?', 'Any pipeline needs at least one data sink.'),
-      new UserErrorMessage('Did you connect all elements?', 'No orphaned elements are allowed within a pipeline, make sure to connect all elements.'),
-      new UserErrorMessage('Separate pipelines', 'It seems you\'ve created more than one pipeline at once. Create only one pipeline at a time!'),
-      new UserErrorMessage('Did you configure all elements?', 'There\'s a pipeline element which is missing some configuration.')
+        new UserErrorMessage('Did you add a data stream?', 'Any pipeline needs at least one data stream.'),
+        new UserErrorMessage('Did you add a data sink?', 'Any pipeline needs at least one data sink.'),
+        new UserErrorMessage('Did you connect all elements?', 'No orphaned elements are allowed within a pipeline, make sure to connect all elements.'),
+        new UserErrorMessage('Separate pipelines', 'It seems you\'ve created more than one pipeline at once. Create only one pipeline at a time!'),
+        new UserErrorMessage('Did you configure all elements?', 'There\'s a pipeline element which is missing some configuration.')
     ];
 
     constructor(private jsplumbFactoryService: JsplumbFactoryService) {
@@ -61,10 +62,10 @@ export class PipelineValidationService {
 
         if (!this.isEmptyPipeline(rawPipelineModel)) {
             this.buildErrorMessages(streamInAssembly,
-              actionInAssembly,
-              allElementsConnected,
-              onlyOnePipelineCreated,
-              allElementsConfigured);
+                actionInAssembly,
+                allElementsConnected,
+                onlyOnePipelineCreated,
+                allElementsConfigured);
         } else {
             this.errorMessages = [];
         }
@@ -76,7 +77,7 @@ export class PipelineValidationService {
 
     isEmptyPipeline(rawPipelineModel) {
         return !this.isActionInAssembly(rawPipelineModel) &&
-          !this.isStreamInAssembly(rawPipelineModel) && !this.isInAssembly(rawPipelineModel, 'sepa');
+            !this.isStreamInAssembly(rawPipelineModel) && !this.isInAssembly(rawPipelineModel, 'sepa');
     }
 
     buildErrorMessages(streamInAssembly, actionInAssembly, allElementsConnected, onlyOnePipelineCreated, allElementsConfigured) {
@@ -149,8 +150,7 @@ export class PipelineValidationService {
         g.setDefaultEdgeLabel(function () {
             return {};
         });
-        const nodes = $('#assembly').find('span[id^=\'jsplumb\']').get();
-
+        const nodes = $('#assembly').find('div[id^=\'jsplumb\']').get();
         for (let i = 0; i < nodes.length; i++) {
             const n = nodes[i];
             const elementOptions = this.getElementOptions(n.id, rawPipelineModel);
@@ -163,7 +163,7 @@ export class PipelineValidationService {
                 });
             }
         }
-        const edges = jsplumbBridge.getAllConnections();
+        const edges = jsplumbBridge.getAllConnections() as Connection[];
         edges.forEach((edge, i) => {
             const c = edges[i];
             g.setEdge(c.source.id, c.target.id);
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss
index 4ae48bf..8fcfa66 100644
--- a/ui/src/scss/main.scss
+++ b/ui/src/scss/main.scss
@@ -24,7 +24,7 @@
 @import '~bootstrap/dist/css/bootstrap.css';
 @import '~@fortawesome/fontawesome-free/css/all.css';
 @import '~angular-ui-tree/dist/angular-ui-tree.min.css';
-@import '~jsplumb/css/jsplumbtoolkit-defaults.css';
+@import '~@jsplumb/browser-ui/css/jsplumbtoolkit.css';
 @import '~ng-prettyjson/dist/ng-prettyjson.min.css';
 @import '~prismjs/themes/prism.css';
 @import '~angular-loading-bar/build/loading-bar.min.css';