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 2020/06/12 14:32:05 UTC

[incubator-streampipes] branch STREAMPIPES-145 updated: [STREAMPIPES-145] Migrate pipeline element recommender

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

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


The following commit(s) were added to refs/heads/STREAMPIPES-145 by this push:
     new 2bcad07  [STREAMPIPES-145] Migrate pipeline element recommender
2bcad07 is described below

commit 2bcad07d655a12f34f4c1caf50a0308011f882b7
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Fri Jun 12 16:31:46 2020 +0200

    [STREAMPIPES-145] Migrate pipeline element recommender
---
 .../pipeline-assembly.component.ts                 |  14 +-
 .../pipeline-element-icon-stand.component.ts       |  10 +-
 .../pipeline-element-options.component.html        |   8 +-
 .../pipeline-element-options.component.ts          |  40 +++---
 .../pipeline-element-recommendation.component.html |  34 +++++
 .../pipeline-element-recommendation.component.scss |   0
 .../pipeline-element-recommendation.component.ts   | 144 +++++++++++++++++++++
 .../pipeline-element/pipeline-element.component.ts |   6 +-
 .../components/pipeline/pipeline.component.ts      |  15 ++-
 ui/src/app/editor-v2/editor.module.ts              |   2 +
 ui/src/app/editor-v2/model/editor.model.ts         |   7 +
 ui/src/app/editor-v2/services/editor.service.ts    |  14 +-
 ui/src/app/editor-v2/services/jsplumb.service.ts   |   4 +-
 .../pipeline-element-recommendation.service.ts     |  57 ++------
 14 files changed, 254 insertions(+), 101 deletions(-)

diff --git a/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.ts b/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.ts
index ce9725e..0fbedce 100644
--- a/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.ts
@@ -16,25 +16,15 @@
  *
  */
 
-import {
-    Component, Input,
-    OnInit,
-} from "@angular/core";
+import {Component, Input, OnInit,} from "@angular/core";
 import {JsplumbBridge} from "../../services/jsplumb-bridge.service";
 import {PipelinePositioningService} from "../../services/pipeline-positioning.service";
-import {EditorDialogManager} from "../../services/editor-dialog-manager.service";
 import {PipelineValidationService} from "../../services/pipeline-validation.service";
 import {JsplumbService} from "../../services/jsplumb.service";
 import {RestApi} from "../../../services/rest-api.service";
-import {TransitionService} from "../../../services/transition.service";
 import {ShepherdService} from "../../../services/tour/shepherd.service";
-import {
-    PipelineElementConfig,
-    PipelineElementHolder,
-    PipelineElementUnion
-} from "../../model/editor.model";
+import {PipelineElementConfig, PipelineElementUnion} from "../../model/editor.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 {SavePipelineComponent} from "../../dialog/save-pipeline/save-pipeline.component";
 import {DialogService} from "../../../core-ui/dialog/base-dialog/base-dialog.service";
diff --git a/ui/src/app/editor-v2/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts b/ui/src/app/editor-v2/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
index 574ecb8..b18627b 100644
--- a/ui/src/app/editor-v2/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline-element-icon-stand/pipeline-element-icon-stand.component.ts
@@ -16,17 +16,9 @@
  *
  */
 
-import {
-    Component, Input,
-    OnInit,
-} from "@angular/core";
+import {Component, Input, OnInit,} from "@angular/core";
 import * as angular from "angular";
 import {RestApi} from "../../../services/rest-api.service";
-import {
-    DataProcessorInvocation, DataSinkInvocation,
-    SpDataSet,
-    SpDataStream
-} from "../../../core-model/gen/streampipes-model";
 import {PipelineElementType, PipelineElementUnion} from "../../model/editor.model";
 import {PipelineElementTypeUtils} from "../../utils/editor.utils";
 
diff --git a/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.html b/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.html
index c48a6a3..cca55f1 100644
--- a/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.html
+++ b/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.html
@@ -62,8 +62,8 @@
         {{pipelineElement.payload.name}}
     </div>
 </div>
