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 08:22:12 UTC

[incubator-streampipes] branch STREAMPIPES-145 updated (c2f4e9f -> d2c63f9)

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

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


    from c2f4e9f  [STREAMPIPES-145] Move dialog templates to core-ui module
     new a011635  [STREAMPIPES-145] Migrate pipeline validation handling
     new d2c63f9  [STREAMPIPES-145] Migrate pipeline start dialog

The 2 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.


Summary of changes:
 .../model/pipeline/PipelineCategory.java           |   2 +
 .../model/pipeline/PipelineOperationStatus.java    |   3 +
 .../streampipes/rest/impl/PipelineCategory.java    |  12 +-
 .../rest/impl/PipelineElementCategory.java         |  19 +--
 .../rest/impl/PipelineWithUserResource.java        |  10 +-
 ui/src/app/NS/XS.service.ts                        |   2 +-
 .../static-property.component.html                 |   1 +
 ui/src/app/core-model/gen/streampipes-model.ts     |  71 ++++++++++-
 .../pipeline-assembly.component.html               |   2 +-
 .../pipeline-assembly.component.ts                 |  19 ++-
 .../components/pipeline/pipeline.component.html    |   2 +-
 .../components/pipeline/pipeline.component.ts      |  11 +-
 .../dialog/customize/customize.component.css       |  40 ------
 .../dialog/customize/customize.component.scss}     |  16 +--
 .../dialog/customize/customize.component.ts        |   5 +-
 .../save-pipeline/save-pipeline.component.html     |  65 ++++++++++
 .../save-pipeline/save-pipeline.component.scss     |  12 +-
 .../save-pipeline/save-pipeline.component.ts       | 137 +++++++++++++++++++++
 ui/src/app/editor-v2/editor.module.ts              |   4 +-
 ui/src/app/editor-v2/model/editor.model.ts         |   3 +-
 ui/src/app/editor-v2/services/editor.service.ts    |  16 ++-
 ui/src/app/editor-v2/services/jsplumb.service.ts   |   1 +
 .../services/pipeline-validation.service.ts        |   4 +-
 .../apis/commons.service.ts}                       |  23 ++--
 .../apis/pipeline-element.service.ts               |  13 +-
 .../app/platform-services/apis/pipeline.service.ts |  89 +++++++++++++
 .../contants/pipeline-element-constants.ts         |  18 ---
 .../contants/platform-services.constants.ts}       |   5 +-
 ui/src/app/platform-services/platform.module.ts    |   6 +-
 ui/src/scss/sp/dialog.scss                         |   2 +
 .../sp/sp-dialog.scss}                             |  18 ++-
 31 files changed, 489 insertions(+), 142 deletions(-)
 delete mode 100644 ui/src/app/editor-v2/dialog/customize/customize.component.css
 copy ui/src/app/{dashboard/components/panel/dashboard-panel.component.css => editor-v2/dialog/customize/customize.component.scss} (86%)
 create mode 100644 ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.html
 copy streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/NoValidConnectionException.java => ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.scss (84%)
 create mode 100644 ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.ts
 copy ui/src/app/{dashboard/services/resize.service.ts => platform-services/apis/commons.service.ts} (71%)
 create mode 100644 ui/src/app/platform-services/apis/pipeline.service.ts
 delete mode 100644 ui/src/app/platform-services/contants/pipeline-element-constants.ts
 copy ui/src/app/{connect/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.css => platform-services/contants/platform-services.constants.ts} (94%)
 copy ui/src/{app/connect/schema-editor/event-property/event-property.component.css => scss/sp/sp-dialog.scss} (81%)


[incubator-streampipes] 01/02: [STREAMPIPES-145] Migrate pipeline validation handling

Posted by ri...@apache.org.
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

commit a0116357615b74fd3a4e4d42d0c2cc0a91b2f464
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Thu Jun 11 16:05:30 2020 +0200

    [STREAMPIPES-145] Migrate pipeline validation handling
---
 ui/src/app/NS/XS.service.ts                                   |  2 +-
 .../connect/static-properties/static-property.component.html  |  1 +
 .../pipeline-assembly/pipeline-assembly.component.html        |  2 +-
 .../app/editor-v2/components/pipeline/pipeline.component.html |  2 +-
 .../app/editor-v2/components/pipeline/pipeline.component.ts   | 11 +++--------
 ui/src/app/editor-v2/dialog/customize/customize.component.ts  |  3 ++-
 ui/src/app/editor-v2/model/editor.model.ts                    |  3 ++-
 ui/src/app/editor-v2/services/jsplumb.service.ts              |  1 +
 ui/src/app/editor-v2/services/pipeline-validation.service.ts  |  4 +++-
 9 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/ui/src/app/NS/XS.service.ts b/ui/src/app/NS/XS.service.ts
