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/07/12 20:52:44 UTC

[incubator-streampipes] branch STREAMPIPES-558 updated (2d499bb97 -> 5e000fd6a)

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

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


    from 2d499bb97 [STREAMPIPES-537] Harmonize layout of files module
     new fe932e50c [hotfix] Minor layout improvement
     new 5e000fd6a [STREAMPIPES-537] Change routing of pipeline and pipeline details, make pipeline editor accessible from pipeline view

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:
 ui/deployment/app-routing.module.mst               |   2 -
 ui/deployment/dev/config.yml                       |   1 -
 ui/deployment/modules.yml                          |   2 +-
 .../basic-nav-tabs/basic-nav-tabs.component.html   |  19 +-
 .../basic-nav-tabs/basic-nav-tabs.component.scss   |   4 +
 .../basic-nav-tabs/basic-nav-tabs.component.ts     |  10 +
 .../existing-adapters.component.scss               |   1 -
 .../overview/dashboard-overview.component.css      |   7 +
 ui/src/app/editor/editor.component.ts              |   6 +-
 .../components/edit/quickedit.component.html       |  61 +++---
 .../components/edit/quickedit.component.ts         | 231 ++++++++++-----------
 .../monitoring/pipeline-monitoring.component.html  |  79 +++----
 .../monitoring/pipeline-monitoring.component.ts    |  51 ++---
 .../pipeline-details-overview.component.html       |  46 ++++
 .../pipeline-details-overview.component.scss}      |   1 -
 .../pipeline-details-overview.component.ts}        |  30 ++-
 .../components/sp-pipeline-details.directive.ts    |  66 ++++++
 .../pipeline-details-tabs.ts}                      |  14 +-
 .../pipeline-details.component.html                |  65 ------
 .../pipeline-details/pipeline-details.component.ts |  77 -------
 .../pipeline-details/pipeline-details.module.ts    |  67 +++---
 .../pipeline-overview.component.scss               |   4 +-
 ui/src/app/pipelines/pipelines.component.html      | 118 ++++++-----
 ui/src/app/pipelines/pipelines.component.ts        |   9 +-
 ui/src/app/pipelines/pipelines.module.ts           |  52 +++++
 .../services/pipeline-operations.service.ts        |   8 +-
 26 files changed, 553 insertions(+), 478 deletions(-)
 create mode 100644 ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html
 rename ui/src/app/pipeline-details/{pipeline-details.component.scss => components/overview/pipeline-details-overview.component.scss} (99%)
 copy ui/src/app/{core/components/streampipes/streampipes.component.ts => pipeline-details/components/overview/pipeline-details-overview.component.ts} (50%)
 create mode 100644 ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts
 copy ui/src/app/{configuration/configuration-tabs.ts => pipeline-details/pipeline-details-tabs.ts} (57%)
 delete mode 100644 ui/src/app/pipeline-details/pipeline-details.component.html
 delete mode 100644 ui/src/app/pipeline-details/pipeline-details.component.ts


[incubator-streampipes] 01/02: [hotfix] Minor layout improvement

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

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

commit fe932e50c1e2d288e748a69e34bc199ca8685f27
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Tue Jul 12 18:01:20 2022 +0200

    [hotfix] Minor layout improvement
---
 .../dashboard/components/overview/dashboard-overview.component.css | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ui/src/app/dashboard/components/overview/dashboard-overview.component.css b/ui/src/app/dashboard/components/overview/dashboard-overview.component.css
index 121e83846..8bd5722e9 100644
--- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.css
+++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.css
@@ -36,3 +36,10 @@ table {
     display: inline;
     margin-right: 10px;
 }
+
+.mat-row:nth-child(even) {
+    background-color: var(--color-bg-1);
+}
+.mat-row:nth-child(odd) {
+    background-color: var(--color-bg-2);
+}


[incubator-streampipes] 02/02: [STREAMPIPES-537] Change routing of pipeline and pipeline details, make pipeline editor accessible from pipeline view

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

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

commit 5e000fd6a9e8112af253a3004b98f94318a4eebc
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Tue Jul 12 22:52:30 2022 +0200

    [STREAMPIPES-537] Change routing of pipeline and pipeline details, make pipeline editor accessible from pipeline view
---
 ui/deployment/app-routing.module.mst               |   2 -
 ui/deployment/dev/config.yml                       |   1 -
 ui/deployment/modules.yml                          |   2 +-
 .../basic-nav-tabs/basic-nav-tabs.component.html   |  19 +-
 .../basic-nav-tabs/basic-nav-tabs.component.scss   |   4 +
 .../basic-nav-tabs/basic-nav-tabs.component.ts     |  10 +
 .../existing-adapters.component.scss               |   1 -
 ui/src/app/editor/editor.component.ts              |   6 +-
 .../components/edit/quickedit.component.html       |  61 +++---
 .../components/edit/quickedit.component.ts         | 231 ++++++++++-----------
 .../monitoring/pipeline-monitoring.component.html  |  79 +++----
 .../monitoring/pipeline-monitoring.component.ts    |  51 ++---
 .../pipeline-details-overview.component.html       |  46 ++++
 .../pipeline-details-overview.component.scss}      |   1 -
 .../pipeline-details-overview.component.ts         |  54 +++++
 .../components/sp-pipeline-details.directive.ts    |  66 ++++++
 .../app/pipeline-details/pipeline-details-tabs.ts} |  30 +--
 .../pipeline-details.component.html                |  65 ------
 .../pipeline-details/pipeline-details.component.ts |  77 -------
 .../pipeline-details/pipeline-details.module.ts    |  67 +++---
 .../pipeline-overview.component.scss               |   4 +-
 ui/src/app/pipelines/pipelines.component.html      | 118 ++++++-----
 ui/src/app/pipelines/pipelines.component.ts        |   9 +-
 ui/src/app/pipelines/pipelines.module.ts           |  52 +++++
 .../services/pipeline-operations.service.ts        |   8 +-
 25 files changed, 581 insertions(+), 483 deletions(-)

diff --git a/ui/deployment/app-routing.module.mst b/ui/deployment/app-routing.module.mst
index 29e46bcf0..093d7a515 100644
--- a/ui/deployment/app-routing.module.mst
+++ b/ui/deployment/app-routing.module.mst
@@ -22,7 +22,6 @@ import {HomeComponent} from "./home/home.component";
 import {LoginComponent} from "./login/components/login/login.component";
 import {SetupComponent} from "./login/components/setup/setup.component";
 import {StreampipesComponent} from "./core/components/streampipes/streampipes.component";
-import {PipelineDetailsComponent} from "./pipeline-details/pipeline-details.component";
 import {StandaloneDashboardComponent} from "./dashboard/components/standalone/standalone-dashboard.component";
 import {AuthCanActivateChildrenGuard} from "./_guards/auth.can-activate-children.guard";
 import {ConfiguredCanActivateGuard} from "./_guards/configured.can-activate.guard";
@@ -70,7 +69,6 @@ const routes: Routes = [
 
       { path: 'notifications', component: NotificationsComponent },
       { path: 'info', component: InfoComponent },
-      { path: 'pipeline-details', component: PipelineDetailsComponent },
       { path: 'profile', component: ProfileComponent},
     ], canActivateChild: [AuthCanActivateChildrenGuard, PageAuthGuard] }
 ];