-<!--<pipeline-element-recommendation raw-pipeline-model="ctrl.rawPipelineModel"-->
-<!--                                 pipeline-element-dom-id="ctrl.pipelineElement.payload.DOM"-->
-<!--                                 recommended-elements="ctrl.recommendedElements"-->
-<!--                                 recommendations-shown="ctrl.recommendationsShown"></pipeline-element-recommendation>-->
+<pipeline-element-recommendation [rawPipelineModel]="rawPipelineModel"
+                                 [pipelineElementDomId]="pipelineElement.payload.dom"
+                                 [recommendedElements]="recommendedElements"
+                                 [recommendationsShown]="recommendationsShown" *ngIf="recommendationsAvailable"></pipeline-element-recommendation>
 
diff --git a/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.ts b/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.ts
index 876c58b..ee8efa4 100644
--- a/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline-element-options/pipeline-element-options.component.ts
@@ -26,11 +26,12 @@ import {PipelineElementRecommendationService} from "../../services/pipeline-elem
 import {ObjectProvider} from "../../services/object-provider.service";
 import {
   InvocablePipelineElementUnion,
-  PipelineElementConfig, PipelineElementType,
+  PipelineElementConfig,
   PipelineElementUnion
 } from "../../model/editor.model";
 import {SpDataStream, WildcardTopicDefinition} from "../../../core-model/gen/streampipes-model";
 import {PipelineElementTypeUtils} from "../../utils/editor.utils";