index e5bbd1e..6323702 100644
--- a/ui/src/app/NS/XS.service.ts
+++ b/ui/src/app/NS/XS.service.ts
@@ -23,7 +23,7 @@ export class xsService {
 
   XS_STRING: string = "xs:string";
   XS_INTEGER: string = "http://www.w3.org/2001/XMLSchema#integer";
-  XS_DOUBLE: string = "http://www.w3.org/2001/XMLSchema#:double";
+  XS_DOUBLE: string = "http://www.w3.org/2001/XMLSchema#double";
   XS_BOOLEAN: string = "http://www.w3.org/2001/XMLSchema#boolean";
   XS_NUMBER: string = "http://www.w3.org/2001/XMLSchema#number";
   XS_STRING1: string = "http://www.w3.org/2001/XMLSchema#string";
diff --git a/ui/src/app/connect/static-properties/static-property.component.html b/ui/src/app/connect/static-properties/static-property.component.html
index b069b61..2fde087 100644
--- a/ui/src/app/connect/static-properties/static-property.component.html
+++ b/ui/src/app/connect/static-properties/static-property.component.html
@@ -85,4 +85,5 @@
 </app-static-collection>
 <mat-divider></mat-divider>
 
+{{staticProperty.internalName}}
 
diff --git a/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.html b/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.html
index 5680b95..a3fa2b6 100644
--- a/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.html
+++ b/ui/src/app/editor-v2/components/pipeline-assembly/pipeline-assembly.component.html
@@ -21,7 +21,7 @@
         <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center">
             <button mat-button matTooltip="Save Pipeline" [matTooltipPosition]="'above'"
                     style="display:flex;align-items:center;" class="md-button settings-bar-icon-button"
-                    [disabled]="!pipelineValid"
+                    [disabled]="!PipelineValidationService.pipelineValid"
                     (click)="submit()" type="submit">
                 <mat-icon>save</mat-icon>&nbsp;Save pipeline
             </button>
diff --git a/ui/src/app/editor-v2/components/pipeline/pipeline.component.html b/ui/src/app/editor-v2/components/pipeline/pipeline.component.html
index ccf4572..fbcd494 100644
--- a/ui/src/app/editor-v2/components/pipeline/pipeline.component.html
+++ b/ui/src/app/editor-v2/components/pipeline/pipeline.component.html
@@ -26,7 +26,7 @@
                  <mat-spinner [mode]="'indeterminate'" class="pipeline-element-progress" [diameter]="40"></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.payload.uncompleted">
+            <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>
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 a0dbc2c..be758e7 100644
--- a/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
+++ b/ui/src/app/editor-v2/components/pipeline/pipeline.component.ts
@@ -110,6 +110,8 @@ export class PipelineComponent implements OnInit {
   validatePipeline() {
     //this.$timeout(() => {
       this.pipelineValid = this.PipelineValidationService.isValidPipeline(this.rawPipelineModel);
+      console.log("validating");
+      console.log(this.pipelineValid);
     //}, 200);
   }
 
@@ -361,15 +363,8 @@ export class PipelineComponent implements OnInit {
     });
 
     dialogRef.afterClosed().subscribe(c => {
-      console.log("after close");
+      this.JsplumbService.activateEndpoint(pipelineElement.payload.dom, pipelineElement.settings.completed)
     });
-
-    // this.EditorDialogManager.showCustomizeDialog($("#" +pe.payload.dom), sourceEndpoint, pe.payload, false)
-    //     .then(() => {
-    //       this.JsplumbService.activateEndpoint(pe.payload.dom, !payload.uncompleted);
-    //     }, () => {
-    //       this.JsplumbService.activateEndpoint(pe.payload.dom, !payload.uncompleted);
-    //     });
   }
 
 