diff --git a/ui/deployment/dev/config.yml b/ui/deployment/dev/config.yml
index d134f440f..8a72ac568 100644
--- a/ui/deployment/dev/config.yml
+++ b/ui/deployment/dev/config.yml
@@ -19,7 +19,6 @@ login:
   logo-navigation: 'deployment/dev/img/logo-navigation.png'
   favicon: 'deployment/dev/img/favicon.png'
 modules:
-  - spEditor
   - spPipelines
   - spConnect
   - spDashboard
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index f12f05d4f..f71f14a63 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -42,7 +42,7 @@ spConnect:
   admin: False
   pageNames: 'PageName.CONNECT'
 spPipelines:
-  componentImport: True
+  componentImport: False
   ng5_moduleName: 'PipelinesModule'
   ng5_component: 'PipelinesComponent'
   ng5_componentPath: './pipelines/pipelines.component'
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
index 25f3eadd1..12a453415 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.html
@@ -18,8 +18,20 @@
 
 <div fxLayout="column" class="page-container">
     <div fxLayout="row" class="p-0 sp-bg-lightgray page-container-nav">
-        <div fxLayout="fill">
-            <div fxFlex="100" class="page-container-nav">
+            <div fxFlex="100" class="page-container-nav pr-5" fxLayout="row">
+                <div fxLayout="row"
+                     fxLayoutAlign="start center"
+                     style="border-right: 2px solid var(--color-bg-2)" *ngIf="showBackLink">
+                    <button mat-button
+                            mat-icon-button
+                            color="accent"
+                            matTooltip="Back"
+                            (click)="navigateBack()"
+                            class="edit-menu-btn"
+                            data-cy="save-data-explorer-go-back-to-overview">
+                        <mat-icon>arrow_back</mat-icon>
+                    </button>
+                </div>
                 <nav mat-tab-nav-bar color="accent">
                     <a mat-tab-link *ngFor="let item of spNavigationItems"
                        (click)="navigateTo(item)"
@@ -27,8 +39,9 @@
                         <span class="upper-case">{{item.itemTitle}}</span>
                     </a>
                 </nav>
+                <span fxFlex></span>
+                <ng-content select="[nav]" fxFlex="100" fxLayout="row" fxLayoutAlign="end center"></ng-content>
             </div>
-        </div>
     </div>
 
     <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100">
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss
index ce626dc9d..19c8ca2a3 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.scss
@@ -41,3 +41,7 @@
 .upper-case {
   text-transform: uppercase;
 }