+import {EditorService} from "../../services/editor.service";
 
 @Component({
   selector: 'pipeline-element-options',
@@ -74,6 +75,7 @@ export class PipelineElementOptionsComponent implements OnInit{
 
   constructor(private ObjectProvider: ObjectProvider,
               private PipelineElementRecommendationService: PipelineElementRecommendationService,
+              private EditorService: EditorService,
               //private InitTooltips: InitTooltips,
               private JsplumbBridge: JsplumbBridge,
               //private EditorDialogManager: EditorDialogManager,
@@ -89,18 +91,18 @@ export class PipelineElementOptionsComponent implements OnInit{
   }
 
   ngOnInit() {
-    // this.$rootScope.$on("SepaElementConfigured", (event, item) => {
-    //   this.pipelineElement.settings.openCustomize = false;
-    //   this.RestApi.updateCachedPipeline(this.rawPipelineModel);
-    //   if (item === this.pipelineElement.payload.DOM) {
-    //     this.initRecs(this.pipelineElement.payload.DOM, this.rawPipelineModel);
-    //   }
-    // });
+    this.EditorService.pipelineElementConfigured$.subscribe(pipelineElementDomId => {
+      this.pipelineElement.settings.openCustomize = false;
+      this.RestApi.updateCachedPipeline(this.rawPipelineModel);
+      if (pipelineElementDomId === this.pipelineElement.payload.dom) {
+        this.initRecs(this.pipelineElement.payload.dom);
+      }
+    });
     let pipelineElementType = PipelineElementTypeUtils.fromType(this.pipelineElement.payload);
     this.pipelineElementCssType = PipelineElementTypeUtils.toCssShortHand(pipelineElementType);
 
     if (this.pipelineElement.type === 'stream') {
-      this.initRecs(this.pipelineElement.payload.dom, this.rawPipelineModel);
+      this.initRecs(this.pipelineElement.payload.dom);
     }
   }
 
@@ -131,16 +133,16 @@ export class PipelineElementOptionsComponent implements OnInit{
     //this.EditorDialogManager.showCustomizeStreamDialog(this.pipelineElement.payload);
   }
 
-  initRecs(elementId, currentPipelineElements) {
-    // var currentPipeline = this.ObjectProvider.makePipeline(angular.copy(currentPipelineElements));
-    // this.PipelineElementRecommendationService.getRecommendations(this.allElements, currentPipeline).then((result) => {
-    //   if (result.success) {
-    //     this.possibleElements = result.possibleElements;
-    //     this.recommendedElements = result.recommendations;
-    //     this.recommendationsAvailable = true;
-    //     //this.InitTooltips.initTooltips();
-    //   }
-    // });
+  initRecs(elementId) {
+    var currentPipeline = this.ObjectProvider.makePipeline(angular.copy(this.rawPipelineModel));
+    this.EditorService.recommendPipelineElement(currentPipeline).subscribe((result) => {
+      if (result.success) {
+        this.possibleElements = this.PipelineElementRecommendationService.collectPossibleElements(this.allElements, result.possibleElements);
+        this.recommendedElements = this.PipelineElementRecommendationService.populateRecommendedList(this.allElements, result.recommendedElements);
+        this.recommendationsAvailable = true;
+        //this.InitTooltips.initTooltips();
+      }
+    });
   }
 
   showRecommendations(e) {
diff --git a/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html b/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html
new file mode 100644
index 0000000..8bc34a1
--- /dev/null
+++ b/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.html
@@ -0,0 +1,34 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div class="cv-wrapper" [ngClass]="recommendationsShown ? 'opened-nav' : ''"
+     *ngIf="recommendedElements.length > 0">
+    <ul>
+        <li *ngFor="let recommendedElement of recommendedElements; index as i"
+            [style]="DomSanitizer.bypassSecurityTrustStyle(recommendationLayout[i].skewStyle)">
+            {{recommendedElement}}
+            <a [style]="DomSanitizer.bypassSecurityTrustStyle(recommendationLayout[i].unskewStyle)" [ngClass]="recommendationLayout[i].type" (click)="create(recommendedElement)" *ngIf="recommendedElement.name">
+            </a>
+            <div (click)="create(recommendedElement)" [style]="DomSanitizer.bypassSecurityTrustStyle(recommendationLayout[i].unskewStyleLabel)"
+                 class="{{recommendationLayout[i].type}}">
+                <pipeline-element [iconSize]="'small'" [pipelineElement]="recommendedElement" *ngIf="recommendedElement.name">
+                </pipeline-element>
+            </div>
+        </li>
+    </ul>
+</div>
diff --git a/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.scss b/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts b/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts
new file mode 100644
index 0000000..2cd25ff
--- /dev/null
+++ b/ui/src/app/editor-v2/components/pipeline-element-recommendation/pipeline-element-recommendation.component.ts
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {JsplumbService} from "../../services/jsplumb.service";
+import {Component, Input, OnInit} from "@angular/core";
+import {PipelineElementConfig, PipelineElementRecommendationLayout} from "../../model/editor.model";
+import {DataProcessorInvocation} from "../../../core-model/gen/streampipes-model";
+import {DomSanitizer} from "@angular/platform-browser";
+
+@Component({
+  selector: 'pipeline-element-recommendation',
+  templateUrl: './pipeline-element-recommendation.component.html',
+  styleUrls: ['./pipeline-element-recommendation.component.scss']
+})
+export class PipelineElementRecommendationComponent implements OnInit {
+
+  @Input()
+  recommendationsShown: boolean;
+
+  @Input()
+  rawPipelineModel: PipelineElementConfig[];
+
+  @Input()
+  pipelineElementDomId: string;
+
+  @Input()
+  recommendedElements: any;
+
+  recommendationLayout: PipelineElementRecommendationLayout[] = [];
+
+  constructor(private JsplumbService: JsplumbService,
+              public DomSanitizer: DomSanitizer) {
+
+  }
+
+  ngOnInit() {
+    this.prepareStyles();
+  }
+
+  prepareStyles() {
+    this.recommendedElements.forEach((element, index) => {
+      let layoutSettings: PipelineElementRecommendationLayout = {
+        skewStyle: element.name ? this.getSkewStyle(index) : {'opacity':0},
+        unskewStyle: this.getUnskewStyle(element, index),
+        unskewStyleLabel: this.getUnskewStyleLabel(index),
+        type: element instanceof DataProcessorInvocation ? "sepa" : "action"
+      };
+      this.recommendationLayout.push(layoutSettings);
+    });
+  }
+
+  create(recommendedElement) {
+    this.recommendationsShown = false;
+    this.JsplumbService.createElement(this.rawPipelineModel, recommendedElement, this.pipelineElementDomId);
+  }
+
+  getUnskewStyle(recommendedElement, index) {
+    var unskew = -(this.getSkew());
+    var rotate = -(90 - (this.getSkew() / 2));
+
+    return {
+      "transform": "skew(" + unskew + "deg)" + " rotate(" + rotate + "deg)" + " scale(1)",
+      "background-color": this.getBackgroundColor(recommendedElement, index)
+    };
+  }
+
+  getBackgroundColor(recommendedElement, index) {
+    var alpha = recommendedElement.weight < 0.2 ? 0.2 : (recommendedElement.weight - 0.2);
+    var 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) {
+    this.fillRemainingItems();
+    // transform: rotate(72deg) skew(18deg);
+    var skew = this.getSkew();
+    var rotate = (index + 1) * this.getAngle();
+
+    return {
+      "transform": "rotate(" + rotate + "deg) skew(" + skew + "deg)"
+    };
+  }
+
+  getUnskewStyleLabel(index) {
+    var unskew = -(this.getSkew());
+    var rotate =  (index + 1) * this.getAngle();
+    var 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() {
+    return (90 - this.getAngle());
+  }
+
+  getAngle() {
+    return (360 / this.recommendedElements.length);
+  }
+
+  fillRemainingItems() {
+    if (this.recommendedElements.length < 6) {
+      for (var i = this.recommendedElements.length; i < 6; i++) {
+        this.recommendedElements.push({fakeElement: true});
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/components/pipeline-element/pipeline-element.component.ts b/ui/src/app/editor-v2/components/pipeline-element/pipeline-element.component.ts
index 00620aa..f065d86 100644
--- a/ui/src/app/editor-v2/components/pipeline-element/pipeline-element.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline-element/pipeline-element.component.ts
@@ -16,11 +16,7 @@
  *
  */
 
-import {
-    Component, Input,
-    OnInit,
-} from "@angular/core";
-import * as angular from "angular";
+import {Component, Input, OnInit,} from "@angular/core";
 import {RestApi} from "../../../services/rest-api.service";
 import {ElementIconText} from "../../../services/get-element-icon-text.service";
 import {ImageChecker} from "../../../services/image-checker.service";
diff --git a/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts b/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
index be758e7..29e0c16 100644
--- a/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
@@ -24,9 +24,9 @@ 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, InjectionToken, Input, OnInit, Pipe} from "@angular/core";
+import {Component, Input, OnInit} from "@angular/core";
 import {
-  InvocablePipelineElementUnion, PIPELINE_ELEMENT_TOKEN,
+  InvocablePipelineElementUnion,
   PipelineElementConfig,
   PipelineElementUnion
 } from "../../model/editor.model";
@@ -40,6 +40,7 @@ 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";
 
 @Component({
   selector: 'pipeline',
@@ -86,6 +87,7 @@ export class PipelineComponent implements OnInit {
               private PipelineEditorService: PipelineEditorService,
               private JsplumbBridge: JsplumbBridge,
               private ObjectProvider: ObjectProvider,
+              private EditorService: EditorService,
               //DialogBuilder,
               //EditorDialogManager,
               // TransitionService,
@@ -302,6 +304,7 @@ export class PipelineComponent implements OnInit {
                   if ((payload.staticProperties && payload.staticProperties.length > 0) || this.isCustomOutput(pe)) {
                     this.showCustomizeDialog(pe);
                   } else {
+                    this.announceConfiguredElement(pe);
                     //this.$rootScope.$broadcast("SepaElementConfigured", pe.payload.DOM);
                     (pe.payload as InvocablePipelineElementUnion).configured = true;
                   }
@@ -363,9 +366,15 @@ export class PipelineComponent implements OnInit {
     });
 
     dialogRef.afterClosed().subscribe(c => {
-      this.JsplumbService.activateEndpoint(pipelineElement.payload.dom, pipelineElement.settings.completed)
+      if (c) {
+        this.JsplumbService.activateEndpoint(pipelineElement.payload.dom, pipelineElement.settings.completed)
+      }
     });
   }
 
+  announceConfiguredElement(pe: PipelineElementConfig) {
+    this.EditorService.announceConfiguredElement(pe.payload.dom);
+  }
+
 
 }
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/editor.module.ts b/ui/src/app/editor-v2/editor.module.ts
index 19f5141..8845c91 100644
--- a/ui/src/app/editor-v2/editor.module.ts
+++ b/ui/src/app/editor-v2/editor.module.ts
@@ -49,6 +49,7 @@ import {CustomizeComponent} from "./dialog/customize/customize.component";
 import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
 import {CoreUiModule} from "../core-ui/core-ui.module";
 import {SavePipelineComponent} from "./dialog/save-pipeline/save-pipeline.component";
+import {PipelineElementRecommendationComponent} from "./components/pipeline-element-recommendation/pipeline-element-recommendation.component";
 
 @NgModule({
     imports: [
@@ -71,6 +72,7 @@ import {SavePipelineComponent} from "./dialog/save-pipeline/save-pipeline.compon
         PipelineElementIconStandComponent,
         PipelineElementComponent,
         PipelineElementOptionsComponent,
+        PipelineElementRecommendationComponent,
         PipelineComponent,
         SavePipelineComponent
     ],
diff --git a/ui/src/app/editor-v2/model/editor.model.ts b/ui/src/app/editor-v2/model/editor.model.ts
index 8f336ea..50e6db4 100644
--- a/ui/src/app/editor-v2/model/editor.model.ts
+++ b/ui/src/app/editor-v2/model/editor.model.ts
@@ -46,6 +46,13 @@ export interface PipelineElementConfig {
   payload: PipelineElementUnion
 }
 
+export interface PipelineElementRecommendationLayout {
+  skewStyle: any;
+  unskewStyle: any;
+  unskewStyleLabel: any;
+  type: string
+}
+
 export enum PipelineElementType {
   DataSet,
   DataStream,
diff --git a/ui/src/app/editor-v2/services/editor.service.ts b/ui/src/app/editor-v2/services/editor.service.ts
index 6f34eb1..ed44cd5 100644
--- a/ui/src/app/editor-v2/services/editor.service.ts
+++ b/ui/src/app/editor-v2/services/editor.service.ts
@@ -24,15 +24,18 @@ import {
     DataProcessorInvocation, PipelineElementRecommendationMessage,
     PipelineModificationMessage
 } from "../../core-model/gen/streampipes-model";
-import {Observable} from "rxjs";
+import {Observable, Subject} from "rxjs";
 import {PlatformServicesCommons} from "../../platform-services/apis/commons.service";
 
 @Injectable()
 export class EditorService {
 
+    private pipelineElementConfigured = new Subject<string>();
+
+    public pipelineElementConfigured$ = this.pipelineElementConfigured.asObservable();
+
     constructor(private http: HttpClient,
-                private platformServicesCommons: PlatformServicesCommons,
-                private authStatusService: AuthStatusService) {
+                private platformServicesCommons: PlatformServicesCommons) {
     }
 
     recommendPipelineElement(pipeline): Observable<PipelineElementRecommendationMessage> {
@@ -63,6 +66,11 @@ export class EditorService {
         return this.platformServicesCommons.authUserBasePath() + '/pipelines'
     }
 
+    announceConfiguredElement(pipelineElementDomId: string) {
+        this.pipelineElementConfigured.next(pipelineElementDomId);
+    }
+
+
 
 
 }
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/services/jsplumb.service.ts b/ui/src/app/editor-v2/services/jsplumb.service.ts
index 2efb534..4df54c5 100644
--- a/ui/src/app/editor-v2/services/jsplumb.service.ts
+++ b/ui/src/app/editor-v2/services/jsplumb.service.ts
@@ -31,9 +31,7 @@ import {
 @Injectable()
 export class JsplumbService {
 
-    apiConstants: any;
     idCounter: any;
-    $timeout: any;
     RestApi: any;
 
     constructor(private JsplumbConfigService: JsplumbConfigService,
@@ -95,7 +93,7 @@ export class JsplumbService {
         var pipelineElementDom = $("#" + pipelineElementDomId);
         var pipelineElementConfig = this.createNewPipelineElementConfigWithFixedCoordinates(pipelineElementDom, pipelineElement, false);
         pipelineModel.push(pipelineElementConfig);
-        this.$timeout(() => {
+        setTimeout(() => {
             this.createAssemblyElement(pipelineElementConfig.payload.dom, pipelineElementConfig.payload, pipelineElementDom);
         });
     }
diff --git a/ui/src/app/editor-v2/services/pipeline-element-recommendation.service.ts b/ui/src/app/editor-v2/services/pipeline-element-recommendation.service.ts
index 64344af..8e16eba 100644
--- a/ui/src/app/editor-v2/services/pipeline-element-recommendation.service.ts
+++ b/ui/src/app/editor-v2/services/pipeline-element-recommendation.service.ts
@@ -19,6 +19,12 @@
 import * as angular from 'angular';
 import {Injectable} from "@angular/core";
 import {EditorService} from "./editor.service";
+import {PipelineElementUnion} from "../model/editor.model";
+import {
+    InvocableStreamPipesEntity,
+    PipelineElementRecommendation,
+    SpDataStream
+} from "../../core-model/gen/streampipes-model";
 
 @Injectable()
 export class PipelineElementRecommendationService {
@@ -26,29 +32,10 @@ export class PipelineElementRecommendationService {
     constructor(private EditorService: EditorService) {
     }
 
-    getRecommendations(allElements, currentPipeline) {
-        return new Promise((resolve, reject) => {
-            this.EditorService.recommendPipelineElement(currentPipeline)
-                .subscribe(msg => {
-                    if (msg.success) {
-                        var result = {};
-                        result["success"] = true;
-                        result['recommendations'] = this.populateRecommendedList(allElements, msg.recommendedElements);
-                        result['possibleElements'] = this.collectPossibleElements(allElements, msg.possibleElements);
-                        resolve(result);
-                    } else {
-                        // TODO improve
-                        var noresult = {success: false};
-                        resolve(noresult);
-                    }
-                });
-        });
-    }
-
-    collectPossibleElements(allElements, possibleElements) {
+    collectPossibleElements(allElements: PipelineElementUnion[], possibleElements: PipelineElementRecommendation[]) {
         var possibleElementConfigs = [];
         angular.forEach(possibleElements, pe => {
-            possibleElementConfigs.push(this.getPipelineElementContents(allElements, pe.elementId));
+            possibleElementConfigs.push(this.getPipelineElementContents(allElements, pe.elementId)[0]);
         })
         return possibleElementConfigs;
     }
@@ -62,32 +49,16 @@ export class PipelineElementRecommendationService {
         var el;
         for (var i = 0; i < maxRecs; i++) {
             el = recs[i];
-            var element = this.getPipelineElementContents(allElements, el.elementId);
-            element.weight = el.weight;
+            var element = this.getPipelineElementContents(allElements, el.elementId)[0];
+            (element as any).weight = el.weight;
             elementRecommendations.push(element);
         }
         return elementRecommendations;
 
     }
 
-    getPipelineElementContents(allElements, belongsTo) {
-        var pipelineElement = undefined;
-        angular.forEach(allElements, category => {
-            angular.forEach(category, sepa => {
-                if (sepa.type != 'stream') {
-                    if (sepa.belongsTo == belongsTo) {
-                        pipelineElement = sepa;
-                    }
-                } else {
-                    if (sepa.elementId == belongsTo) {
-                        pipelineElement = sepa;
-                    }
-                }
-            });
-        });
-        return pipelineElement;
+    getPipelineElementContents(allElements: PipelineElementUnion[], belongsTo: string) {
+        return allElements
+                .filter(pe => (pe instanceof SpDataStream && pe.elementId === belongsTo) || (pe instanceof InvocableStreamPipesEntity && pe.belongsTo === belongsTo));
     }
-
-}
-
-PipelineElementRecommendationService.$inject=['RestApi']
\ No newline at end of file
+}
\ No newline at end of file