diff --git a/ui/src/app/editor-v2/dialog/customize/customize.component.ts b/ui/src/app/editor-v2/dialog/customize/customize.component.ts
index 788d35e..d6b44e4 100644
--- a/ui/src/app/editor-v2/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor-v2/dialog/customize/customize.component.ts
@@ -75,11 +75,12 @@ export class CustomizeComponent implements OnInit {
 
   save() {
     this.pipelineElement.payload = this.cachedPipelineElement;
+    this.pipelineElement.settings.completed = true;
+    this.pipelineElement.payload.configured = true;
     this.dialogRef.close(this.pipelineElement);
   }
 
   validConfiguration(event: any) {
-
   }
 
 }
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/model/editor.model.ts b/ui/src/app/editor-v2/model/editor.model.ts
index d09d2d6..8f336ea 100644
--- a/ui/src/app/editor-v2/model/editor.model.ts
+++ b/ui/src/app/editor-v2/model/editor.model.ts
@@ -36,7 +36,8 @@ export interface PipelineElementConfig {
     displaySettings: string,
     connectable: string,
     disabled: boolean,
-    loadingStatus: boolean
+    loadingStatus: boolean,
+    completed: boolean
     position: {
       x: number,
       y: number
diff --git a/ui/src/app/editor-v2/services/jsplumb.service.ts b/ui/src/app/editor-v2/services/jsplumb.service.ts
index 2c773e5..2efb534 100644
--- a/ui/src/app/editor-v2/services/jsplumb.service.ts
+++ b/ui/src/app/editor-v2/services/jsplumb.service.ts
@@ -156,6 +156,7 @@ export class JsplumbService {
         pipelineElementConfig.settings = {connectable: connectable,
             openCustomize: !(pipelineElement as any).configured,
             preview: isPreview,
+            completed: (pipelineElement instanceof SpDataStream || isPreview),
             disabled: false,
             loadingStatus: false,
             displaySettings: displaySettings,
diff --git a/ui/src/app/editor-v2/services/pipeline-validation.service.ts b/ui/src/app/editor-v2/services/pipeline-validation.service.ts
index 59901c5..ea335e9 100644
--- a/ui/src/app/editor-v2/services/pipeline-validation.service.ts
+++ b/ui/src/app/editor-v2/services/pipeline-validation.service.ts
@@ -26,6 +26,7 @@ import {PipelineElementConfig} from "../model/editor.model";
 export class PipelineValidationService {
 
     errorMessages: any = [];
+    pipelineValid: boolean = false;
 
     availableErrorMessages: any = [
         {title: "Did you add a data stream?", content: "Any pipeline needs at least one data stream."},
@@ -58,7 +59,8 @@ export class PipelineValidationService {
             this.errorMessages = [];
         }
 
-        return streamInAssembly && actionInAssembly && allElementsConnected && onlyOnePipelineCreated;
+        this.pipelineValid = streamInAssembly && actionInAssembly && allElementsConnected && onlyOnePipelineCreated;
+        return this.pipelineValid;
     }
 
     isEmptyPipeline(rawPipelineModel) {


[incubator-streampipes] 02/02: [STREAMPIPES-145] Migrate pipeline start dialog

Posted by ri...@apache.org.
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

commit d2c63f9b96728fe9a260ce4db488a86a6558df7f
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Fri Jun 12 10:21:57 2020 +0200

    [STREAMPIPES-145] Migrate pipeline start dialog
---
 .../model/pipeline/PipelineCategory.java           |   2 +
 .../model/pipeline/PipelineOperationStatus.java    |   3 +
 .../streampipes/rest/impl/PipelineCategory.java    |  12 +-
 .../rest/impl/PipelineElementCategory.java         |  19 +--
 .../rest/impl/PipelineWithUserResource.java        |  10 +-
 ui/src/app/core-model/gen/streampipes-model.ts     |  71 ++++++++++-
 .../pipeline-assembly.component.ts                 |  19 ++-
 ...mize.component.css => customize.component.scss} |  17 +--
 .../dialog/customize/customize.component.ts        |   2 +-
 .../save-pipeline/save-pipeline.component.html     |  65 ++++++++++
 .../save-pipeline/save-pipeline.component.scss}    |  11 ++
 .../save-pipeline/save-pipeline.component.ts       | 137 +++++++++++++++++++++
 ui/src/app/editor-v2/editor.module.ts              |   4 +-
 ui/src/app/editor-v2/services/editor.service.ts    |  16 ++-
 .../apis/commons.service.ts}                       |  34 +++--
 .../apis/pipeline-element.service.ts               |  13 +-
 .../app/platform-services/apis/pipeline.service.ts |  89 +++++++++++++
 ...constants.ts => platform-services.constants.ts} |   4 +
 ui/src/app/platform-services/platform.module.ts    |   6 +-
 ui/src/scss/sp/dialog.scss                         |   2 +
 .../sp/sp-dialog.scss}                             |  18 ++-
 21 files changed, 478 insertions(+), 76 deletions(-)

diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineCategory.java b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineCategory.java
index b5599bd..364dfb8 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineCategory.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineCategory.java
@@ -19,7 +19,9 @@
 package org.apache.streampipes.model.pipeline;
 
 import com.google.gson.annotations.SerializedName;
+import org.apache.streampipes.model.shared.annotation.TsModel;
 
+@TsModel
 public class PipelineCategory {
 
 	private String categoryName;
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineOperationStatus.java b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineOperationStatus.java
index 4f4a1d0..575bfaf 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineOperationStatus.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineOperationStatus.java
@@ -18,9 +18,12 @@
 
 package org.apache.streampipes.model.pipeline;
 
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
 import java.util.ArrayList;
 import java.util.List;
 
+@TsModel
 public class PipelineOperationStatus {
 
 	private String pipelineId;
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCategory.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCategory.java
index 66070e2..5ac049e 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCategory.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineCategory.java
@@ -19,14 +19,10 @@
 package org.apache.streampipes.rest.impl;
 
 import org.apache.streampipes.model.message.Notifications;
+import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
 import org.apache.streampipes.storage.api.IPipelineCategoryStorage;
 
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
@@ -35,6 +31,7 @@ public class PipelineCategory extends AbstractRestInterface {
 
 	@GET
 	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	public Response getCategories(@PathParam("username") String username) {
 		return ok(getPipelineCategoryStorage()
 				.getPipelineCategories());
@@ -42,6 +39,8 @@ public class PipelineCategory extends AbstractRestInterface {
 	
 	@POST
 	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	public Response addCategory(@PathParam("username") String username, org.apache.streampipes.model.pipeline.PipelineCategory pipelineCategory) {
 		boolean success = getPipelineCategoryStorage()
 				.addPipelineCategory(pipelineCategory);
@@ -52,6 +51,7 @@ public class PipelineCategory extends AbstractRestInterface {
 	@DELETE
 	@Path("/{categoryId}")
 	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	public Response removeCategory(@PathParam("username") String username, @PathParam("categoryId") String categoryId) {
 		boolean success = getPipelineCategoryStorage()
 				.deletePipelineCategory(categoryId);
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementCategory.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementCategory.java
index fb2a783..06aee1d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementCategory.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementCategory.java
@@ -24,22 +24,24 @@ import org.apache.streampipes.model.DataSinkType;
 import org.apache.streampipes.model.client.Category;
 import org.apache.streampipes.model.graph.DataSourceDescription;
 import org.apache.streampipes.rest.api.IPipelineElementCategory;
+import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
 import org.apache.streampipes.storage.management.StorageManager;
 
-import java.util.List;
-import java.util.stream.Collectors;
-
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @Path("/v2/categories")
 public class PipelineElementCategory extends AbstractRestInterface implements IPipelineElementCategory {
 
 	@GET
 	@Path("/ep")
-	@Produces("application/json")
+	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	@Override
 	public Response getEps() {
 		return ok(makeCategories(StorageManager.INSTANCE.getPipelineElementStorage().getAllDataSources()));
@@ -47,7 +49,8 @@ public class PipelineElementCategory extends AbstractRestInterface implements IP
 
 	@GET
 	@Path("/epa")
-	@Produces("application/json")
+	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	@Override
 	public Response getEpaCategories() {
 		return ok(DataProcessorType.values());
@@ -55,7 +58,8 @@ public class PipelineElementCategory extends AbstractRestInterface implements IP
 
 	@GET
 	@Path("/adapter")
-	@Produces("application/json")
+	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	@Override
 	public Response getAdapterCategories() {
 		return ok(AdapterType.values());
@@ -63,7 +67,8 @@ public class PipelineElementCategory extends AbstractRestInterface implements IP
 
 	@GET
 	@Path("/ec")
-	@Produces("application/json")
+	@Produces(MediaType.APPLICATION_JSON)
+	@JacksonSerialized
 	@Override
 	public Response getEcCategories() {
 		return ok(DataSinkType.values());
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
index 5f7399a..4854c69 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineWithUserResource.java
@@ -64,7 +64,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/own")
-    @GsonWithIds
+    @JacksonSerialized
     @Override
     public Response getOwn(@PathParam("username") String username) {
         return ok(getUserService()
@@ -74,7 +74,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/system")
-    @GsonWithIds
+    @JacksonSerialized
     @Override
     public Response getSystemPipelines() {
         return ok(getPipelineStorage().getSystemPipelines());
@@ -127,7 +127,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
     @Path("/{pipelineId}/start")
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @GsonWithIds
+    @JacksonSerialized
     public Response start(@PathParam("username") String username, @PathParam("pipelineId") String pipelineId) {
         try {
             Pipeline pipeline = getPipelineStorage()
@@ -143,7 +143,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
     @Path("/{pipelineId}/stop")
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @GsonWithIds
+    @JacksonSerialized
     public Response stop(@PathParam("username") String username, @PathParam("pipelineId") String pipelineId) {
         logger.info("User: " + username + " stopped pipeline: " + pipelineId);
         PipelineManagement pm = new PipelineManagement();
@@ -152,7 +152,7 @@ public class PipelineWithUserResource extends AbstractRestInterface implements I
 
     @POST
     @Produces(MediaType.APPLICATION_JSON)
-    @GsonWithIds
+    @JacksonSerialized
     public Response addPipeline(@PathParam("username") String username, Pipeline pipeline) {
         String pipelineId = UUID.randomUUID().toString();
         pipeline.setPipelineId(pipelineId);
diff --git a/ui/src/app/core-model/gen/streampipes-model.ts b/ui/src/app/core-model/gen/streampipes-model.ts
index 252605e..4d383f7 100644
--- a/ui/src/app/core-model/gen/streampipes-model.ts
+++ b/ui/src/app/core-model/gen/streampipes-model.ts
@@ -1,7 +1,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.23.603 on 2020-06-10 11:14:31.
+// Generated using typescript-generator version 2.23.603 on 2020-06-11 23:05:01.
 
 export class AbstractStreamPipesEntity {
     "@class": "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStreamDescription" | "org.apache.streampipes.model.connect.adapter.G [...]
@@ -133,8 +133,8 @@ export class NamedStreamPipesEntity extends AbstractStreamPipesEntity {
         instance.includedLocales = __getCopyArrayFn(__identity<string>())(data.includedLocales);
         instance.applicationLinks = __getCopyArrayFn(ApplicationLink.fromData)(data.applicationLinks);
         instance.connectedTo = __getCopyArrayFn(__identity<string>())(data.connectedTo);
-        instance.dom = data.dom;
         instance.uri = data.uri;
+        instance.dom = data.dom;
         return instance;
     }
 }
@@ -169,9 +169,9 @@ export class AdapterDescription extends NamedStreamPipesEntity {
         instance.config = __getCopyArrayFn(StaticProperty.fromDataUnion)(data.config);
         instance.rules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.rules);
         instance.category = __getCopyArrayFn(__identity<string>())(data.category);
+        instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
         instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules);
         instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules);
-        instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
         instance.couchDBId = data.couchDBId;
         instance._rev = data._rev;
         return instance;
@@ -1378,9 +1378,9 @@ export class GenericAdapterSetDescription extends AdapterSetDescription implemen
         }
         const instance = target || new GenericAdapterSetDescription();
         super.fromData(data, instance);
-        instance.eventSchema = EventSchema.fromData(data.eventSchema);
         instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+        instance.eventSchema = EventSchema.fromData(data.eventSchema);
         return instance;
     }
 }
@@ -1397,9 +1397,9 @@ export class GenericAdapterStreamDescription extends AdapterStreamDescription im
         }
         const instance = target || new GenericAdapterStreamDescription();
         super.fromData(data, instance);
-        instance.eventSchema = EventSchema.fromData(data.eventSchema);
         instance.formatDescription = FormatDescription.fromData(data.formatDescription);
         instance.protocolDescription = ProtocolDescription.fromData(data.protocolDescription);
+        instance.eventSchema = EventSchema.fromData(data.eventSchema);
         return instance;
     }
 }
@@ -1791,6 +1791,25 @@ export class Pipeline extends ElementComposition {
     }
 }
 
+export class PipelineCategory {
+    categoryDescription: string;
+    categoryId: string;
+    categoryName: string;
+    rev: string;
+
+    static fromData(data: PipelineCategory, target?: PipelineCategory): PipelineCategory {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new PipelineCategory();
+        instance.categoryName = data.categoryName;
+        instance.categoryDescription = data.categoryDescription;
+        instance.categoryId = data.categoryId;
+        instance.rev = data.rev;
+        return instance;
+    }
+}
+
 export class PipelineElementRecommendation {
     count: number;
     description: string;
@@ -1829,6 +1848,25 @@ export class PipelineElementRecommendationMessage {
     }
 }
 
+export class PipelineElementStatus {
+    elementId: string;
+    elementName: string;
+    optionalMessage: string;
+    success: boolean;
+
+    static fromData(data: PipelineElementStatus, target?: PipelineElementStatus): PipelineElementStatus {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new PipelineElementStatus();
+        instance.elementId = data.elementId;
+        instance.elementName = data.elementName;
+        instance.optionalMessage = data.optionalMessage;
+        instance.success = data.success;
+        return instance;
+    }
+}
+
 export class PipelineModification {
     domId: string;
     elementId: string;
@@ -1864,6 +1902,27 @@ export class PipelineModificationMessage extends Message {
     }
 }
 
+export class PipelineOperationStatus {
+    elementStatus: PipelineElementStatus[];
+    pipelineId: string;
+    pipelineName: string;
+    success: boolean;
+    title: string;
+
+    static fromData(data: PipelineOperationStatus, target?: PipelineOperationStatus): PipelineOperationStatus {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new PipelineOperationStatus();
+        instance.pipelineId = data.pipelineId;
+        instance.pipelineName = data.pipelineName;
+        instance.title = data.title;
+        instance.success = data.success;
+        instance.elementStatus = __getCopyArrayFn(PipelineElementStatus.fromData)(data.elementStatus);
+        return instance;
+    }
+}
+
 export class Precision extends EventPropertyQualityDefinition {
     "@class": "org.apache.streampipes.model.quality.Precision";
     quantityValue: number;
@@ -2196,8 +2255,8 @@ export class SpDataSet extends SpDataStream {
         instance.supportedGrounding = EventGrounding.fromData(data.supportedGrounding);
         instance.datasetInvocationId = data.datasetInvocationId;
         instance.correspondingPipeline = data.correspondingPipeline;
-        instance.brokerHostname = data.brokerHostname;
         instance.actualTopicName = data.actualTopicName;
+        instance.brokerHostname = data.brokerHostname;
         return instance;
     }
 }
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 62c10a4..ce9725e 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
@@ -33,6 +33,11 @@ import {
     PipelineElementHolder,
     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";
 
 
 @Component({
@@ -43,7 +48,6 @@ import {
 export class PipelineAssemblyComponent implements OnInit {
 
     PipelineEditorService: any;
-    ObjectProvider: any;
     DialogBuilder: any;
     currentMouseOverElement: any;
     currentZoomLevel: any;
@@ -74,12 +78,14 @@ export class PipelineAssemblyComponent implements OnInit {
 
     constructor(private JsplumbBridge: JsplumbBridge,
                 private PipelinePositioningService: PipelinePositioningService,
+                private ObjectProvider: ObjectProvider,
                 //private EditorDialogManager: EditorDialogManager,
                 public PipelineValidationService: PipelineValidationService,
                 private RestApi: RestApi,
                 private JsplumbService: JsplumbService,
                 //private TransitionService: TransitionService,
-                private ShepherdService: ShepherdService) {
+                private ShepherdService: ShepherdService,
+                private dialogService: DialogService) {
 
         this.selectMode = true;
         this.currentZoomLevel = 1;
@@ -192,7 +198,14 @@ export class PipelineAssemblyComponent implements OnInit {
             pipeline._id = this.currentModifiedPipelineId;
         }
 
-        this.openPipelineNameModal(pipeline, (!!this.currentModifiedPipelineId));
+        const dialogRef = this.dialogService.open(SavePipelineComponent,{
+            panelType: PanelType.SLIDE_IN_PANEL,
+            title: "Save pipeline",
+            data: {
+                "pipeline": pipeline,
+                "currentModifiedPipelineId": this.currentModifiedPipelineId
+            }
+        });
     }
 
 
diff --git a/ui/src/app/editor-v2/dialog/customize/customize.component.css b/ui/src/app/editor-v2/dialog/customize/customize.component.scss
similarity index 79%
copy from ui/src/app/editor-v2/dialog/customize/customize.component.css
copy to ui/src/app/editor-v2/dialog/customize/customize.component.scss
index 6abbbdd..d043e55 100644
--- a/ui/src/app/editor-v2/dialog/customize/customize.component.css
+++ b/ui/src/app/editor-v2/dialog/customize/customize.component.scss
@@ -16,22 +16,7 @@
  *
  */
 
-.dialog-container {
-    display: flex;
-    flex-flow: column;
-    align-items: stretch;
-    flex: 1 1 100%;
-    height:100%;
-}
-
-.mat-dialog-content {
-    margin: 0px;
-    flex: 1 1 auto;
-}
-
-.mat-dialog-actions {
-    padding: 10px;
-}
+@import '../../../../scss/sp/sp-dialog.scss';
 
 .customize-section {
     display:flex;
diff --git a/ui/src/app/editor-v2/dialog/customize/customize.component.ts b/ui/src/app/editor-v2/dialog/customize/customize.component.ts
index d6b44e4..174f502 100644
--- a/ui/src/app/editor-v2/dialog/customize/customize.component.ts
+++ b/ui/src/app/editor-v2/dialog/customize/customize.component.ts
@@ -25,7 +25,7 @@ import {EventSchema} from "../../../core-model/gen/streampipes-model";
 @Component({
   selector: 'customize-pipeline-element',
   templateUrl: './customize.component.html',
-  styleUrls: ['./customize.component.css']
+  styleUrls: ['./customize.component.scss']
 })
 export class CustomizeComponent implements OnInit {
 
diff --git a/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.html b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.html
new file mode 100644
index 0000000..0c1aaf4
--- /dev/null
+++ b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.html
@@ -0,0 +1,65 @@
+<!--
+  ~ 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="dialog-container">
+    <div class="mat-dialog-content padding-20">
+        <div fxFlex="100" fxLayout="column">
+
+        <form name="submitPipelineForm">
+            <div fxFlex="100" fxLayout="column">
+                <div id="overwriteCheckbox" class="checkbox" *ngIf="modificationMode">
+                    <mat-radio-group class="md-accent" [(ngModel)]="updateMode">
+                        <mat-radio-button [value]="'update'">
+                            Update pipeline <b>{{pipeline.name}}</b>
+                        </mat-radio-button>
+                        <mat-radio-button [value]="'clone'">
+                            Create new pipeline
+                        </mat-radio-button>
+                    </mat-radio-group>
+                </div>
+                <div fxFlex="100" fxLayout="column" *ngIf="!modificationMode || updateMode=='clone'">
+                    <mat-form-field fxFlex><mat-label>Pipeline Name</mat-label>
+                        <input matInput name="pipelineName" [(ngModel)]="pipeline.name" required [maxLength]="40"/>
+<!--                        <span ng-show="submitPipelineForm.pipelineName.$touched && submitPipelineForm.pipelineName.$error.required">Please provide a pipeline name.</span>-->
+<!--                        <span ng-show="submitPipelineForm.pipelineName.$error.maxlength">Please provide a shorter pipeline name.</span>-->
+                    </mat-form-field>
+                    <mat-form-field fxFlex><mat-label>Description</mat-label>
+                        <input matInput name="pipelineDescription" [(ngModel)]="pipeline.description" [maxLength]="80"/>
+<!--                        <span ng-show="submitPipelineForm.pipelineDescription.$error.maxlength">Please provide a shorter description.</span>-->
+                    </mat-form-field>
+                </div>
+                <mat-checkbox (click)="triggerTutorial()" aria-label="Start Pipeline" [(ngModel)]="startPipelineAfterStorage">
+                    Start pipeline immediately
+                </mat-checkbox>
+            </div>
+        </form>
+        </div>
+    </div>
+    <div class="mat-dialog-actions">
+        <mat-divider style="margin-bottom:10px;"></mat-divider>
+        <button mat-button mat-raised-button color="primary" (click)="savePipelineName(false)" style="margin-right:10px;">
+            Save
+        </button>
+        <button mat-button mat-raised-button color="primary" (click)="savePipelineName(true)" style="margin-right:10px;">
+            Save and go to pipeline view
+        </button>
+        <button mat-button mat-raised-button class="mat-basic" (click)="hide()">
+            Cancel
+        </button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/platform-services/contants/pipeline-element-constants.ts b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.scss
similarity index 83%
copy from ui/src/app/platform-services/contants/pipeline-element-constants.ts
copy to ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.scss
index 58ba04b..b2f7ca6 100644
--- a/ui/src/app/platform-services/contants/pipeline-element-constants.ts
+++ b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.scss
@@ -16,3 +16,14 @@
  *
  */
 
+@import '../../../../scss/sp/sp-dialog.scss';
+
+.customize-section {
+  display:flex;
+  flex: 1 1 auto;
+  padding: 20px;
+}
+
+.padding-20 {
+  padding: 20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.ts b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.ts
new file mode 100644
index 0000000..836ada2
--- /dev/null
+++ b/ui/src/app/editor-v2/dialog/save-pipeline/save-pipeline.component.ts
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {Component, Inject, Input, OnInit} from "@angular/core";
+import {DialogRef} from "../../../core-ui/dialog/base-dialog/dialog-ref";
+import {Message, Pipeline} from "../../../core-model/gen/streampipes-model";
+import {ObjectProvider} from "../../services/object-provider.service";
+import {EditorService} from "../../services/editor.service";
+import {PipelineService} from "../../../platform-services/apis/pipeline.service";
+import {ShepherdService} from "../../../services/tour/shepherd.service";
+
+@Component({
+  selector: 'save-pipeline',
+  templateUrl: './save-pipeline.component.html',
+  styleUrls: ['./save-pipeline.component.scss']
+})
+export class SavePipelineComponent implements OnInit {
+
+  pipelineCategories: any;
+  startPipelineAfterStorage: any;
+  updateMode: any;
+  submitPipelineForm: any;
+  TransitionService: any;
+
+  @Input()
+  pipeline: Pipeline;
+  @Input()
+  modificationMode: string;
+
+  constructor(private editorService: EditorService,
+              private dialogRef: DialogRef<SavePipelineComponent>,
+              private objectProvider: ObjectProvider,
+              private pipelineService: PipelineService,
+              //TransitionService,
+              @Inject("$state") private $state: any,
+              private ShepherdService: ShepherdService) {
+    this.pipelineCategories = [];
+    this.updateMode = "update";
+    //this.TransitionService = TransitionService;
+    //this.ShepherdService = ShepherdService;
+  }
+
+  ngOnInit() {
+    this.getPipelineCategories();
+    if (this.ShepherdService.isTourActive()) {
+      this.ShepherdService.trigger("enter-pipeline-name");
+    }
+
+  }
+
+  triggerTutorial() {
+    if (this.ShepherdService.isTourActive()) {
+      this.ShepherdService.trigger("save-pipeline-dialog");
+    }
+  }
+
+  displayErrors(data) {
+    for (var i = 0, notification; notification = data.notifications[i]; i++) {
+      //this.showToast("error", notification.title, notification.description);
+    }
+  }
+
+  displaySuccess(data) {
+    if (data.notifications.length > 0) {
+      //this.showToast("success", data.notifications[0].title, data.notifications[0].description);
+    }
+  }
+
+  getPipelineCategories() {
+    this.pipelineService.getPipelineCategories().subscribe(pipelineCategories => {
+          this.pipelineCategories = pipelineCategories;
+        });
+  };
+
+
+  savePipelineName(switchTab) {
+    if (this.pipeline.name == "") {
+      //this.showToast("error", "Please enter a name for your pipeline");
+      return false;
+    }
+
+    let storageRequest;
+
+    if (this.modificationMode && this.updateMode === 'update') {
+      storageRequest = this.pipelineService.updatePipeline(this.pipeline);
+    } else {
+      storageRequest = this.pipelineService.storePipeline(this.pipeline);
+    }
+
+    storageRequest
+        .subscribe(statusMessage => {
+          if (statusMessage.success) {
+            this.afterStorage(statusMessage, switchTab);
+          } else {
+            this.displayErrors(statusMessage);
+          }
+        }, data => {
+          //this.showToast("error", "Connection Error", "Could not fulfill request");
+        });
+  };
+
+  afterStorage(data: Message, switchTab) {
+    this.displaySuccess(data);
+    this.hide();
+    //this.TransitionService.makePipelineAssemblyEmpty(true);
+    this.editorService.removePipelineFromCache();
+    if (this.ShepherdService.isTourActive()) {
+      this.ShepherdService.hideCurrentStep();
+    }
+    if (switchTab && !this.startPipelineAfterStorage) {
+      this.$state.go("streampipes.pipelines");
+    }
+    if (this.startPipelineAfterStorage) {
+      this.$state.go("streampipes.pipelines", {pipeline: data.notifications[1].description});
+    }
+  }
+
+  hide() {
+    this.dialogRef.close();
+    //this.$mdDialog.hide();
+  };
+}
\ 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 08f173c..19f5141 100644
--- a/ui/src/app/editor-v2/editor.module.ts
+++ b/ui/src/app/editor-v2/editor.module.ts
@@ -48,6 +48,7 @@ import {OverlayModule} from "@angular/cdk/overlay";
 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";
 
 @NgModule({
     imports: [
@@ -70,7 +71,8 @@ import {CoreUiModule} from "../core-ui/core-ui.module";
         PipelineElementIconStandComponent,
         PipelineElementComponent,
         PipelineElementOptionsComponent,
-        PipelineComponent
+        PipelineComponent,
+        SavePipelineComponent
     ],
     providers: [
         EditorService,
diff --git a/ui/src/app/editor-v2/services/editor.service.ts b/ui/src/app/editor-v2/services/editor.service.ts
index 309c386..6f34eb1 100644
--- a/ui/src/app/editor-v2/services/editor.service.ts
+++ b/ui/src/app/editor-v2/services/editor.service.ts
@@ -25,11 +25,13 @@ import {
     PipelineModificationMessage
 } from "../../core-model/gen/streampipes-model";
 import {Observable} from "rxjs";
+import {PlatformServicesCommons} from "../../platform-services/apis/commons.service";
 
 @Injectable()
 export class EditorService {
 
     constructor(private http: HttpClient,
+                private platformServicesCommons: PlatformServicesCommons,
                 private authStatusService: AuthStatusService) {
     }
 
@@ -45,12 +47,20 @@ export class EditorService {
             });
     }
 
-    private get baseUrl() {
-        return '/streampipes-backend';
+    getCachedPipeline() {
+        return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipeline-cache");
+    }
+
+    updateCachedPipeline(rawPipelineModel: any) {
+        return this.http.post(this.platformServicesCommons.authUserBasePath() + "/pipeline-cache", rawPipelineModel);
+    }
+
+    removePipelineFromCache() {
+        return this.http.delete(this.platformServicesCommons.authUserBasePath() + "/pipeline-cache");
     }
 
     private get pipelinesResourceUrl() {
-        return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/pipelines'
+        return this.platformServicesCommons.authUserBasePath() + '/pipelines'
     }
 
 
diff --git a/ui/src/app/editor-v2/dialog/customize/customize.component.css b/ui/src/app/platform-services/apis/commons.service.ts
similarity index 66%
rename from ui/src/app/editor-v2/dialog/customize/customize.component.css
rename to ui/src/app/platform-services/apis/commons.service.ts
index 6abbbdd..2c38292 100644
--- a/ui/src/app/editor-v2/dialog/customize/customize.component.css
+++ b/ui/src/app/platform-services/apis/commons.service.ts
@@ -16,25 +16,23 @@
  *
  */
 
-.dialog-container {
-    display: flex;
-    flex-flow: column;
-    align-items: stretch;
-    flex: 1 1 100%;
-    height:100%;
-}
+import {AuthStatusService} from "../../services/auth-status.service";
+import {Injectable} from "@angular/core";
 
-.mat-dialog-content {
-    margin: 0px;
-    flex: 1 1 auto;
-}
+@Injectable()
+export class PlatformServicesCommons {
+
+  constructor(private authStatusService: AuthStatusService) {
+
+  }
+
+  get basePath(): string {
+    return '/streampipes-backend';
+  }
+
+  authUserBasePath() {
+    return this.basePath + '/api/v2/users/' + this.authStatusService.email;
+  }
 
-.mat-dialog-actions {
-    padding: 10px;
 }
 
-.customize-section {
-    display:flex;
-    flex: 1 1 auto;
-    padding: 20px;
-}
\ No newline at end of file
diff --git a/ui/src/app/platform-services/apis/pipeline-element.service.ts b/ui/src/app/platform-services/apis/pipeline-element.service.ts
index 31c1b79..0463376 100644
--- a/ui/src/app/platform-services/apis/pipeline-element.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-element.service.ts
@@ -25,12 +25,13 @@ import {
   DataSinkInvocation,
   DataSourceDescription
 } from "../../core-model/gen/streampipes-model";
+import {PlatformServicesCommons} from "./commons.service";
 
 @Injectable()
 export class PipelineElementService {
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService) {
+              private platformServicesCommons: PlatformServicesCommons) {
   }
 
   getDataProcessors(): Observable<Array<DataProcessorInvocation>> {
@@ -51,19 +52,15 @@ export class PipelineElementService {
     })
   }
 
-  private get baseUrl(): string {
-    return '/streampipes-backend';
-  }
-
   private get dataProcessorsUrl(): string {
-    return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/sepas'
+    return this.platformServicesCommons.authUserBasePath() + '/sepas'
   }
 
   private get dataSourcesUrl(): string {
-    return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/sources'
+    return this.platformServicesCommons.authUserBasePath() + '/sources'
   }
 
   private get dataSinksUrl(): string {
-    return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/actions'
+    return this.platformServicesCommons.authUserBasePath() + '/actions'
   }
 }
\ No newline at end of file
diff --git a/ui/src/app/platform-services/apis/pipeline.service.ts b/ui/src/app/platform-services/apis/pipeline.service.ts
new file mode 100644
index 0000000..91637bc
--- /dev/null
+++ b/ui/src/app/platform-services/apis/pipeline.service.ts
@@ -0,0 +1,89 @@
+/*
+ * 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 {Injectable} from "@angular/core";
+import {HttpClient} from "@angular/common/http";
+import {PlatformServicesCommons} from "./commons.service";
+import {Observable} from "rxjs";
+import {Message, Pipeline} from "../../core-model/gen/streampipes-model";
+import {map} from "rxjs/operators";
+
+@Injectable()
+export class PipelineService {
+
+  constructor(private http: HttpClient,
+              private platformServicesCommons: PlatformServicesCommons) {
+
+  }
+
+  getPipelineCategories() {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelinecategories");
+  };
+
+  storePipelineCategory(pipelineCategory) {
+    return this.http.post(this.platformServicesCommons.authUserBasePath() + "/pipelinecategories", pipelineCategory);
+  };
+
+  deletePipelineCategory(categoryId) {
+    return this.http.delete(this.platformServicesCommons.authUserBasePath() + "/pipelinecategories/" + categoryId);
+  }
+
+  startPipeline(pipelineId) {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/" + pipelineId + "/start");
+  }
+
+  stopPipeline(pipelineId) {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/" + pipelineId + "/stop");
+  }
+
+  getPipelineById(pipelineId) {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/" + pipelineId);
+  }
+
+  getPipelineStatusById(pipelineId) {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/" + pipelineId + "/status");
+  }
+
+  storePipeline(pipeline): Observable<Message> {
+    return this.http.post(this.platformServicesCommons.authUserBasePath() + "/pipelines", pipeline)
+        .pipe(map(response => {
+          return Message.fromData(response as Message);
+        }));
+  }
+
+  updatePipeline(pipeline): Observable<Message> {
+    var pipelineId = pipeline._id;
+    return this.http.put(this.platformServicesCommons.authUserBasePath() + "/pipelines/" + pipelineId, pipeline)
+        .pipe(map(response => {
+          return Message.fromData(response as Message);
+        }));
+  }
+
+  getOwnPipelines(): Observable<Pipeline[]> {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/own").pipe(map(response => {
+      return (response as any[]).map(p => Pipeline.fromData(p));
+    }));
+  };
+
+  getSystemPipelines(): Observable<Pipeline[]> {
+    return this.http.get(this.platformServicesCommons.authUserBasePath() + "/pipelines/system").pipe(map(response => {
+      return (response as any[]).map(p => Pipeline.fromData(p));
+    }))
+  };
+
+}
\ No newline at end of file
diff --git a/ui/src/app/platform-services/contants/pipeline-element-constants.ts b/ui/src/app/platform-services/contants/platform-services.constants.ts
similarity index 94%
copy from ui/src/app/platform-services/contants/pipeline-element-constants.ts
copy to ui/src/app/platform-services/contants/platform-services.constants.ts
index 58ba04b..1879aa6 100644
--- a/ui/src/app/platform-services/contants/pipeline-element-constants.ts
+++ b/ui/src/app/platform-services/contants/platform-services.constants.ts
@@ -16,3 +16,7 @@
  *
  */
 
+export class PlatformServicesConstants {
+
+}
+
diff --git a/ui/src/app/platform-services/platform.module.ts b/ui/src/app/platform-services/platform.module.ts
index b4f2ca9..1d235d2 100644
--- a/ui/src/app/platform-services/platform.module.ts
+++ b/ui/src/app/platform-services/platform.module.ts
@@ -20,14 +20,18 @@ import {NgModule} from '@angular/core';
 import {TsonLdSerializerService} from './tsonld-serializer.service';
 import {PipelineTemplateService} from './apis/pipeline-template.service';
 import {PipelineElementService} from "./apis/pipeline-element.service";
+import {PipelineService} from "./apis/pipeline.service";
+import {PlatformServicesCommons} from "./apis/commons.service";
 
 @NgModule({
   imports: [],
   declarations: [],
   providers: [
+    PlatformServicesCommons,
     TsonLdSerializerService,
     PipelineTemplateService,
-    PipelineElementService
+    PipelineElementService,
+    PipelineService
   ],
   entryComponents: []
 })
diff --git a/ui/src/scss/sp/dialog.scss b/ui/src/scss/sp/dialog.scss
index 380fda1..5e64bdd 100644
--- a/ui/src/scss/sp/dialog.scss
+++ b/ui/src/scss/sp/dialog.scss
@@ -16,6 +16,8 @@
  *
  */
 
+@import '../variables';
+
 .sp-no-padding-dialog .mat-dialog-container {
   box-shadow: 0 11px 15px -7px rgba(0,0,0,.2), 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12);
   display: block;
diff --git a/ui/src/app/platform-services/contants/pipeline-element-constants.ts b/ui/src/scss/sp/sp-dialog.scss
similarity index 78%
rename from ui/src/app/platform-services/contants/pipeline-element-constants.ts
rename to ui/src/scss/sp/sp-dialog.scss
index 58ba04b..6ff62bf 100644
--- a/ui/src/app/platform-services/contants/pipeline-element-constants.ts
+++ b/ui/src/scss/sp/sp-dialog.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * 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.
@@ -16,3 +16,19 @@
  *
  */
 
+.dialog-container {
+  display: flex;
+  flex-flow: column;
+  align-items: stretch;
+  flex: 1 1 100%;
+  height:100%;
+}
+
+.mat-dialog-content {
+  margin: 0px;
+  flex: 1 1 auto;
+}
+
+.mat-dialog-actions {
+  padding: 10px;
+}
\ No newline at end of file