+
+.pr-5 {
+  padding-right: 5px;
+}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
index bdace86dd..5ab53a56b 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
@@ -33,6 +33,12 @@ export class SpBasicNavTabsComponent {
   @Input()
   activeLink: string;
 
+  @Input()
+  showBackLink = false;
+
+  @Input()
+  backLinkTarget: string[] = [];
+
   constructor(private router: Router) {
 
   }
@@ -40,4 +46,8 @@ export class SpBasicNavTabsComponent {
   navigateTo(spNavigationItem: SpNavigationItem) {
     this.router.navigate(spNavigationItem.itemLink);
   }
+
+  navigateBack() {
+    this.router.navigate(this.backLinkTarget);
+  }
 }
diff --git a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss
index b0368049f..f38f54d32 100644
--- a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss
+++ b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.scss
@@ -48,6 +48,5 @@
 .filter-bar-margin {
   margin-left: 10px;
   padding-left: 10px;
-  border-left: 2px solid var(--color-bg-2)
 }
 
diff --git a/ui/src/app/editor/editor.component.ts b/ui/src/app/editor/editor.component.ts
index 76caa68e6..3ebcb368a 100644
--- a/ui/src/app/editor/editor.component.ts
+++ b/ui/src/app/editor/editor.component.ts
@@ -60,9 +60,9 @@ export class EditorComponent implements OnInit {
   }
 
   ngOnInit() {
-    this.activatedRoute.queryParams.subscribe(params => {
-      if (params['pipeline']) {
-        this.currentModifiedPipelineId = params['pipeline'];
+    this.activatedRoute.params.subscribe(params => {
+      if (params.pipelineId) {
+        this.currentModifiedPipelineId = params.pipelineId;
       }
     });
     zip(this.pipelineElementService.getDataStreams(),
diff --git a/ui/src/app/pipeline-details/components/edit/quickedit.component.html b/ui/src/app/pipeline-details/components/edit/quickedit.component.html
index ba52554b2..2af6ed274 100644
--- a/ui/src/app/pipeline-details/components/edit/quickedit.component.html
+++ b/ui/src/app/pipeline-details/components/edit/quickedit.component.html
@@ -16,28 +16,40 @@
   ~
   -->
 
-<div>
-    <div class="assembly-options-preview sp-blue-bg">
-        <div fxLayout="row" fxLayoutAlign="start center">
-            <h4>Edit configuration</h4>
-            <span fxFlex></span>
-            <button color="accent" mat-button mat-raised-button matTooltip="Save Pipeline" matTooltipPosition="above"
-                    style="display:flex;align-items:center;" class="settings-bar-icon-button"
-                    [disabled]="(!formValid || pipelineUpdating)"
-                    (click)="updatePipeline()">
-                <mat-icon>save</mat-icon>
-                <span>&nbsp;Update pipeline</span>
-            </button>
+<sp-basic-nav-tabs [spNavigationItems]="tabs"
+                   [activeLink]="'quick-edit'"
+                   [showBackLink]="true"
+                   [backLinkTarget]="['pipelines']">
+
+    <div fxLayout="column" class="page-container-padding" *ngIf="pipeline">
+        <pipeline-preview [jspcanvas]="'assembly-preview'"
+                          [pipeline]="pipeline"
+                          (selectedElementEmitter)="selectElement($event)"
+                          style="margin-bottom:15px;"
+                          class="md-padding"
+                          *ngIf="pipelineAvailable"></pipeline-preview>
+        <div class="assembly-options-preview sp-blue-bg">
+            <div fxLayout="row" fxLayoutAlign="start center">
+                <h4>Edit configuration</h4>
+                <span fxFlex></span>
+                <button color="accent" mat-button mat-raised-button matTooltip="Save Pipeline"
+                        matTooltipPosition="above"
+                        style="display:flex;align-items:center;" class="settings-bar-icon-button"
+                        [disabled]="(!formValid || pipelineUpdating)"
+                        (click)="updatePipeline()">
+                    <mat-icon>save</mat-icon>
+                    <span>&nbsp;Update pipeline</span>
+                </button>
+            </div>
         </div>
-    </div>
-    <div class="sp-blue-border">
-        <div *ngIf="selectedElement">
-            <div fxLayout="column" style="padding:5px;padding-left:10px;">
-                <pipeline-elements-row [pipeline]="pipeline"
-                                       [element]="selectedElement"></pipeline-elements-row>
+        <div class="sp-blue-border">
+            <div *ngIf="selectedElement">
+                <div fxLayout="column" style="padding:5px;padding-left:10px;">
+                    <pipeline-elements-row [pipeline]="pipeline"
+                                           [element]="selectedElement"></pipeline-elements-row>
 
-                <div fxFlex="100" fxLayout="column"
-                     *ngIf="isInvocable">
+                    <div fxFlex="100" fxLayout="column"
+                         *ngIf="isInvocable">
                         <form [formGroup]="parentForm" fxFlex="100">
                             <app-static-property *ngFor="let config of _selectedElement.staticProperties"
                                                  [staticProperty]="config"
@@ -48,11 +60,12 @@
                                                  [fieldName]="config.internalName">
                             </app-static-property>
                         </form>
+                    </div>
                 </div>
             </div>
-        </div>
-        <div fxLayout="column" fxLayoutAlign="center center" *ngIf="!selectedElement">
-            (select an element in the preview window to modify it)
+            <div fxLayout="column" fxLayoutAlign="center center" *ngIf="!selectedElement">
+                (select an element in the preview window to modify it)
+            </div>
         </div>
     </div>
-</div>
+</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/components/edit/quickedit.component.ts b/ui/src/app/pipeline-details/components/edit/quickedit.component.ts
index 15877ec79..d63894a99 100644
--- a/ui/src/app/pipeline-details/components/edit/quickedit.component.ts
+++ b/ui/src/app/pipeline-details/components/edit/quickedit.component.ts
@@ -16,135 +16,132 @@
  *
  */
 
+import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
 import {
-    AfterViewInit,
-    ChangeDetectorRef,
-    Component,
-    EventEmitter,
-    Input,
-    OnInit,
-    Output
-} from '@angular/core';
-import {
-    PipelineService,
-    DataProcessorInvocation,
-    DataSinkInvocation,
-    EventSchema,
-    Pipeline
+  DataProcessorInvocation,
+  DataSinkInvocation,
+  EventSchema,
+  PipelineService
 } from '@streampipes/platform-services';
 import { PipelineElementUnion } from '../../../editor/model/editor.model';
 import { FormBuilder, FormGroup } from '@angular/forms';
+import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive';
+import { ActivatedRoute } from '@angular/router';
+import { AuthService } from '../../../services/auth.service';
 
 @Component({
-    selector: 'quick-edit',
-    templateUrl: './quickedit.component.html',
+  selector: 'quick-edit',
+  templateUrl: './quickedit.component.html',
 })
-export class QuickEditComponent implements OnInit, AfterViewInit {
-
-    @Input()
-    pipeline: Pipeline;
-
-    @Output()
-    reloadPipelineEmitter: EventEmitter<void> = new EventEmitter<void>();
-
-    _selectedElement: PipelineElementUnion;
-
-    eventSchemas: EventSchema[];
-
-    parentForm: FormGroup;
-    formValid: boolean;
-    viewInitialized = false;
-
-    isInvocable = false;
-    isDataProcessor = false;
-
-    pipelineUpdating = false;
-
-    constructor(private pipelineService: PipelineService,
-                private fb: FormBuilder,
-                private changeDetectorRef: ChangeDetectorRef) {
-
-    }
-
-    ngOnInit() {
-        this.parentForm = this.fb.group({
-        });
-
-        this.parentForm.statusChanges.subscribe((status) => {
-            this.formValid = this.viewInitialized && this.parentForm.valid;
-        });
-    }
-
-    ngAfterViewInit(): void {
-        this.viewInitialized = true;
-        this.formValid = this.viewInitialized && this.parentForm.valid;
-        this.changeDetectorRef.detectChanges();
-    }
-
-    updatePipeline() {
-        this.pipelineUpdating = true;
-        this.updatePipelineElement();
-        this.pipelineService.updatePipeline(this.pipeline).subscribe(data => {
-            this.reloadPipelineEmitter.emit();
-            this.pipelineUpdating = false;
-        });
-    }
-
-    updatePipelineElement() {
-        if (this._selectedElement instanceof DataProcessorInvocation) {
-            this.updateDataProcessor();
-        } else if (this._selectedElement instanceof DataSinkInvocation) {
-            this.updateDataSink();
-        }
+export class QuickEditComponent extends SpPipelineDetailsDirective implements OnInit, AfterViewInit {
+
+  _selectedElement: PipelineElementUnion;
+
+  eventSchemas: EventSchema[];
+
+  parentForm: FormGroup;
+  formValid: boolean;
+  viewInitialized = false;
+
+  isInvocable = false;
+  isDataProcessor = false;
+
+  pipelineUpdating = false;
+
+  constructor(activatedRoute: ActivatedRoute,
+              pipelineService: PipelineService,
+              authService: AuthService,
+              private fb: FormBuilder,
+              private changeDetectorRef: ChangeDetectorRef) {
+    super(activatedRoute, pipelineService, authService);
+  }
+
+  ngOnInit() {
+    super.onInit();
+    this.parentForm = this.fb.group({});
+
+    this.parentForm.statusChanges.subscribe((status) => {
+      this.formValid = this.viewInitialized && this.parentForm.valid;
+    });
+  }
+
+  ngAfterViewInit(): void {
+    this.viewInitialized = true;
+    this.formValid = this.viewInitialized && this.parentForm.valid;
+    this.changeDetectorRef.detectChanges();
+  }
+
+  updatePipeline() {
+    this.pipelineUpdating = true;
+    this.updatePipelineElement();
+    this.pipelineService.updatePipeline(this.pipeline).subscribe(data => {
+      this.loadPipeline();
+      this.pipelineUpdating = false;
+    });
+  }
+
+  updatePipelineElement() {
+    if (this._selectedElement instanceof DataProcessorInvocation) {
+      this.updateDataProcessor();
+    } else if (this._selectedElement instanceof DataSinkInvocation) {
+      this.updateDataSink();
     }
-
-    updateDataProcessor() {
-        const dataProcessors: DataProcessorInvocation[] = [];
-        this.pipeline.sepas.forEach(p => {
-           if (p.dom === this._selectedElement.dom) {
-               dataProcessors.push(this._selectedElement as DataProcessorInvocation);
-           } else {
-                dataProcessors.push(p);
-           }
-        });
-        this.pipeline.sepas = dataProcessors;
+  }
+
+  updateDataProcessor() {
+    const dataProcessors: DataProcessorInvocation[] = [];
+    this.pipeline.sepas.forEach(p => {
+      if (p.dom === this._selectedElement.dom) {
+        dataProcessors.push(this._selectedElement as DataProcessorInvocation);
+      } else {
+        dataProcessors.push(p);
+      }
+    });
+    this.pipeline.sepas = dataProcessors;
+  }
+
+  updateDataSink() {
+    const dataSinks: DataSinkInvocation[] = [];
+    this.pipeline.actions.forEach(p => {
+      if (p.dom === this._selectedElement.dom) {
+        dataSinks.push(this._selectedElement as DataSinkInvocation);
+      } else {
+        dataSinks.push(p);
+      }
+    });
+    this.pipeline.actions = dataSinks;
+  }
+
+  get selectedElement() {
+    return this._selectedElement;
+  }
+
+  @Input()
+  set selectedElement(selectedElement: PipelineElementUnion) {
+    if (this._selectedElement) {
+      this.updatePipelineElement();
     }
-
-    updateDataSink() {
-        const dataSinks: DataSinkInvocation[] = [];
-        this.pipeline.actions.forEach(p => {
-            if (p.dom === this._selectedElement.dom) {
-                dataSinks.push(this._selectedElement as DataSinkInvocation);
-            } else {
-                dataSinks.push(p);
-            }
-        });
-        this.pipeline.actions = dataSinks;
+    this._selectedElement = selectedElement;
+    this.eventSchemas = [];
+    if (this._selectedElement instanceof DataProcessorInvocation || this._selectedElement instanceof DataSinkInvocation) {
+      (this._selectedElement as any).inputStreams.forEach(is => {
+        this.eventSchemas = this.eventSchemas.concat(is.eventSchema);
+      });
     }
+    this.updateTypeInfo();
+  }
 
-    get selectedElement() {
-        return this._selectedElement;
-    }
+  updateTypeInfo() {
+    this.isDataProcessor = this._selectedElement instanceof DataProcessorInvocation;
+    this.isInvocable = this._selectedElement instanceof DataProcessorInvocation ||
+      this._selectedElement instanceof DataSinkInvocation;
+  }
 
-    @Input()
-    set selectedElement(selectedElement: PipelineElementUnion) {
-        if (this._selectedElement) {
-            this.updatePipelineElement();
-        }
-        this._selectedElement = selectedElement;
-        this.eventSchemas = [];
-        if (this._selectedElement instanceof DataProcessorInvocation || this._selectedElement instanceof DataSinkInvocation) {
-            (this._selectedElement as any).inputStreams.forEach(is => {
-                this.eventSchemas = this.eventSchemas.concat(is.eventSchema);
-            });
-        }
-        this.updateTypeInfo();
-    }
+  selectElement(element: PipelineElementUnion) {
+    this.selectedElement = element;
+  }
 
-    updateTypeInfo() {
-        this.isDataProcessor = this._selectedElement instanceof DataProcessorInvocation;
-        this.isInvocable = this._selectedElement instanceof DataProcessorInvocation ||
-            this._selectedElement instanceof DataSinkInvocation;
-    }
+  onPipelineAvailable(): void {
+  }
 }
 
diff --git a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html
index 4c27a4634..3f4b4c109 100644
--- a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html
+++ b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.html
@@ -16,51 +16,52 @@
   ~
   -->
 
+<sp-basic-nav-tabs [spNavigationItems]="tabs"
+                   [activeLink]="'monitoring'"
+                   [showBackLink]="true"
+                   [backLinkTarget]="['pipelines']">
 
-<div fxFlex="100" fxLayout="column">
-    <div fxLayout="column" class="fixed-height add-options">
-        <div class="add-options-item" fxLayoutAlign="start center" fxLayout="row" style="padding-right:10px;">
-            <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
-                <mat-slide-toggle [(ngModel)]="autoRefresh" color="accent">Auto refresh</mat-slide-toggle>
-            </div>
-        </div>
+    <div nav fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
+        <mat-slide-toggle [(ngModel)]="autoRefresh" color="accent">Auto refresh</mat-slide-toggle>
     </div>
-    <div fxFlex="100" fxLayout="column" class="page-container-padding-inner">
-        <div fxFlex="100" *ngIf="!pipeline.running" fxLayout="column" fxLayoutAlign="center center">
-            <div class="error-message">(monitoring info is only available for running pipelines)</div>
-            <button mat-button mat-raised-button color="accent"
-                    matTooltip="Start Pipeline" matTooltipPosition="above"
-                    *ngIf="hasPipelineWritePrivileges"
-                    (click)="startPipeline()">
-                <mat-icon>play_arrow</mat-icon>
-                <span>&nbsp;Start pipeline</span>
-            </button>
-        </div>
-        <div fxFlex="100" *ngIf="pipeline.running && pipelineMonitoringInfoAvailable">
-            <div *ngFor="let pipelineElement of allElements" fxLayout="column" class="mb-10">
-                <div class="assembly-options-preview sp-blue-bg" [id]="pipelineElement.elementId">
-                    <div fxLayout="row" fxLayoutAlign="start center">
-                        <h4>{{pipelineElement.name}}</h4>
-                    </div>
-                </div>
-                <div class="sp-blue-border pipeline-element-statistics-panel">
-                    <div fxFlex="100" fxLayout="row">
-                        <div fxFlex="20" fxLayoutAlign="start start">
-                            <pipeline-elements-row style="width: 100%;"
-                                                   [showDescription]="false"
-                                                   [pipeline]="pipeline"
-                                                   [element]="pipelineElement"></pipeline-elements-row>
+    <div fxLayout="column" class="page-container-padding" *ngIf="pipeline">
+        <div fxFlex="100" fxLayout="column" class="page-container-padding-inner">
+            <div fxFlex="100" *ngIf="!pipeline.running" fxLayout="column" fxLayoutAlign="center center">
+                <div class="error-message">(monitoring info is only available for running pipelines)</div>
+                <button mat-button mat-raised-button color="accent"
+                        matTooltip="Start Pipeline" matTooltipPosition="above"
+                        *ngIf="hasPipelineWritePrivileges"
+                        (click)="startPipeline()">
+                    <mat-icon>play_arrow</mat-icon>
+                    <span>&nbsp;Start pipeline</span>
+                </button>
+            </div>
+            <div fxFlex="100" *ngIf="pipeline.running && pipelineMonitoringInfoAvailable">
+                <div *ngFor="let pipelineElement of allElements" fxLayout="column" class="mb-10">
+                    <div class="assembly-options-preview sp-blue-bg" [id]="pipelineElement.elementId">
+                        <div fxLayout="row" fxLayoutAlign="start center">
+                            <h4>{{pipelineElement.name}}</h4>
                         </div>
-                        <div fxFlex="80" fxLayoutAlign="start center">
-                            <pipeline-element-statistics
-                                    [pipeline]="pipeline"
-                                    [pipelineElement]="pipelineElement"
-                                    [pipelineElementMonitoringInfo]="pipelineElementMonitoringInfo.get(pipelineElement.elementId)">
-                            </pipeline-element-statistics>
+                    </div>
+                    <div class="sp-blue-border pipeline-element-statistics-panel">
+                        <div fxFlex="100" fxLayout="row">
+                            <div fxFlex="20" fxLayoutAlign="start start">
+                                <pipeline-elements-row style="width: 100%;"
+                                                       [showDescription]="false"
+                                                       [pipeline]="pipeline"
+                                                       [element]="pipelineElement"></pipeline-elements-row>
+                            </div>
+                            <div fxFlex="80" fxLayoutAlign="start center">
+                                <pipeline-element-statistics
+                                        [pipeline]="pipeline"
+                                        [pipelineElement]="pipelineElement"
+                                        [pipelineElementMonitoringInfo]="pipelineElementMonitoringInfo.get(pipelineElement.elementId)">
+                                </pipeline-element-statistics>
+                            </div>
                         </div>
                     </div>
                 </div>
             </div>
         </div>
     </div>
-</div>
+</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts
index ea83eda39..3cff74f74 100644
--- a/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts
+++ b/ui/src/app/pipeline-details/components/monitoring/pipeline-monitoring.component.ts
@@ -16,29 +16,28 @@
  *
  */
 
-import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
 import {
-  DataProcessorInvocation, DataSinkInvocation,
-  Pipeline, PipelineElementMonitoringInfo,
+  DataProcessorInvocation,
+  DataSinkInvocation,
+  PipelineElementMonitoringInfo,
   PipelineMonitoringInfo,
-  SpDataSet, SpDataStream
+  PipelineMonitoringService,
+  PipelineService,
+  SpDataSet,
+  SpDataStream
 } from '@streampipes/platform-services';
-import { PipelineMonitoringService } from '@streampipes/platform-services';
 import { PipelineOperationsService } from '../../../pipelines/services/pipeline-operations.service';
 import { AuthService } from '../../../services/auth.service';
-import { UserPrivilege } from '../../../_enums/user-privilege.enum';
+import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive';
+import { ActivatedRoute } from '@angular/router';
 
 @Component({
   selector: 'pipeline-monitoring',
   templateUrl: './pipeline-monitoring.component.html',
   styleUrls: ['./pipeline-monitoring.component.scss']
 })
-export class PipelineMonitoringComponent implements OnInit, OnDestroy {
-
-  _pipeline: Pipeline;
-
-  @Output()
-  reloadPipelineEmitter: EventEmitter<boolean> = new EventEmitter<boolean>();
+export class PipelineMonitoringComponent extends SpPipelineDetailsDirective implements OnInit, OnDestroy {
 
   pipelineMonitoringInfo: PipelineMonitoringInfo;
   pipelineMonitoringInfoAvailable = false;
@@ -49,19 +48,16 @@ export class PipelineMonitoringComponent implements OnInit, OnDestroy {
 
   pipelineElementMonitoringInfo: Map<string, PipelineElementMonitoringInfo>;
 
-  hasPipelineWritePrivileges = false;
-
-  constructor(private pipelineMonitoringService: PipelineMonitoringService,
-              private pipelineOperationsService: PipelineOperationsService,
-              private authService: AuthService) {
+  constructor(activatedRoute: ActivatedRoute,
+              pipelineService: PipelineService,
+              authService: AuthService,
+              private pipelineMonitoringService: PipelineMonitoringService,
+              private pipelineOperationsService: PipelineOperationsService) {
+    super(activatedRoute, pipelineService, authService);
   }
 
   ngOnInit(): void {
-    this.authService.user$.subscribe(user => {
-      this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE);
-    });
-    this.collectAllElements();
-    this.checkMonitoringInfoCollection();
+    super.onInit();
   }
 
   checkMonitoringInfoCollection() {
@@ -104,17 +100,12 @@ export class PipelineMonitoringComponent implements OnInit, OnDestroy {
   }
 
   startPipeline() {
-    this.pipelineOperationsService.startPipeline(this.pipeline._id, this.reloadPipelineEmitter);
+    //this.pipelineOperationsService.startPipeline(this.pipeline._id, () => this.loadPipeline());
   }
 
-  @Input()
-  set pipeline(pipeline: Pipeline) {
-    this._pipeline = pipeline;
+  onPipelineAvailable(): void {
+    this.collectAllElements();
     this.checkMonitoringInfoCollection();
   }
 
-  get pipeline() {
-    return this._pipeline;
-  }
-
 }
diff --git a/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html
new file mode 100644
index 000000000..eca67efd2
--- /dev/null
+++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.html
@@ -0,0 +1,46 @@
+<!--
+  ~ 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.
+  ~
+  -->
+
+<sp-basic-nav-tabs [spNavigationItems]="tabs" [activeLink]="'overview'" [showBackLink]="true" [backLinkTarget]="['pipelines']">
+    <div fxLayout="column" class="page-container-padding">
+        <div fxFlex="100" fxLayout="column">
+            <pipeline-preview [jspcanvas]="'assembly-preview'"
+                              [pipeline]="pipeline"
+                              (selectedElementEmitter)="selectElement($event)"
+                              style="margin-bottom:15px;"
+                              class="md-padding"
+                              *ngIf="pipelineAvailable"></pipeline-preview>
+            <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable">
+                <div fxFlex="60" class="md-padding">
+                    <div fxFlex fxLayout="column">
+                        <pipeline-elements [pipeline]="pipeline"
+                                           [selectedElement]="selectedElement"></pipeline-elements>
+                    </div>
+                </div>
+                <div fxFlex="40" class="md-padding">
+                    <div fxFlex fxLayout="column">
+                        <pipeline-actions (reloadPipelineEmitter)="loadPipeline()" [pipeline]="pipeline"
+                                          style="margin-bottom:15px;"
+                                          *ngIf="hasPipelineWritePrivileges"></pipeline-actions>
+                        <pipeline-status [pipeline]="pipeline"></pipeline-status>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</sp-basic-nav-tabs>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.scss b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss
similarity index 99%
rename from ui/src/app/pipeline-details/pipeline-details.component.scss
rename to ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss
index a375af7ff..1100ab49e 100644
--- a/ui/src/app/pipeline-details/pipeline-details.component.scss
+++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.scss
@@ -19,4 +19,3 @@
 .md-padding {
   padding: 10px;
 }
-
diff --git a/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts
new file mode 100644
index 000000000..2ace0e015
--- /dev/null
+++ b/ui/src/app/pipeline-details/components/overview/pipeline-details-overview.component.ts
@@ -0,0 +1,54 @@
+/*
+ * 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, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { SpPipelineDetailsDirective } from '../sp-pipeline-details.directive';
+import { AuthService } from '../../../services/auth.service';
+import { PipelineService } from '@streampipes/platform-services';
+import { PipelineElementUnion } from '../../../editor/model/editor.model';
+
+@Component({
+  selector: 'sp-pipeline-details-overview-component',
+  templateUrl: './pipeline-details-overview.component.html',
+  styleUrls: ['./pipeline-details-overview.component.scss']
+})
+export class SpPipelineDetailsOverviewComponent extends SpPipelineDetailsDirective implements OnInit {
+
+  tabs = [];
+  selectedElement: PipelineElementUnion;
+
+  constructor(activatedRoute: ActivatedRoute,
+              pipelineService: PipelineService,
+              authService: AuthService) {
+    super(activatedRoute, pipelineService, authService);
+  }
+
+  ngOnInit(): void {
+    super.onInit();
+  }
+
+  selectElement(element: PipelineElementUnion) {
+    this.selectedElement = element;
+  }
+
+  onPipelineAvailable(): void {
+  }
+
+
+}
diff --git a/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts b/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts
new file mode 100644
index 000000000..bf4bb26b0
--- /dev/null
+++ b/ui/src/app/pipeline-details/components/sp-pipeline-details.directive.ts
@@ -0,0 +1,66 @@
+/*
+ * 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 { Directive } from '@angular/core';
+import { UserPrivilege } from '../../_enums/user-privilege.enum';
+import { ActivatedRoute } from '@angular/router';
+import { AuthService } from '../../services/auth.service';
+import { Pipeline, PipelineService } from '@streampipes/platform-services';
+import { SpPipelineDetailsTabs } from '../pipeline-details-tabs';
+
+@Directive()
+export abstract class SpPipelineDetailsDirective {
+
+  tabs = [];
+  hasPipelineWritePrivileges = false;
+  hasPipelineDeletePrivileges = false;
+
+  currentPipeline: string;
+  pipeline: Pipeline;
+  pipelineAvailable = false;
+
+  constructor(protected activatedRoute: ActivatedRoute,
+              protected pipelineService: PipelineService,
+              protected authService: AuthService) {
+  }
+
+  onInit(): void {
+    this.authService.user$.subscribe(user => {
+      this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE);
+      this.hasPipelineDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_PIPELINE);
+      const pipelineId = this.activatedRoute.snapshot.params.pipelineId;
+      if (pipelineId) {
+        this.tabs = new SpPipelineDetailsTabs().getTabs(pipelineId);
+        this.currentPipeline = pipelineId;
+        this.loadPipeline();
+      }
+    });
+  }
+
+  loadPipeline(): void {
+    this.pipelineService.getPipelineById(this.currentPipeline)
+      .subscribe(pipeline => {
+        this.pipeline = pipeline;
+        this.pipelineAvailable = true;
+        this.onPipelineAvailable();
+      });
+  }
+
+  abstract onPipelineAvailable(): void;
+
+}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts b/ui/src/app/pipeline-details/pipeline-details-tabs.ts
similarity index 56%
copy from ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
copy to ui/src/app/pipeline-details/pipeline-details-tabs.ts
index bdace86dd..966c4a748 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/components/basic-nav-tabs/basic-nav-tabs.component.ts
+++ b/ui/src/app/pipeline-details/pipeline-details-tabs.ts
@@ -16,28 +16,16 @@
  *
  */
 
-import { Component, Input } from '@angular/core';
-import { Router } from '@angular/router';
-import { SpNavigationItem } from '../../models/sp-navigation.model';
+import { SpNavigationItem } from '@streampipes/shared-ui';
 
-@Component({
-  selector: 'sp-basic-nav-tabs',
-  templateUrl: './basic-nav-tabs.component.html',
-  styleUrls: ['./basic-nav-tabs.component.scss']
-})
-export class SpBasicNavTabsComponent {
+export class SpPipelineDetailsTabs {
 
-  @Input()
-  spNavigationItems: SpNavigationItem[];
-
-  @Input()
-  activeLink: string;
-
-  constructor(private router: Router) {
-
-  }
-
-  navigateTo(spNavigationItem: SpNavigationItem) {
-    this.router.navigate(spNavigationItem.itemLink);
+  public getTabs(pipelineId: string): SpNavigationItem[] {
+    return [
+      {itemId: 'overview', itemTitle: 'Overview', itemLink: ['pipelines', 'details', pipelineId, 'overview']},
+      {itemId: 'monitoring', itemTitle: 'Monitoring', itemLink: ['pipelines', 'details', pipelineId, 'monitoring']},
+      // {itemId: 'errors', itemTitle: 'Errors', itemLink: ['pipelines', 'details', pipelineId, 'errors']},
+      {itemId: 'quick-edit', itemTitle: 'Quick Edit', itemLink: ['pipelines', 'details', pipelineId, 'quick-edit']}
+    ];
   }
 }
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.html b/ui/src/app/pipeline-details/pipeline-details.component.html
deleted file mode 100644
index 2733ce184..000000000
--- a/ui/src/app/pipeline-details/pipeline-details.component.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!--
-  ~ 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 fxLayout="column" class="page-container">
-    <div fxLayout="row" class="border sp-tab-bg" style="padding:0px">
-        <div fxFlex="100" class="page-container-nav">
-            <div fxFlex="100" fxLayout="row">
-                <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="setSelectedIndex($event)" color="accent">
-                    <mat-tab label="Overview"></mat-tab>
-                    <mat-tab label="Monitoring"></mat-tab>
-                    <mat-tab label="Errors"></mat-tab>
-                    <mat-tab label="Quick Edit" [disabled]="pipelineAvailable && pipeline.running" *ngIf="hasPipelineWritePrivileges"></mat-tab>
-                </mat-tab-group>
-            </div>
-        </div>
-    </div>
-    <div fxFlex="100" fxLayout="column">
-        <pipeline-preview [jspcanvas]="'assembly-preview'"
-                          [pipeline]="pipeline"
-                          (selectedElementEmitter)="selectElement($event)"
-                          style="margin-bottom:15px;"
-                          class="md-padding"
-                          *ngIf="pipelineAvailable"></pipeline-preview>
-    <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 0">
-        <div fxFlex="60" class="md-padding">
-            <div fxFlex fxLayout="column">
-                <pipeline-elements [pipeline]="pipeline"
-                                   [selectedElement]="selectedElement"></pipeline-elements>
-            </div>
-        </div>
-        <div fxFlex="40" class="md-padding">
-            <div fxFlex fxLayout="column">
-                <pipeline-actions (reloadPipelineEmitter)="loadPipeline()" [pipeline]="pipeline"
-                                  style="margin-bottom:15px;" *ngIf="hasPipelineWritePrivileges"></pipeline-actions>
-                <pipeline-status [pipeline]="pipeline"></pipeline-status>
-            </div>
-        </div>
-    </div>
-    <div fxFlex fxLayout="column" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 1">
-        <pipeline-monitoring [pipeline]="pipeline" (reloadPipelineEmitter)="loadPipeline()"></pipeline-monitoring>
-    </div>
-    <div fxFlex fxLayout="row" fxLayoutAlign="start top" *ngIf="pipelineAvailable && selectedIndex == 3">
-        <div fxFlex="100" class="md-padding">
-            <div fxFlex fxLayout="column">
-                <quick-edit [pipeline]="pipeline" [selectedElement]="selectedElement" (reloadPipelineEmitter)="loadPipeline()"></quick-edit>
-            </div>
-        </div>
-    </div>
-    </div>
-</div>
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.ts b/ui/src/app/pipeline-details/pipeline-details.component.ts
deleted file mode 100644
index 93508741f..000000000
--- a/ui/src/app/pipeline-details/pipeline-details.component.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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, OnInit } from '@angular/core';
-import { Pipeline, PipelineService } from '@streampipes/platform-services';
-import { PipelineElementUnion } from '../editor/model/editor.model';
-import { ActivatedRoute } from '@angular/router';
-import { AuthService } from '../services/auth.service';
-import { UserPrivilege } from '../_enums/user-privilege.enum';
-
-@Component({
-    selector: 'pipeline-details',
-    templateUrl: './pipeline-details.component.html',
-    styleUrls: ['./pipeline-details.component.scss']
-})
-export class PipelineDetailsComponent implements OnInit {
-
-    currentPipeline: string;
-    pipeline: Pipeline;
-    pipelineAvailable = false;
-
-    selectedIndex = 0;
-    selectedElement: PipelineElementUnion;
-
-    hasPipelineWritePrivileges = false;
-    hasPipelineDeletePrivileges = false;
-
-    constructor(private activatedRoute: ActivatedRoute,
-                private pipelineService: PipelineService,
-                private authService: AuthService) {
-    }
-
-    ngOnInit() {
-        this.authService.user$.subscribe(user => {
-            this.hasPipelineWritePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_WRITE_PIPELINE);
-            this.hasPipelineDeletePrivileges = this.authService.hasRole(UserPrivilege.PRIVILEGE_DELETE_PIPELINE);
-        });
-        this.activatedRoute.queryParams.subscribe(params => {
-            if (params['pipeline']) {
-                this.currentPipeline = params['pipeline'];
-                this.loadPipeline();
-            }
-        });
-    }
-
-    setSelectedIndex(index: number) {
-        this.selectedIndex = index;
-    }
-
-    loadPipeline() {
-        this.pipelineService.getPipelineById(this.currentPipeline)
-            .subscribe(pipeline => {
-                this.pipeline = pipeline;
-                this.pipelineAvailable = true;
-            });
-    }
-
-    selectElement(element: PipelineElementUnion) {
-        this.selectedElement = element;
-    }
-
-}
diff --git a/ui/src/app/pipeline-details/pipeline-details.module.ts b/ui/src/app/pipeline-details/pipeline-details.module.ts
index 8978f7df8..7afc3a8cb 100644
--- a/ui/src/app/pipeline-details/pipeline-details.module.ts
+++ b/ui/src/app/pipeline-details/pipeline-details.module.ts
@@ -24,7 +24,6 @@ import { MatButtonModule } from '@angular/material/button';
 import { CustomMaterialModule } from '../CustomMaterial/custom-material.module';
 import { CommonModule } from '@angular/common';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
-import { PipelineDetailsComponent } from './pipeline-details.component';
 import { PipelinePreviewComponent } from './components/preview/pipeline-preview.component';
 import { EditorModule } from '../editor/editor.module';
 import { PipelineActionsComponent } from './components/actions/pipeline-actions.component';
@@ -39,40 +38,42 @@ import { NgxChartsModule } from '@swimlane/ngx-charts';
 import { BarchartWidgetComponent } from './components/monitoring/widget/barchart/barchart-widget.component';
 import { StatusWidgetComponent } from './components/monitoring/widget/status/status-widget.component';
 import { PlatformServicesModule } from '@streampipes/platform-services';
+import { SpPipelineDetailsOverviewComponent } from './components/overview/pipeline-details-overview.component';
+import { SharedUiModule } from '@streampipes/shared-ui';
 
 @NgModule({
-    imports: [
-        CoreUiModule,
-        FlexLayoutModule,
-        FormsModule,
-        MatTabsModule,
-        MatButtonModule,
-        CustomMaterialModule,
-        CommonModule,
-        MatProgressSpinnerModule,
-        NgxChartsModule,
-        EditorModule,
-        FormsModule,
-        ReactiveFormsModule,
-        PlatformServicesModule
-    ],
-    declarations: [
-        PipelineActionsComponent,
-        PipelineElementsComponent,
-        PipelineElementsRowComponent,
-        PipelineElementStatisticsComponent,
-        PipelineDetailsComponent,
-        PipelineMonitoringComponent,
-        PipelineStatusComponent,
-        PipelinePreviewComponent,
-        QuickEditComponent,
-        StatusWidgetComponent,
-        BarchartWidgetComponent
-    ],
-    providers: [],
-    exports: [
-        PipelineDetailsComponent
-    ]
+  imports: [
+    CoreUiModule,
+    FlexLayoutModule,
+    FormsModule,
+    MatTabsModule,
+    MatButtonModule,
+    CustomMaterialModule,
+    CommonModule,
+    MatProgressSpinnerModule,
+    NgxChartsModule,
+    EditorModule,
+    FormsModule,
+    ReactiveFormsModule,
+    PlatformServicesModule,
+    SharedUiModule
+  ],
+  declarations: [
+    PipelineActionsComponent,
+    PipelineElementsComponent,
+    PipelineElementsRowComponent,
+    PipelineElementStatisticsComponent,
+    PipelineMonitoringComponent,
+    PipelineStatusComponent,
+    PipelinePreviewComponent,
+    QuickEditComponent,
+    StatusWidgetComponent,
+    BarchartWidgetComponent,
+    SpPipelineDetailsOverviewComponent,
+  ],
+  providers: [],
+  exports: [
+  ]
 })
 export class PipelineDetailsModule {
 
diff --git a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss
index c2bef2352..7f1e8435c 100644
--- a/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss
+++ b/ui/src/app/pipelines/components/pipeline-overview/pipeline-overview.component.scss
@@ -25,10 +25,10 @@
 }
 
 .mat-row:nth-child(even) {
-  background-color: var(--color-bg-2);
+  background-color: var(--color-bg-1);
 }
 .mat-row:nth-child(odd) {
-  background-color: var(--color-bg-3);
+  background-color: var(--color-bg-2);
 }
 
 .mat-column-status {
diff --git a/ui/src/app/pipelines/pipelines.component.html b/ui/src/app/pipelines/pipelines.component.html
index cb8f87e08..71835b494 100644
--- a/ui/src/app/pipelines/pipelines.component.html
+++ b/ui/src/app/pipelines/pipelines.component.html
@@ -16,65 +16,69 @@
   ~
   -->
 
-<div fxLayout="column" class="page-container">
-    <div fxLayout="row" class="border sp-tab-bg" style="padding:0;">
-        <div fxFlex="100" class="page-container-nav">
-            <div fxFlex="100" fxLayout="row">
-                <button mat-button mat-flat-button color="accent" (click)="showPipelineCategoriesDialog()">Manage Categories</button>
-                <div fxFlex fxLayoutAlign="start center" [attr.id]="'peType'">
-                    <mat-tab-group [selectedIndex]="selectedCategoryIndex" (selectedIndexChange)="setSelectedTab($event)" color="accent">
-                        <mat-tab label="All pipelines"></mat-tab>
-                        <mat-tab *ngFor="let category of pipelineCategories" label="{{category.categoryName}}"></mat-tab>
-                    </mat-tab-group>
-                </div>
-            </div>
-        </div>
+<sp-basic-view [showBackLink]="false" [padding]="true">
+    <div nav fxFlex="100" fxLayoutAlign="start center" fxLayout="row" class="pl-10">
+        <button mat-button mat-raised-button color="accent" (click)="navigateToPipelineEditor()">
+            <i class="material-icons">add</i>&nbsp;New pipeline
+        </button>
+        <button class="mr-10" mat-button color="accent" (click)="startAllPipelines(true)"
+                [disabled]="checkCurrentSelectionStatus(false)" *ngIf="hasPipelineWritePrivileges">
+            <mat-icon>play_arrow</mat-icon><span>Start all pipelines</span>
+        </button>
+        <button mat-button color="accent" (click)="startAllPipelines(false)"
+                [disabled]="checkCurrentSelectionStatus(true)" *ngIf="hasPipelineWritePrivileges">
+            <mat-icon>stop</mat-icon>
+            <span>Stop all pipelines</span>
+        </button>
+        <span fxFlex></span>
+        <button mat-button mat-icon-button color="accent" matTooltip="Refresh pipelines" matTooltipPosition="above"
+                (click)="refreshPipelines()">
+            <i class="material-icons">
+                refresh
+            </i>
+        </button>
+        <button mat-button mat-icon-button color="accent" matTooltip="Export pipelines" matTooltipPosition="above"
+                (click)="exportPipelines()">
+            <i class="material-icons">
+                cloud_download
+            </i>
+        </button>
+        <button mat-button mat-icon-button color="accent" matTooltip="Import pipelines" matTooltipPosition="above"
+                (click)="openImportPipelinesDialog()">
+            <i class="material-icons">
+                cloud_upload
+            </i>
+        </button>
     </div>
-    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100">
-        <div fxLayout="row">
-            <button class="mr-10" mat-button mat-raised-button color="accent" (click)="startAllPipelines(true)"
-                       [disabled]="checkCurrentSelectionStatus(false)" *ngIf="hasPipelineWritePrivileges">Start all pipelines
-            </button>
-            <button mat-button mat-raised-button color="accent" (click)="startAllPipelines(false)"
-                       [disabled]="checkCurrentSelectionStatus(true)" *ngIf="hasPipelineWritePrivileges">Stop all pipelines
-            </button>
-        </div>
-        <div class="assemblyOptions sp-blue-bg mt-20" style="padding:5px;">
-            <div fxLayout="row" fxLayoutAlign="start center">
-                <h4>My pipelines</h4>
-                <span fxFlex></span>
-                <button mat-button mat-icon-button matTooltip="Refresh pipelines" matTooltipPosition="above"
-                        (click)="refreshPipelines()">
-                    <i class="material-icons">
-                        refresh
-                    </i>
-                </button>
-                <button mat-button mat-icon-button matTooltip="Export pipelines" matTooltipPosition="above"
-                        (click)="exportPipelines()">
-                    <i class="material-icons">
-                        cloud_download
-                    </i>
-                </button>
-                <button mat-button mat-icon-button matTooltip="Import pipelines" matTooltipPosition="above"
-                        (click)="openImportPipelinesDialog()">
-                    <i class="material-icons">
-                        cloud_upload
-                    </i>
-                </button>
+    <div fxFlex="100" fxLayout="column">
+        <div fxLayout="column">
+            <sp-basic-header-title-component title="My pipelines"></sp-basic-header-title-component>
+            <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
+                <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90"
+                                      [hideToolbar]="true">
+                    <div fxFlex="100">
+                        <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="pipelines"
+                                           [pipelineToStart]="pipelineToStart"
+                                           (refreshPipelinesEmitter)="refreshPipelines()"
+                                           *ngIf="pipelinesReady"></pipeline-overview>
+                    </div>
+                </sp-basic-inner-panel>
+            </div>
+            <div fxFlex="100" fxLayout="column" style="margin-top: 20px;">
+                <sp-basic-header-title-component title="System-generated pipelines"></sp-basic-header-title-component>
+                <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
+                    <sp-basic-inner-panel [showTitle]="false" innerPadding="0" outerMargin="0" fxFlex="90"
+                                          [hideToolbar]="true">
+                        <div fxFlex="100">
+                            <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="systemPipelines"
+                                               [pipelineToStart]="systemPipelineToStart"
+                                               (refreshPipelinesEmitter)="refreshPipelines()"
+                                               *ngIf="pipelinesReady"></pipeline-overview>
+                        </div>
+                    </sp-basic-inner-panel>
+                </div>
             </div>
-        </div>
-        <div class="sp-blue-border">
-            <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="pipelines" [pipelineToStart]="pipelineToStart"
-                              (refreshPipelinesEmitter)="refreshPipelines()" *ngIf="pipelinesReady"></pipeline-overview>
-        </div>
-        <div style="margin-top:20px;margin-bottom:20px;"></div>
-        <div class="assemblyOptions sp-blue-bg">
-            <h4>System-generated pipelines</h4>
-        </div>
-        <div class="sp-blue-border">
-            <pipeline-overview [activeCategoryId]="activeCategoryId" [pipelines]="systemPipelines" [pipelineToStart]="systemPipelineToStart"
-                              (refreshPipelinesEmitter)="refreshPipelines()" *ngIf="pipelinesReady"></pipeline-overview>
         </div>
     </div>
-</div>
+</sp-basic-view>
 
diff --git a/ui/src/app/pipelines/pipelines.component.ts b/ui/src/app/pipelines/pipelines.component.ts
index 316810dbf..c1177fcc6 100644
--- a/ui/src/app/pipelines/pipelines.component.ts
+++ b/ui/src/app/pipelines/pipelines.component.ts
@@ -24,7 +24,7 @@ import { ImportPipelineDialogComponent } from './dialog/import-pipeline/import-p
 import { StartAllPipelinesDialogComponent } from './dialog/start-all-pipelines/start-all-pipelines-dialog.component';
 import { PipelineCategoriesDialogComponent } from './dialog/pipeline-categories/pipeline-categories-dialog.component';
 import { zip } from 'rxjs';
-import { ActivatedRoute } from '@angular/router';
+import { ActivatedRoute, Router } from '@angular/router';
 import { AuthService } from '../services/auth.service';
 import { UserPrivilege } from '../_enums/user-privilege.enum';
 
@@ -56,7 +56,8 @@ export class PipelinesComponent implements OnInit {
   constructor(private pipelineService: PipelineService,
               private dialogService: DialogService,
               private activatedRoute: ActivatedRoute,
-              private authService: AuthService) {
+              private authService: AuthService,
+              private router: Router) {
     this.pipelineCategories = [];
     this.starting = false;
     this.stopping = false;
@@ -192,4 +193,8 @@ export class PipelinesComponent implements OnInit {
   showPipeline(pipeline) {
     pipeline.display = !pipeline.display;
   }
+
+  navigateToPipelineEditor() {
+    this.router.navigate(['pipelines', 'create']);
+  }
 }
diff --git a/ui/src/app/pipelines/pipelines.module.ts b/ui/src/app/pipelines/pipelines.module.ts
index 0049362d5..17ca3ecef 100644
--- a/ui/src/app/pipelines/pipelines.module.ts
+++ b/ui/src/app/pipelines/pipelines.module.ts
@@ -39,6 +39,14 @@ import { MatTableModule } from '@angular/material/table';
 import { PipelineNotificationsComponent } from './dialog/pipeline-notifications/pipeline-notifications.component';
 import { CoreUiModule } from '../core-ui/core-ui.module';
 import { PlatformServicesModule } from '@streampipes/platform-services';
+import { SharedUiModule } from '../../../projects/streampipes/shared-ui/src/lib/shared-ui.module';
+import { EditorModule } from '../editor/editor.module';
+import { PipelineDetailsModule } from '../pipeline-details/pipeline-details.module';
+import { RouterModule } from '@angular/router';
+import { EditorComponent } from '../editor/editor.component';
+import { SpPipelineDetailsOverviewComponent } from '../pipeline-details/components/overview/pipeline-details-overview.component';
+import { PipelineMonitoringComponent } from '../pipeline-details/components/monitoring/pipeline-monitoring.component';
+import { QuickEditComponent } from '../pipeline-details/components/edit/quickedit.component';
 
 @NgModule({
   imports: [
@@ -53,6 +61,50 @@ import { PlatformServicesModule } from '@streampipes/platform-services';
     MatTableModule,
     CoreUiModule,
     PlatformServicesModule,
+    EditorModule,
+    PipelineDetailsModule,
+    SharedUiModule,
+    RouterModule.forChild([
+      {
+        path: 'pipelines',
+        children: [
+          {
+            path: '',
+            component: PipelinesComponent
+          },
+          {
+            path: 'details/:pipelineId',
+            children: [
+              {
+                path: '',
+                redirectTo: 'overview',
+                pathMatch: 'full'
+              },
+              {
+                path: 'overview',
+                component: SpPipelineDetailsOverviewComponent,
+              },
+              {
+                path: 'monitoring',
+                component: PipelineMonitoringComponent,
+              },
+              {
+                path: 'quick-edit',
+                component: QuickEditComponent,
+              }
+            ]
+          },
+          {
+            path: 'create',
+            component: EditorComponent
+          },
+          {
+            path: 'modify/:pipelineId',
+            component: EditorComponent
+          }
+        ]
+      }
+    ]),
   ],
   declarations: [
     DeletePipelineDialogComponent,
diff --git a/ui/src/app/pipelines/services/pipeline-operations.service.ts b/ui/src/app/pipelines/services/pipeline-operations.service.ts
index 0135fcab8..997d0f1dd 100644
--- a/ui/src/app/pipelines/services/pipeline-operations.service.ts
+++ b/ui/src/app/pipelines/services/pipeline-operations.service.ts
@@ -141,12 +141,12 @@ export class PipelineOperationsService {
     });
   }
 
-  showPipelineInEditor(id) {
-    this.router.navigate(['editor'], { queryParams: { pipeline: id }});
+  showPipelineInEditor(id: string) {
+    this.router.navigate(['pipelines', 'modify', id]);
   }
 
-  showPipelineDetails(id) {
-    this.router.navigate(['pipeline-details'], { queryParams: { pipeline: id }});
+  showPipelineDetails(id: string) {
+    this.router.navigate(['pipelines', 'details', id]);
   }
 
   modifyPipeline(pipeline) {