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 2021/10/03 18:36:32 UTC

[incubator-streampipes] branch STREAMPIPES-426 updated (6456656 -> c0c2a6e)

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

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


    from 6456656  [STREAMPIPES-436] Fix bug in client resolver
     new 7c23310  [STREAMPIPES-437] Add initial authorization support
     new b2a3918  [hotfix] Extract configuration layout into wrapper component
     new c0c2a6e  [hotfix] Harmonize appearance of settings components

The 3 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:
 .../client/user/JwtAuthenticationResponse.java     |  17 +--
 .../apache/streampipes/model/client/user/Role.java |  15 ++-
 .../streampipes/model/client/user/UserAccount.java |   4 +-
 .../streampipes/model/client/user/UserInfo.java    |   7 +-
 .../setup/UserRegistrationInstallationStep.java    |   3 +-
 .../streampipes/rest/impl/Authentication.java      |  28 ++--
 .../streampipes/security/jwt/JwtTokenUtils.java    |  20 ++-
 .../user/management/jwt/JwtTokenProvider.java      |  37 +++++-
 ui/deployment/app-routing.module.mst               |   7 +-
 ui/deployment/base-navigation.component.mst        |  95 ++++++++------
 ui/deployment/home.service.mst                     |  12 +-
 ui/deployment/modules.yml                          |  11 +-
 ui/deployment/prebuild.js                          |   1 +
 .../page-name.enum.ts}                             |  23 ++--
 .../src/app/_enums/user-role.enum.ts               |  15 ++-
 ...vate.guard.ts => page-auth.can-active.guard.ts} |  23 ++--
 ui/src/app/app-routing.module.ts                   |  23 ++--
 .../app/configuration/configuration.component.html |  18 ++-
 ui/src/app/configuration/configuration.module.ts   |   8 +-
 .../datalake-configuration.component.html          | 122 +++++++++---------
 .../messaging-configuration.component.html         | 142 ++++++++++-----------
 .../pipeline-element-configuration.component.html  |  92 +++++++------
 .../security-configuration.component.html}         |   0
 .../security-configuration.component.scss}         |   0
 .../security-configuration.component.ts}           |  12 +-
 ui/src/app/core-ui/core-ui.module.ts               |   5 +-
 .../split-section/split-section.component.html}    |  12 +-
 .../split-section/split-section.component.scss}    |  25 ++--
 .../split-section/split-section.component.ts}      |  17 +--
 .../core/components/base-navigation.component.ts   | 123 +++++++++++-------
 .../core/components/iconbar/iconbar.component.html |  26 ++--
 .../core/components/iconbar/iconbar.component.ts   |   4 +-
 .../core/components/toolbar/toolbar.component.ts   |  15 +--
 ui/src/app/home/home.component.ts                  |   2 +-
 .../general-profile-settings.component.html        |  52 +++-----
 .../general-profile-settings.component.scss        |  14 --
 .../token/token-management-settings.component.html | 102 +++++++--------
 .../token/token-management-settings.component.scss |  19 ---
 ui/src/app/profile/profile.module.ts               |   2 +
 ui/src/app/services/auth.service.ts                |  75 ++++++++++-
 ui/src/scss/sp/main.scss                           |   6 +
 41 files changed, 688 insertions(+), 546 deletions(-)
 copy ui/src/app/{data-explorer/components/widgets/utils/select-properties/select-properties.component.css => _enums/page-name.enum.ts} (79%)
 copy streampipes-model/src/main/java/org/apache/streampipes/model/pipeline/PipelineHealthStatus.java => ui/src/app/_enums/user-role.enum.ts (83%)
 copy ui/src/app/_guards/{configured.can-activate.guard.ts => page-auth.can-active.guard.ts} (64%)
 copy ui/src/app/{app-transport-monitoring/components/incoming/incoming-view.component.html => configuration/security-configuration/security-configuration.component.html} (100%)
 copy ui/src/app/{editor/components/pipeline-element-recommendation/pipeline-element-recommendation.component.scss => configuration/security-configuration/security-configuration.component.scss} (100%)
 copy ui/src/app/{connect/components/schema-editor/loading-message/loading-message.component.ts => configuration/security-configuration/security-configuration.component.ts} (78%)
 copy ui/src/app/{app-asset-monitoring/components/view-asset/view-asset.component.html => core-ui/split-section/split-section.component.html} (73%)
 copy ui/src/app/{profile/components/general/general-profile-settings.component.scss => core-ui/split-section/split-section.component.scss} (80%)
 copy ui/src/app/{data-explorer/components/widgets/utils/load-data-spinner/load-data-spinner.component.ts => core-ui/split-section/split-section.component.ts} (73%)

[incubator-streampipes] 02/03: [hotfix] Extract configuration layout into wrapper component

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

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

commit b2a3918457f0f0820d43f63766c6a40ece6fed42
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sun Oct 3 19:15:04 2021 +0200

    [hotfix] Extract configuration layout into wrapper component
---
 ui/src/app/configuration/configuration.module.ts   |   2 +
 .../security-configuration.component.html          |   0
 .../security-configuration.component.scss}         |  28 ------
 .../security-configuration.component.ts}           |  33 ++-----
 ui/src/app/core-ui/core-ui.module.ts               |   5 +-
 .../split-section/split-section.component.html     |  27 ++++++
 .../split-section/split-section.component.scss}    |  20 +---
 .../split-section/split-section.component.ts}      |  33 +++----
 .../general-profile-settings.component.html        |  52 +++++------
 .../general-profile-settings.component.scss        |  14 ---
 .../token/token-management-settings.component.html | 102 ++++++++++-----------
 .../token/token-management-settings.component.scss |  14 ---
 ui/src/app/profile/profile.module.ts               |   2 +
 13 files changed, 125 insertions(+), 207 deletions(-)

diff --git a/ui/src/app/configuration/configuration.module.ts b/ui/src/app/configuration/configuration.module.ts
index 9235675..cfa5f63 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -43,6 +43,7 @@ import { DatalakeConfigurationComponent } from './datalake-configuration/datalak
 import { DatalakeRestService } from '../core-services/datalake/datalake-rest.service';
 import { DeleteDatalakeIndexComponent } from './dialog/delete-datalake-index/delete-datalake-index-dialog.component';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { SecurityConfigurationComponent } from './security-configuration/security-configuration.component';
 
 @NgModule({
   imports: [
@@ -69,6 +70,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
     ConsulConfigsNumberComponent,
     DeleteDatalakeIndexComponent,
     PipelineElementConfigurationComponent,
+    SecurityConfigurationComponent,
     MessagingConfigurationComponent,
     DatalakeConfigurationComponent
   ],
diff --git a/ui/src/app/configuration/security-configuration/security-configuration.component.html b/ui/src/app/configuration/security-configuration/security-configuration.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.scss b/ui/src/app/configuration/security-configuration/security-configuration.component.scss
similarity index 69%
copy from ui/src/app/profile/components/general/general-profile-settings.component.scss
copy to ui/src/app/configuration/security-configuration/security-configuration.component.scss
index 0d460dd..13cbc4a 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.scss
+++ b/ui/src/app/configuration/security-configuration/security-configuration.component.scss
@@ -15,31 +15,3 @@
  * limitations under the License.
  *
  */
-
-.settings-title {
-  font-weight: bold;
-  font-size: 16pt;
-}
-
-.settings-description {
-  font-size: 12pt;
-}
-
-.profile-section {
-  border-right: 2px solid gray;
-  margin-right: 15px;
-}
-
-.title-section {
-  width: 300px;
-}
-
-.appearance-radio-group {
-  display: flex;
-  flex-direction: column;
-  margin: 15px 0;
-}
-
-.appearance-radio-button {
-  margin: 5px;
-}
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.scss b/ui/src/app/configuration/security-configuration/security-configuration.component.ts
similarity index 69%
copy from ui/src/app/profile/components/general/general-profile-settings.component.scss
copy to ui/src/app/configuration/security-configuration/security-configuration.component.ts
index 0d460dd..a4d9ed8 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.scss
+++ b/ui/src/app/configuration/security-configuration/security-configuration.component.ts
@@ -16,30 +16,15 @@
  *
  */
 
-.settings-title {
-  font-weight: bold;
-  font-size: 16pt;
-}
-
-.settings-description {
-  font-size: 12pt;
-}
-
-.profile-section {
-  border-right: 2px solid gray;
-  margin-right: 15px;
-}
-
-.title-section {
-  width: 300px;
-}
+import { Component, OnInit } from '@angular/core';
 
-.appearance-radio-group {
-  display: flex;
-  flex-direction: column;
-  margin: 15px 0;
-}
+@Component({
+  selector: 'sp-security-configuration',
+  templateUrl: './security-configuration.component.html',
+  styleUrls: ['./security-configuration.component.scss']
+})
+export class SecurityConfigurationComponent implements OnInit {
+  ngOnInit(): void {
+  }
 
-.appearance-radio-button {
-  margin: 5px;
 }
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index 64d1a6d..9c9a578 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -79,6 +79,7 @@ import { BarchartWidgetComponent } from './widget/barchart/barchart-widget.compo
 import { ErrorHintComponent } from './error-hint/error-hint.component';
 import { AddToCollectionComponent } from './static-properties/static-collection/add-to-collection/add-to-collection.component';
 import { PipelineStartedStatusComponent } from './pipeline/pipeline-started-status/pipeline-started-status.component';
+import { SplitSectionComponent } from './split-section/split-section.component';
 
 @NgModule({
   imports: [
@@ -117,6 +118,7 @@ import { PipelineStartedStatusComponent } from './pipeline/pipeline-started-stat
     ImageViewerComponent,
     StandardDialogComponent,
     PanelDialogComponent,
+    SplitSectionComponent,
     StaticAnyInput,
     StaticPropertyComponent,
     StaticFreeInputComponent,
@@ -178,7 +180,8 @@ import { PipelineStartedStatusComponent } from './pipeline/pipeline-started-stat
     StatusWidgetComponent,
     BarchartWidgetComponent,
     ErrorHintComponent,
-    PipelineStartedStatusComponent
+    PipelineStartedStatusComponent,
+    SplitSectionComponent
   ]
 })
 export class CoreUiModule {
diff --git a/ui/src/app/core-ui/split-section/split-section.component.html b/ui/src/app/core-ui/split-section/split-section.component.html
new file mode 100644
index 0000000..4cabfbe
--- /dev/null
+++ b/ui/src/app/core-ui/split-section/split-section.component.html
@@ -0,0 +1,27 @@
+<!--
+  ~ 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="row" fxFlex="100">
+    <div fxFlex="300px" fxLayout="column" class="split-section">
+        <div class="split-section-title">{{title}}</div>
+        <div class="split-section-description">{{subtitle}}</div>
+    </div>
+    <div fxFill fxLayout="column">
+        <ng-content></ng-content>
+    </div>
+</div>
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.scss b/ui/src/app/core-ui/split-section/split-section.component.scss
similarity index 79%
copy from ui/src/app/profile/components/general/general-profile-settings.component.scss
copy to ui/src/app/core-ui/split-section/split-section.component.scss
index 0d460dd..53d13f0 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.scss
+++ b/ui/src/app/core-ui/split-section/split-section.component.scss
@@ -16,30 +16,16 @@
  *
  */
 
-.settings-title {
+.split-section-title {
   font-weight: bold;
   font-size: 16pt;
 }
 
-.settings-description {
+.split-section-description {
   font-size: 12pt;
 }
 
-.profile-section {
+.split-section {
   border-right: 2px solid gray;
   margin-right: 15px;
 }
-
-.title-section {
-  width: 300px;
-}
-
-.appearance-radio-group {
-  display: flex;
-  flex-direction: column;
-  margin: 15px 0;
-}
-
-.appearance-radio-button {
-  margin: 5px;
-}
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.scss b/ui/src/app/core-ui/split-section/split-section.component.ts
similarity index 70%
copy from ui/src/app/profile/components/general/general-profile-settings.component.scss
copy to ui/src/app/core-ui/split-section/split-section.component.ts
index 0d460dd..7e66956 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.scss
+++ b/ui/src/app/core-ui/split-section/split-section.component.ts
@@ -16,30 +16,19 @@
  *
  */
 
-.settings-title {
-  font-weight: bold;
-  font-size: 16pt;
-}
-
-.settings-description {
-  font-size: 12pt;
-}
+import { Component, Input, OnDestroy, OnInit } from '@angular/core';
 
-.profile-section {
-  border-right: 2px solid gray;
-  margin-right: 15px;
-}
+@Component({
+  selector: 'sp-split-section',
+  templateUrl: './split-section.component.html',
+  styleUrls: ['./split-section.component.scss']
+})
+export class SplitSectionComponent {
 
-.title-section {
-  width: 300px;
-}
+  @Input()
+  title: string;
 
-.appearance-radio-group {
-  display: flex;
-  flex-direction: column;
-  margin: 15px 0;
-}
+  @Input()
+  subtitle: string;
 
-.appearance-radio-button {
-  margin: 5px;
 }
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.html b/ui/src/app/profile/components/general/general-profile-settings.component.html
index 19bf587..8a16d4e 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.html
+++ b/ui/src/app/profile/components/general/general-profile-settings.component.html
@@ -18,40 +18,30 @@
 
 <div fxLayout="row" class="page-container-padding">
     <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="profileLoaded">
-        <div fxLayout="row" fxFlex="100">
-            <div fxFlex="300px" fxLayout="column" class="profile-section">
-                <div class="settings-title">Main Settings</div>
-                <div class="settings-description">Manage your basic profile settings here.</div>
-            </div>
-            <div fxFill fxLayout="column">
-                <mat-form-field fxFlex>
-                    <mat-label>Email</mat-label>
-                    <input [(ngModel)]="userData.email" matInput type="email" name="email" disabled/>
-                    <mat-hint>Your mail address can't be changed currently.</mat-hint>
-                </mat-form-field>
-                <mat-form-field fxFlex>
-                    <mat-label>Username</mat-label>
-                    <input [(ngModel)]="userData.username" matInput/>
-                </mat-form-field>
-                <mat-form-field fxFlex>
-                    <mat-label>Full Name</mat-label>
-                    <input [(ngModel)]="userData.fullName" matInput/>
-                </mat-form-field>
-                <div>
-                    <button mat-button mat-raised-button color="accent"
+        <sp-split-section title="Main Settings" subtitle="Manage your basic profile settings here.">
+            <mat-form-field fxFlex>
+                <mat-label>Email</mat-label>
+                <input [(ngModel)]="userData.email" matInput type="email" name="email" disabled/>
+                <mat-hint>Your mail address can't be changed currently.</mat-hint>
+            </mat-form-field>
+            <mat-form-field fxFlex>
+                <mat-label>Username</mat-label>
+                <input [(ngModel)]="userData.username" matInput/>
+            </mat-form-field>
+            <mat-form-field fxFlex>
+                <mat-label>Full Name</mat-label>
+                <input [(ngModel)]="userData.fullName" matInput/>
+            </mat-form-field>
+            <div>
+                <button mat-button mat-raised-button color="accent"
                         (click)="saveProfileSettings()">
-                        Update profile
-                    </button>
-                </div>
+                    Update profile
+                </button>
             </div>
-        </div>
+        </sp-split-section>
         <mat-divider></mat-divider>
         <div fxLayout="row" fxFlex="100" class="mt-30">
-            <div fxFlex="300px" fxLayout="column" class="profile-section">
-                <div class="settings-title">Appearance</div>
-                <div class="settings-description">Change the appearance of your {{appConstants.APP_NAME}} installation</div>
-            </div>
-            <div fxFill fxLayout="column">
+            <sp-split-section title="Appearance" subtitle="Change the appearance of your {{appConstants.APP_NAME}} installation">
                 <label id="radio-group-label">Color Scheme</label>
                 <mat-radio-group [(ngModel)]="darkMode"
                                  aria-labelledby="radio-group-label"
@@ -65,7 +55,7 @@
                         Save color scheme
                     </button>
                 </div>
-            </div>
+            </sp-split-section>
         </div>
     </div>
 
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.scss b/ui/src/app/profile/components/general/general-profile-settings.component.scss
index 0d460dd..8ad885d 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.scss
+++ b/ui/src/app/profile/components/general/general-profile-settings.component.scss
@@ -16,20 +16,6 @@
  *
  */
 
-.settings-title {
-  font-weight: bold;
-  font-size: 16pt;
-}
-
-.settings-description {
-  font-size: 12pt;
-}
-
-.profile-section {
-  border-right: 2px solid gray;
-  margin-right: 15px;
-}
-
 .title-section {
   width: 300px;
 }
diff --git a/ui/src/app/profile/components/token/token-management-settings.component.html b/ui/src/app/profile/components/token/token-management-settings.component.html
index f21451b..da3ca1b 100644
--- a/ui/src/app/profile/components/token/token-management-settings.component.html
+++ b/ui/src/app/profile/components/token/token-management-settings.component.html
@@ -18,73 +18,63 @@
 
 <div fxLayout="row" class="page-container-padding">
     <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" *ngIf="profileLoaded">
-        <div fxLayout="row" fxFlex="100">
-            <div fxFlex="300px" fxLayout="column" class="profile-section">
-                <div class="settings-title">API Keys</div>
-                <div class="settings-description">Manage your API keys for third-party application access to
-                    {{appConstants.APP_NAME}}.
+        <sp-split-section title="API Keys" subtitle="Manage your API keys for third-party application access to
+                    {{appConstants.APP_NAME}}">
+            <div fxLayout="column" class="subsection">
+                <div class="subsection-title">New API key</div>
+                <mat-form-field fxFlex color="accent">
+                    <mat-label>Name</mat-label>
+                    <input [(ngModel)]="newTokenName" matInput/>
+                </mat-form-field>
+                <div>
+                    <button mat-button mat-raised-button color="accent"
+                            (click)="requestNewKey()">
+                        Create new API key
+                    </button>
                 </div>
             </div>
-            <div fxFill fxLayout="column">
-                <div fxLayout="column" class="subsection">
-                    <div class="subsection-title">New API key</div>
-                    <mat-form-field fxFlex color="accent">
-                        <mat-label>Name</mat-label>
-                        <input [(ngModel)]="newTokenName" matInput/>
-                    </mat-form-field>
-                    <div>
-                        <button mat-button mat-raised-button color="accent"
-                                (click)="requestNewKey()">
-                            Create new API key
-                        </button>
+            <div fxLayout="column" class="subsection mt-10" *ngIf="newTokenCreated">
+                <div class="subsection-title">Key created</div>
+                <div class="subsection-small">Your new API key has been created. Please copy the key now - you won't be able to see the key again.</div>
+                <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="new-token">
+                    <div class="token-name">{{newlyCreatedToken.tokenName}}</div>
+                    <div class="displayed-token">
+                        {{newlyCreatedToken.rawToken}}
                     </div>
+                    <button mat-button mat-raised-button color="accent"
+                            [cdkCopyToClipboard]="newlyCreatedToken.rawToken">
+                        Copy
+                    </button>
                 </div>
-                <div fxLayout="column" class="subsection mt-10" *ngIf="newTokenCreated">
-                    <div class="subsection-title">Key created</div>
-                    <div class="subsection-small">Your new API key has been created. Please copy the key now - you won't be able to see the key again.</div>
-                    <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="new-token">
-                        <div class="token-name">{{newlyCreatedToken.tokenName}}</div>
-                        <div class="displayed-token">
-                            {{newlyCreatedToken.rawToken}}
-                        </div>
-                        <button mat-button mat-raised-button color="accent"
-                                [cdkCopyToClipboard]="newlyCreatedToken.rawToken">
-                            Copy
-                        </button>
-                    </div>
-                </div>
-                <mat-divider class="divider"></mat-divider>
-                <div fxLayout="column" class="subsection mt-10">
-                    <div class="subsection-title">Existing API keys</div>
-                    <div *ngIf="userData.userApiTokens.length == 0">(no keys available)</div>
-                    <table mat-table [dataSource]="apiKeyDataSource" class="mat-elevation-z0" *ngIf="userData.userApiTokens.length > 0">
-                        <ng-container matColumnDef="name">
-                            <th mat-header-cell *matHeaderCellDef> Name</th>
-                            <td mat-cell *matCellDef="let element"> {{element.tokenName}} </td>
-                        </ng-container>
+            </div>
+            <mat-divider class="divider"></mat-divider>
+            <div fxLayout="column" class="subsection mt-10">
+                <div class="subsection-title">Existing API keys</div>
+                <div *ngIf="userData.userApiTokens.length == 0">(no keys available)</div>
+                <table mat-table [dataSource]="apiKeyDataSource" class="mat-elevation-z0" *ngIf="userData.userApiTokens.length > 0">
+                    <ng-container matColumnDef="name">
+                        <th mat-header-cell *matHeaderCellDef> Name</th>
+                        <td mat-cell *matCellDef="let element"> {{element.tokenName}} </td>
+                    </ng-container>
 
-                        <!-- Name Column -->
-                        <ng-container matColumnDef="action">
-                            <th mat-header-cell *matHeaderCellDef> Action</th>
-                            <td mat-cell *matCellDef="let element">
-                                <div fxLayout="end end">
+                    <!-- Name Column -->
+                    <ng-container matColumnDef="action">
+                        <th mat-header-cell *matHeaderCellDef> Action</th>
+                        <td mat-cell *matCellDef="let element">
+                            <div fxLayout="end end">
                                 <button mat-button mat-raised-button color="warn"
                                         (click)="revokeApiKey(element)">
                                     Revoke
                                 </button>
-                                </div>
-                            </td>
-                        </ng-container>
+                            </div>
+                        </td>
+                    </ng-container>
 
-                        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
-                        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
-                    </table>
-                </div>
-            </div>
-            <div fxFill fxLayout="column">
+                    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+                </table>
             </div>
-        </div>
+        </sp-split-section>
         <mat-divider></mat-divider>
     </div>
-
 </div>
diff --git a/ui/src/app/profile/components/token/token-management-settings.component.scss b/ui/src/app/profile/components/token/token-management-settings.component.scss
index 696831b..b713f43 100644
--- a/ui/src/app/profile/components/token/token-management-settings.component.scss
+++ b/ui/src/app/profile/components/token/token-management-settings.component.scss
@@ -16,20 +16,6 @@
  *
  */
 
-.settings-title {
-  font-weight: bold;
-  font-size: 16pt;
-}
-
-.settings-description {
-  font-size: 12pt;
-}
-
-.profile-section {
-  border-right: 2px solid gray;
-  margin-right: 15px;
-}
-
 .title-section {
   width: 300px;
 }
diff --git a/ui/src/app/profile/profile.module.ts b/ui/src/app/profile/profile.module.ts
index 273bf9f..4ebcfd9 100644
--- a/ui/src/app/profile/profile.module.ts
+++ b/ui/src/app/profile/profile.module.ts
@@ -29,6 +29,7 @@ import {GeneralProfileSettingsComponent} from "./components/general/general-prof
 import {ProfileService} from "./profile.service";
 import {MatDividerModule} from "@angular/material/divider";
 import { ClipboardModule } from '@angular/cdk/clipboard';
+import { CoreUiModule } from '../core-ui/core-ui.module';
 
 @NgModule({
   imports: [
@@ -40,6 +41,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard';
     CustomMaterialModule,
     CommonModule,
     ClipboardModule,
+    CoreUiModule,
   ],
   declarations: [
     GeneralProfileSettingsComponent,

[incubator-streampipes] 03/03: [hotfix] Harmonize appearance of settings components

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

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

commit c0c2a6e9862fcce6150340aafb86b1d66c08ff3c
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sun Oct 3 20:33:23 2021 +0200

    [hotfix] Harmonize appearance of settings components
---
 .../app/configuration/configuration.component.html |  18 ++-
 ui/src/app/configuration/configuration.module.ts   |   6 +-
 .../datalake-configuration.component.html          | 122 +++++++++---------
 .../messaging-configuration.component.html         | 142 ++++++++++-----------
 .../pipeline-element-configuration.component.html  |  92 +++++++------
 .../security-configuration.component.html          |  18 +++
 .../split-section/split-section.component.html     |  16 ++-
 .../split-section/split-section.component.scss     |   5 +
 .../token/token-management-settings.component.scss |   5 -
 ui/src/scss/sp/main.scss                           |   6 +
 10 files changed, 229 insertions(+), 201 deletions(-)

diff --git a/ui/src/app/configuration/configuration.component.html b/ui/src/app/configuration/configuration.component.html
index 2456699..5219006 100644
--- a/ui/src/app/configuration/configuration.component.html
+++ b/ui/src/app/configuration/configuration.component.html
@@ -16,26 +16,32 @@
   ~
   -->
 
-<div fxLayout="column" fxFlex="100" class="page-container">
+<div fxLayout="column" class="page-container">
     <div fxLayout="row" class="p-0 sp-bg-lightgray page-container-nav">
         <div fxLayout="fill">
             <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectedIndexChange($event)"
                            color="accent">
-                <mat-tab label="Pipeline Element Configuration"></mat-tab>
+                <mat-tab label="DataLake"></mat-tab>
                 <mat-tab label="Messaging"></mat-tab>
-                <mat-tab
-                        label="DataLake"></mat-tab>
+                <mat-tab label="Pipeline Element Configuration"></mat-tab>
+                <mat-tab label="Security"></mat-tab>
             </mat-tab-group>
         </div>
     </div>
 
+    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100">
     <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="selectedIndex == 0">
-        <pipeline-element-configuration fxFlex="100"></pipeline-element-configuration>
+        <sp-datalake-configuration fxFlex="100"></sp-datalake-configuration>
     </div>
     <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="selectedIndex == 1">
         <messaging-configuration fxFlex="100"></messaging-configuration>
     </div>
     <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="selectedIndex == 2">
-        <sp-datalake-configuration fxFlex="100"></sp-datalake-configuration>
+        <pipeline-element-configuration fxFlex="100"></pipeline-element-configuration>
+    </div>
+    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="selectedIndex == 3">
+        <sp-security-configuration fxFlex="100"></sp-security-configuration>
     </div>
+    </div>
+
 </div>
diff --git a/ui/src/app/configuration/configuration.module.ts b/ui/src/app/configuration/configuration.module.ts
index cfa5f63..3005794 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -44,6 +44,8 @@ import { DatalakeRestService } from '../core-services/datalake/datalake-rest.ser
 import { DeleteDatalakeIndexComponent } from './dialog/delete-datalake-index/delete-datalake-index-dialog.component';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 import { SecurityConfigurationComponent } from './security-configuration/security-configuration.component';
+import { CoreUiModule } from '../core-ui/core-ui.module';
+import { MatDividerModule } from '@angular/material/divider';
 
 @NgModule({
   imports: [
@@ -56,9 +58,11 @@ import { SecurityConfigurationComponent } from './security-configuration/securit
     MatIconModule,
     MatInputModule,
     MatCheckboxModule,
+    MatDividerModule,
     MatTooltipModule,
     FormsModule,
-    DragDropModule
+    DragDropModule,
+    CoreUiModule
   ],
   declarations: [
     ConfigurationComponent,
diff --git a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
index 146619b..bbc29d5 100644
--- a/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
+++ b/ui/src/app/configuration/datalake-configuration/datalake-configuration.component.html
@@ -16,52 +16,48 @@
   ~
   -->
 
-<div fxFlex="100" fxLayout="column" style="margin-top:40px;">
-    <div fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch">
-        <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
-            <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
-                <h4>Datalake Settings</h4>
-                <span flex></span>
-            </div>
-        </div>
-
-        <div fxFlex="100" class="sp-blue-border">
-            <table
-                    fxFlex="100"
-                    mat-table
-                    data-cy="datalake-settings"
-                    [dataSource]="dataSource"
-                    style="width: 100%;"
-                    matSort>
+<div fxLayout="row" class="page-container-padding">
+    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start">
+        <sp-split-section title="Data Lake Settings"
+                          subtitle="Truncate and delete persisted data streams">
+            <div fxFlex="100" fxLayout="column">
+                <div class="subsection-title">Existing data lake indices</div>
+                <table
+                        fxFlex="100"
+                        mat-table
+                        data-cy="datalake-settings"
+                        [dataSource]="dataSource"
+                        style="width: 100%;"
+                        matSort>
 
-                <ng-container matColumnDef="name">
-                    <th mat-header-cell mat-sort-header *matHeaderCellDef>Name</th>
-                    <td mat-cell *matCellDef="let configurationEntry">
-                        <h4 style="margin-bottom:0px;">{{configurationEntry.name}}</h4>
-                    </td>
-                </ng-container>
+                    <ng-container matColumnDef="name">
+                        <th mat-header-cell mat-sort-header *matHeaderCellDef>Name</th>
+                        <td mat-cell *matCellDef="let configurationEntry">
+                            <h4 style="margin-bottom:0px;">{{configurationEntry.name}}</h4>
+                        </td>
+                    </ng-container>
 
-                <ng-container matColumnDef="pipeline">
-                    <th mat-header-cell mat-sort-header *matHeaderCellDef>Related Pipeline</th>
-                    <td mat-cell *matCellDef="let configurationEntry">
-                        {{configurationEntry.pipelines}}
-                    </td>
-                </ng-container>
+                    <ng-container matColumnDef="pipeline">
+                        <th mat-header-cell mat-sort-header *matHeaderCellDef>Related Pipeline</th>
+                        <td mat-cell *matCellDef="let configurationEntry">
+                            {{configurationEntry.pipelines}}
+                        </td>
+                    </ng-container>
 
-                <ng-container matColumnDef="events">
-                    <th mat-header-cell mat-sort-header *matHeaderCellDef># Events</th>
-                    <td
-                            mat-cell
-                            data-cy="datalake-number-of-events"
-                            *matCellDef="let configurationEntry">
-                        {{configurationEntry.events | number}}
-                    </td>
-                </ng-container>
+                    <ng-container matColumnDef="events">
+                        <th mat-header-cell mat-sort-header *matHeaderCellDef># Events</th>
+                        <td
+                                mat-cell
+                                data-cy="datalake-number-of-events"
+                                *matCellDef="let configurationEntry">
+                            {{configurationEntry.events | number}}
+                        </td>
+                    </ng-container>
 
-                <ng-container matColumnDef="truncate">
-                    <th mat-header-cell *matHeaderCellDef>Truncate</th>
-                    <td mat-cell *matCellDef="let configurationEntry">
-                        <div fxLayout="row">
+                    <ng-container matColumnDef="truncate">
+                        <th mat-header-cell *matHeaderCellDef>Truncate</th>
+                        <td mat-cell *matCellDef="let configurationEntry">
+                            <div fxLayout="row">
                             <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center">
                                     <button color="accent"
                                             mat-button
@@ -73,14 +69,14 @@
                                         <i class="material-icons">local_fire_department</i>
                                     </button>
                                 </span>
-                        </div>
-                    </td>
-                </ng-container>
+                            </div>
+                        </td>
+                    </ng-container>
 
-                <ng-container matColumnDef="remove">
-                    <th mat-header-cell *matHeaderCellDef>Remove</th>
-                    <td mat-cell *matCellDef="let configurationEntry">
-                        <div fxLayout="row">
+                    <ng-container matColumnDef="remove">
+                        <th mat-header-cell *matHeaderCellDef>Remove</th>
+                        <td mat-cell *matCellDef="let configurationEntry">
+                            <div fxLayout="row">
                             <span fxFlex fxFlexOrder="3" fxLayout="row" fxLayoutAlign="center center">
                                     <button color="accent"
                                             mat-button
@@ -93,20 +89,22 @@
                                         <i class="material-icons">delete</i>
                                     </button>
                                 </span>
-                        </div>
-                    </td>
-                </ng-container>
+                            </div>
+                        </td>
+                    </ng-container>
 
-                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
-                <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+                    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
 
-            </table>
-        </div>
-        <div fxFlex="100" fxLayoutAlign="end end">
-            <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="20"></mat-paginator>
-        </div>
-        <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="availableMeasurements.length == 0">
-            <h5>(no stored measurements)</h5>
-        </div>
+                </table>
+            </div>
+            <div fxFlex="100" fxLayoutAlign="end end">
+                <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="20"></mat-paginator>
+            </div>
+            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center" *ngIf="availableMeasurements.length == 0">
+                <h5>(no stored measurements)</h5>
+            </div>
+        </sp-split-section>
     </div>
 </div>
+
diff --git a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html
index f8dba27..b64ea3a 100644
--- a/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html
+++ b/ui/src/app/configuration/messaging-configuration/messaging-configuration.component.html
@@ -16,83 +16,81 @@
   ~
   -->
 
-<div fxFlex="100" fxLayout="column" style="margin-top:40px;">
-    <div fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch">
-        <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
-            <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
-                <h4>Kafka Settings</h4>
-                <span flex></span>
-            </div>
-        </div>
-        <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border page-container-padding-inner">
-            <form (ngSubmit)="updateMessagingSettings()" class="form-width" fxFlex="100" fxLayout="column" *ngIf="loadingCompleted">
-                <mat-form-field class="form-field" fxFlex="100">
-                    <input matInput [(ngModel)]="messagingSettings.batchSize"
-                           [placeholder]="'Batch Size'" type="text"
-                           [ngModelOptions]="{standalone: true}">
-                </mat-form-field>
-                <mat-form-field class="form-field" fxFlex="100">
-                    <input matInput [(ngModel)]="messagingSettings.messageMaxBytes"
-                           [placeholder]="'Message Max Bytes'" type="text"
-                           [ngModelOptions]="{standalone: true}">
-                </mat-form-field>
-                <mat-form-field class="form-field" fxFlex="100">
-                    <input matInput [(ngModel)]="messagingSettings.acks"
-                           [placeholder]="'Acks'" type="text"
-                           [ngModelOptions]="{standalone: true}">
-                </mat-form-field>
-                <mat-form-field class="form-field" fxFlex="100">
-                    <input matInput [(ngModel)]="messagingSettings.lingerMs"
-                           [placeholder]="'Linger MS'" type="text"
-                           [ngModelOptions]="{standalone: true}">
-                </mat-form-field>
-                <div fxLayoutAlign="end center">
-                    <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button">Update
-                    </button>
-                </div>
-
-            </form>
-        </div>
+<div fxLayout="row" class="page-container-padding">
+    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start">
+        <sp-split-section title="Kafka Settings"
+                          subtitle="Manage Kafka settings for pipeline communication">
+            <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner">
+                <form (ngSubmit)="updateMessagingSettings()" class="form-width" fxFlex="100" fxLayout="column"
+                      *ngIf="loadingCompleted">
+                    <mat-form-field class="form-field" fxFlex="100">
+                        <input matInput [(ngModel)]="messagingSettings.batchSize"
+                               [placeholder]="'Batch Size'" type="text"
+                               [ngModelOptions]="{standalone: true}">
+                    </mat-form-field>
+                    <mat-form-field class="form-field" fxFlex="100">
+                        <input matInput [(ngModel)]="messagingSettings.messageMaxBytes"
+                               [placeholder]="'Message Max Bytes'" type="text"
+                               [ngModelOptions]="{standalone: true}">
+                    </mat-form-field>
+                    <mat-form-field class="form-field" fxFlex="100">
+                        <input matInput [(ngModel)]="messagingSettings.acks"
+                               [placeholder]="'Acks'" type="text"
+                               [ngModelOptions]="{standalone: true}">
+                    </mat-form-field>
+                    <mat-form-field class="form-field" fxFlex="100">
+                        <input matInput [(ngModel)]="messagingSettings.lingerMs"
+                               [placeholder]="'Linger MS'" type="text"
+                               [ngModelOptions]="{standalone: true}">
+                    </mat-form-field>
+                    <div fxLayoutAlign="start center" class="mt-10">
+                        <button mat-raised-button color="accent" type="submit"
+                                class="md-raised md-primary submit-button">Update
+                        </button>
+                    </div>
 
-    </div>
-    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start stretch" style="margin-top:40px;">
-        <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
-            <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
-                <h4>Message Formats</h4>
-                <span flex></span>
+                </form>
             </div>
-        </div>
-        <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border page-container-padding-inner">
-            <div cdkDropList class="data-format-list" (cdkDropListDropped)="drop($event)" *ngIf="loadingCompleted">
-                <div class="data-format-box" *ngFor="let format of messagingSettings.prioritizedFormats" cdkDrag>
-                    {{format}}
+        </sp-split-section>
+        <mat-divider></mat-divider>
+        <div class="mt-30">
+            <sp-split-section title="Message Formats"
+                              subtitle="Manage the priority of message formats used">
+                <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner">
+                    <div cdkDropList class="data-format-list" (cdkDropListDropped)="drop($event)"
+                         *ngIf="loadingCompleted">
+                        <div class="data-format-box" *ngFor="let format of messagingSettings.prioritizedFormats"
+                             cdkDrag>
+                            {{format}}
+                        </div>
+                    </div>
+                    <div fxLayoutAlign="start center" class="mt-10">
+                        <button mat-raised-button color="accent" type="submit"
+                                class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update
+                        </button>
+                    </div>
                 </div>
-            </div>
-            <div fxLayoutAlign="end center">
-                <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update
-                </button>
-            </div>
-        </div>
-    </div>
-    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start stretch" style="margin-top:40px;">
-        <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
-            <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
-                <h4>Protocols</h4>
-                <span fxFlex></span>
-            </div>
+            </sp-split-section>
         </div>
-        <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border page-container-padding-inner">
-            <div cdkDropList class="data-format-list" (cdkDropListDropped)="dropProtocol($event)"
-                 *ngIf="loadingCompleted">
-                <div class="data-format-box" *ngFor="let protocol of messagingSettings.prioritizedProtocols" cdkDrag>
-                    {{protocol}}
+        <mat-divider></mat-divider>
+        <div class="mt-30">
+            <sp-split-section title="Protocols"
+                              subtitle="Manage the priority of protocols used">
+                <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="page-container-padding-inner">
+                    <div cdkDropList class="data-format-list" (cdkDropListDropped)="dropProtocol($event)"
+                         *ngIf="loadingCompleted">
+                        <div class="data-format-box" *ngFor="let protocol of messagingSettings.prioritizedProtocols"
+                             cdkDrag>
+                            {{protocol}}
+                        </div>
+                    </div>
+                    <div fxLayoutAlign="start center" class="mt-10">
+                        <button mat-raised-button color="accent" type="submit"
+                                class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update
+                        </button>
+                    </div>
                 </div>
-            </div>
-            <div fxLayoutAlign="end center">
-                <button mat-raised-button color="accent" type="submit" class="md-raised md-primary submit-button" (click)="updateMessagingSettings()">Update
-                </button>
-            </div>
+            </sp-split-section>
         </div>
-
     </div>
 </div>
diff --git a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html
index 68df495..339fe0a 100644
--- a/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html
+++ b/ui/src/app/configuration/pipeline-element-configuration/pipeline-element-configuration.component.html
@@ -16,64 +16,60 @@
   ~
   -->
 
-<div fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch" style="margin-top:40px;">
-    <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
-        <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
-            <h4>Pipeline Element Configuration</h4>
-            <span flex></span>
-        </div>
-    </div>
-    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border">
-        <table fxFlex="100" mat-table [dataSource]="dataSource" multiTemplateDataRows>
+<div fxLayout="row" class="page-container-padding">
+    <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start">
+        <sp-split-section title="Pipeline Element Configuration"
+                          subtitle="Configure basic settings of core and extensions services">
+            <table fxFlex="100" mat-table [dataSource]="dataSource" multiTemplateDataRows>
 
-            <ng-container matColumnDef="status">
-                <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Status</th>
-                <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                <ng-container matColumnDef="status">
+                    <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Status</th>
+                    <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
                             <span *ngIf="element.meta.status === 'passing'" fxLayoutAlign="center center">
                                 <mat-icon class="service-icon-passing">lens</mat-icon>
                             </span>
-                    <span *ngIf="element.meta.status === 'critical'" fxLayoutAlign="center center">
+                        <span *ngIf="element.meta.status === 'critical'" fxLayoutAlign="center center">
                                 <mat-icon class="service-icon-critical">lens</mat-icon>
                             </span>
-                </td>
-            </ng-container>
+                    </td>
+                </ng-container>
 
-            <ng-container matColumnDef="name">
-                <th fxFlex="40" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Extensions Service Group
-                </th>
-                <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
-                    {{element.name}}
-                </td>
-            </ng-container>
+                <ng-container matColumnDef="name">
+                    <th fxFlex="40" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Extensions Service Group
+                    </th>
+                    <td fxFlex="40" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        {{element.name}}
+                    </td>
+                </ng-container>
 
-            <ng-container matColumnDef="action">
-                <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Action</th>
-                <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
-                    <button mat-button mat-raised-button color="primary" (click)="expand(element)">
-                        Edit
-                    </button>
-                </td>
-            </ng-container>
+                <ng-container matColumnDef="action">
+                    <th fxFlex="30" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Action</th>
+                    <td fxFlex="30" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        <button mat-button mat-raised-button color="accent" (click)="expand(element)">
+                            Edit
+                        </button>
+                    </td>
+                </ng-container>
 
-            <ng-container matColumnDef="expandedDetail">
-                <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
-                    <div class="consul-configuration-detail"
-                         [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
-                        <div fxFlex="100">
-                            <consul-configs [consulService]="element"
-                                            (updateConsulService)="updateConsulService($event)"></consul-configs>
+                <ng-container matColumnDef="expandedDetail">
+                    <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
+                        <div class="consul-configuration-detail"
+                             [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
+                            <div fxFlex="100">
+                                <consul-configs [consulService]="element"
+                                                (updateConsulService)="updateConsulService($event)"></consul-configs>
+                            </div>
                         </div>
-                    </div>
-                </td>
-            </ng-container>
+                    </td>
+                </ng-container>
 
-            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
-            <tr mat-row *matRowDef="let element; columns: displayedColumns;"
-                class="consul-configuration-row"
-                [class.consul-configuration-row-expanded]="expandedElement === element">
-            </tr>
-            <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="consul-configuration-detail-row"></tr>
-        </table>
-        <!--                <mat-paginator [pageSize]="20" [pageSizeOptions]="[20, 50, 100]" showFirstLastButtons></mat-paginator>-->
+                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                <tr mat-row *matRowDef="let element; columns: displayedColumns;"
+                    class="consul-configuration-row"
+                    [class.consul-configuration-row-expanded]="expandedElement === element">
+                </tr>
+                <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="consul-configuration-detail-row"></tr>
+            </table>
+        </sp-split-section>
     </div>
 </div>
diff --git a/ui/src/app/configuration/security-configuration/security-configuration.component.html b/ui/src/app/configuration/security-configuration/security-configuration.component.html
index e69de29..e40d375 100644
--- a/ui/src/app/configuration/security-configuration/security-configuration.component.html
+++ b/ui/src/app/configuration/security-configuration/security-configuration.component.html
@@ -0,0 +1,18 @@
+<!--
+  ~ 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.
+  ~
+  -->
+
diff --git a/ui/src/app/core-ui/split-section/split-section.component.html b/ui/src/app/core-ui/split-section/split-section.component.html
index 4cabfbe..b275d0c 100644
--- a/ui/src/app/core-ui/split-section/split-section.component.html
+++ b/ui/src/app/core-ui/split-section/split-section.component.html
@@ -16,12 +16,14 @@
   ~
   -->
 
-<div fxLayout="row" fxFlex="100">
-    <div fxFlex="300px" fxLayout="column" class="split-section">
-        <div class="split-section-title">{{title}}</div>
-        <div class="split-section-description">{{subtitle}}</div>
-    </div>
-    <div fxFill fxLayout="column">
-        <ng-content></ng-content>
+<div fxFlex="100" fxLayout="column">
+    <div fxLayout="row">
+        <div fxFlex="300px" fxLayout="column" class="split-section">
+            <div class="split-section-title">{{title}}</div>
+            <div class="split-section-description">{{subtitle}}</div>
+        </div>
+        <div fxFlex fxLayout="column">
+            <ng-content></ng-content>
+        </div>
     </div>
 </div>
diff --git a/ui/src/app/core-ui/split-section/split-section.component.scss b/ui/src/app/core-ui/split-section/split-section.component.scss
index 53d13f0..2d75a6f 100644
--- a/ui/src/app/core-ui/split-section/split-section.component.scss
+++ b/ui/src/app/core-ui/split-section/split-section.component.scss
@@ -16,6 +16,10 @@
  *
  */
 
+:host {
+  width: 100%;
+}
+
 .split-section-title {
   font-weight: bold;
   font-size: 16pt;
@@ -28,4 +32,5 @@
 .split-section {
   border-right: 2px solid gray;
   margin-right: 15px;
+  padding-right: 5px;
 }
diff --git a/ui/src/app/profile/components/token/token-management-settings.component.scss b/ui/src/app/profile/components/token/token-management-settings.component.scss
index b713f43..67df1a9 100644
--- a/ui/src/app/profile/components/token/token-management-settings.component.scss
+++ b/ui/src/app/profile/components/token/token-management-settings.component.scss
@@ -20,11 +20,6 @@
   width: 300px;
 }
 
-.subsection-title {
-  font-size: 12pt;
-  font-weight: bold;
-  margin-bottom: 10px;
-}
 
 .subsection {
   margin-bottom: 15px;
diff --git a/ui/src/scss/sp/main.scss b/ui/src/scss/sp/main.scss
index 91063a9..9ee9197 100644
--- a/ui/src/scss/sp/main.scss
+++ b/ui/src/scss/sp/main.scss
@@ -369,6 +369,12 @@ md-content {
 
 }
 
+.subsection-title {
+  font-size: 12pt;
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
 .page-container-no-border {
   margin: 10px;
   min-height: calc(100% - 20px);

[incubator-streampipes] 01/03: [STREAMPIPES-437] Add initial authorization support

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

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

commit 7c233106458466299945b4e4e81f92b1d942d69c
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sun Oct 3 18:00:31 2021 +0200

    [STREAMPIPES-437] Add initial authorization support
---
 .../client/user/JwtAuthenticationResponse.java     |  17 +--
 .../apache/streampipes/model/client/user/Role.java |  15 ++-
 .../streampipes/model/client/user/UserAccount.java |   4 +-
 .../streampipes/model/client/user/UserInfo.java    |   7 +-
 .../setup/UserRegistrationInstallationStep.java    |   3 +-
 .../streampipes/rest/impl/Authentication.java      |  28 ++---
 .../streampipes/security/jwt/JwtTokenUtils.java    |  20 +++-
 .../user/management/jwt/JwtTokenProvider.java      |  37 ++++++-
 ui/deployment/app-routing.module.mst               |   7 +-
 ui/deployment/base-navigation.component.mst        |  95 +++++++++-------
 ui/deployment/home.service.mst                     |  12 +-
 ui/deployment/modules.yml                          |  11 +-
 ui/deployment/prebuild.js                          |   1 +
 .../src/app/_enums/page-name.enum.ts               |  24 ++--
 .../src/app/_enums/user-role.enum.ts               |  20 ++--
 .../src/app/_guards/page-auth.can-active.guard.ts  |  22 ++--
 ui/src/app/app-routing.module.ts                   |  23 ++--
 .../core/components/base-navigation.component.ts   | 123 +++++++++++++--------
 .../core/components/iconbar/iconbar.component.html |  26 +++--
 .../core/components/iconbar/iconbar.component.ts   |   4 +-
 .../core/components/toolbar/toolbar.component.ts   |  15 +--
 ui/src/app/home/home.component.ts                  |   2 +-
 ui/src/app/services/auth.service.ts                |  75 ++++++++++++-
 23 files changed, 392 insertions(+), 199 deletions(-)

diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java
index f3d1bce..ace0e87 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java
@@ -3,17 +3,13 @@ package org.apache.streampipes.model.client.user;
 public class JwtAuthenticationResponse {
 
 	private String accessToken;
-	private UserInfo userInfo;
 
-	public static JwtAuthenticationResponse from(String accessToken,
-																							 UserInfo userInfo) {
-		return new JwtAuthenticationResponse(accessToken, userInfo);
+	public static JwtAuthenticationResponse from(String accessToken) {
+		return new JwtAuthenticationResponse(accessToken);
 	}
 
-	private JwtAuthenticationResponse(String accessToken,
-																		UserInfo userInfo) {
+	private JwtAuthenticationResponse(String accessToken) {
 		this.accessToken = accessToken;
-		this.userInfo = userInfo;
 	}
 
 	public String getAccessToken() {
@@ -24,11 +20,4 @@ public class JwtAuthenticationResponse {
 		this.accessToken = accessToken;
 	}
 
-	public UserInfo getUserInfo() {
-		return userInfo;
-	}
-
-	public void setUserInfo(UserInfo userInfo) {
-		this.userInfo = userInfo;
-	}
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
index da1f2d2..ca87883 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
@@ -19,11 +19,14 @@
 package org.apache.streampipes.model.client.user;
 
 public enum Role {
-  SYSTEM_ADMINISTRATOR,
-  MANAGER,
-  OPERATOR,
-  DIMENSION_OPERATOR,
-  USER_DEMO,
-  BUSINESS_ANALYST
+  ADMIN,
+  PIPELINE_ADMIN,
+  DASHBOARD_ADMIN,
+  DATA_EXPLORER_ADMIN,
+  CONNECT_ADMIN,
+  DASHBOARD_USER,
+  DATA_EXPLORER_USER,
+  PIPELINE_USER,
+  APP_USER
 
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserAccount.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserAccount.java
index c082dd6..c6bfd34 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserAccount.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserAccount.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 @TsModel
 public class UserAccount extends Principal {
@@ -162,7 +163,6 @@ public class UserAccount extends Principal {
 		this.hideTutorial = hideTutorial;
 	}
 
-
 	public boolean isDarkMode() {
 		return darkMode;
 	}
@@ -173,7 +173,7 @@ public class UserAccount extends Principal {
 
 	@Override
 	public Collection<? extends GrantedAuthority> getAuthorities() {
-		return null;
+		return roles.stream().map(Enum::toString).map(r -> (GrantedAuthority) () -> r).collect(Collectors.toList());
 	}
 
 	@Override
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
index 0f8bc98..d12a1ec 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
@@ -21,6 +21,7 @@ package org.apache.streampipes.model.client.user;
 import org.apache.streampipes.model.shared.annotation.TsModel;
 
 import java.util.List;
+import java.util.Set;
 
 @TsModel
 public class UserInfo {
@@ -28,7 +29,7 @@ public class UserInfo {
   private String userId;
   private String displayName;
   private String email;
-  private List<String> roles;
+  private Set<String> roles;
   private boolean showTutorial;
   private boolean darkMode;
 
@@ -59,11 +60,11 @@ public class UserInfo {
     this.email = email;
   }
 
-  public List<String> getRoles() {
+  public Set<String> getRoles() {
     return roles;
   }
 
-  public void setRoles(List<String> roles) {
+  public void setRoles(Set<String> roles) {
     this.roles = roles;
   }
 
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/UserRegistrationInstallationStep.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/UserRegistrationInstallationStep.java
index 90e70f5..92737b1 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/UserRegistrationInstallationStep.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/UserRegistrationInstallationStep.java
@@ -47,8 +47,7 @@ public class UserRegistrationInstallationStep extends InstallationStep {
 		this.initialServiceAccountName = initialServiceAccountName;
 		this.initialServiceAccountSecret = initialServiceAccountSecret;
 		roles = new HashSet<>();
-		roles.add(Role.SYSTEM_ADMINISTRATOR);
-		roles.add(Role.USER_DEMO);
+		roles.add(Role.ADMIN);
 	}
 
 	@Override
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
index fdd0824..0ac40fb 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
@@ -55,8 +55,7 @@ public class Authentication extends AbstractRestResource {
     try {
       org.springframework.security.core.Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(token.getUsername(), token.getPassword()));
       SecurityContextHolder.getContext().setAuthentication(authentication);
-      JwtAuthenticationResponse tokenResp = makeJwtResponse(authentication);
-      return ok(tokenResp);
+      return processAuth(authentication);
     } catch (BadCredentialsException e) {
       return unauthorized();
     }
@@ -70,8 +69,7 @@ public class Authentication extends AbstractRestResource {
   public Response doLogin() {
     try {
       org.springframework.security.core.Authentication auth = SecurityContextHolder.getContext().getAuthentication();
-      JwtAuthenticationResponse tokenResp = makeJwtResponse(auth);
-      return ok(tokenResp);
+      return processAuth(auth);
     } catch (BadCredentialsException e) {
       return ok(new ErrorMessage(NotificationType.LOGIN_FAILED.uiNotification()));
     }
@@ -94,18 +92,20 @@ public class Authentication extends AbstractRestResource {
     }
   }
 
+  private Response processAuth(org.springframework.security.core.Authentication auth) {
+    Principal principal = (Principal) auth.getPrincipal();
+    if (principal instanceof UserAccount) {
+      JwtAuthenticationResponse tokenResp = makeJwtResponse(auth);
+      return ok(tokenResp);
+    } else {
+      throw new BadCredentialsException("Could not create auth token");
+    }
+  }
+
   private JwtAuthenticationResponse makeJwtResponse(org.springframework.security.core.Authentication auth) {
     String jwt = new JwtTokenProvider().createToken(auth);
-    UserAccount localUser = (UserAccount) auth.getPrincipal();
-    return JwtAuthenticationResponse.from(jwt, toUserInfo(localUser));
+    return JwtAuthenticationResponse.from(jwt);
   }
 
-  private UserInfo toUserInfo(UserAccount localUser) {
-    UserInfo userInfo = new UserInfo();
-    userInfo.setUserId("id");
-    userInfo.setEmail(localUser.getEmail());
-    userInfo.setDisplayName(localUser.getUsername());
-    userInfo.setShowTutorial(!localUser.isHideTutorial());
-    return userInfo;
-  }
+
 }
diff --git a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
index 5efe10a..beafb4b 100644
--- a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
+++ b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
 import javax.crypto.SecretKey;
 import java.nio.charset.StandardCharsets;
 import java.util.Date;
+import java.util.Map;
 
 public class JwtTokenUtils {
 
@@ -35,6 +36,23 @@ public class JwtTokenUtils {
                                     String tokenSecret,
                                     Date expirationDate) {
 
+    return prepareJwtToken(subject, tokenSecret, expirationDate).compact();
+
+  }
+
+  public static String makeJwtToken(String subject,
+                                    String tokenSecret,
+                                    Map<String, Object> claims,
+                                    Date expirationDate) {
+
+    JwtBuilder builder = prepareJwtToken(subject, tokenSecret, expirationDate);
+
+    return builder.addClaims(claims).compact();
+  }
+
+  private static JwtBuilder prepareJwtToken(String subject,
+                                            String tokenSecret,
+                                            Date expirationDate) {
     SecretKey key = Keys.hmacShaKeyFor(tokenSecret.getBytes(StandardCharsets.UTF_8));
 
     return Jwts
@@ -42,7 +60,7 @@ public class JwtTokenUtils {
             .setSubject(subject)
             .setIssuedAt(new Date())
             .setExpiration(expirationDate)
-            .signWith(key).compact();
+            .signWith(key);
   }
 
   public static String getUserIdFromToken(String tokenSecret,
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java
index e22f51b..3dc0857 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java
@@ -3,13 +3,22 @@ package org.apache.streampipes.user.management.jwt;
 import org.apache.streampipes.config.backend.BackendConfig;
 import org.apache.streampipes.config.backend.model.LocalAuthConfig;
 import org.apache.streampipes.model.client.user.Principal;
+import org.apache.streampipes.model.client.user.UserAccount;
+import org.apache.streampipes.model.client.user.UserInfo;
 import org.apache.streampipes.security.jwt.JwtTokenUtils;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
 
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 public class JwtTokenProvider {
 
+	public static final String CLAIM_USER = "user";
+
 	private BackendConfig config;
 
 	public JwtTokenProvider() {
@@ -18,9 +27,24 @@ public class JwtTokenProvider {
 
 	public String createToken(Authentication authentication) {
 		Principal userPrincipal = (Principal) authentication.getPrincipal();
+		Set<String> roles = authentication
+						.getAuthorities()
+						.stream()
+						.map(GrantedAuthority::getAuthority)
+						.collect(Collectors.toSet());
+
 		Date tokenExpirationDate = makeExpirationDate();
+		Map<String, Object> claims = makeClaims(userPrincipal, roles);
 
-		return JwtTokenUtils.makeJwtToken(userPrincipal.getPrincipalName(), tokenSecret(), tokenExpirationDate);
+		return JwtTokenUtils.makeJwtToken(userPrincipal.getPrincipalName(), tokenSecret(), claims, tokenExpirationDate);
+	}
+
+	private Map<String, Object> makeClaims(Principal principal,
+																				 Set<String> roles) {
+		Map<String, Object> claims = new HashMap<>();
+		claims.put(CLAIM_USER, toUserInfo((UserAccount) principal, roles));
+
+		return claims;
 	}
 
 	public String getUserIdFromToken(String token) {
@@ -48,4 +72,15 @@ public class JwtTokenProvider {
 		Date now = new Date();
 		return new Date(now.getTime() + authConfig().getTokenExpirationTimeMillis());
 	}
+
+	private UserInfo toUserInfo(UserAccount localUser,
+															Set<String> roles) {
+		UserInfo userInfo = new UserInfo();
+		userInfo.setUserId("id");
+		userInfo.setEmail(localUser.getEmail());
+		userInfo.setDisplayName(localUser.getUsername());
+		userInfo.setShowTutorial(!localUser.isHideTutorial());
+		userInfo.setRoles(roles);
+		return userInfo;
+	}
 }
diff --git a/ui/deployment/app-routing.module.mst b/ui/deployment/app-routing.module.mst
index 4ddc5e2..b313701 100644
--- a/ui/deployment/app-routing.module.mst
+++ b/ui/deployment/app-routing.module.mst
@@ -32,6 +32,8 @@ import {InfoComponent} from "./info/info.component";
 import {NotificationsComponent} from "./notifications/notifications.component";
 import {ProfileComponent} from "./profile/profile.component";
 import {ApidocsComponent} from "./apidocs/apidocs.component";
+import { PageName } from './_enums/page-name.enum';
+import { PageAuthGuard } from './_guards/page-auth.can-active.guard';
 
 {{#modulesActive}}
 {{#ng5}}
@@ -50,14 +52,14 @@ const routes: Routes = [
       { path: '', component: HomeComponent, canActivate: [ConfiguredCanActivateGuard] },
       {{#modulesActive}}
       {{#ng5}}
-      { path: '{{{link}}}', component: {{{ng5_component}}} },
+      { path: '{{{link}}}', component: {{{ng5_component}}}, data: { authPageNames: [{{{pageNames}}}]}},
       {{/ng5}}
       {{/modulesActive}}
       { path: 'notifications', component: NotificationsComponent },
       { path: 'info', component: InfoComponent },
       { path: 'pipeline-details', component: PipelineDetailsComponent },
       { path: 'profile', component: ProfileComponent},
-    ], canActivateChild: [AuthCanActivateChildrenGuard] }
+    ], canActivateChild: [AuthCanActivateChildrenGuard, PageAuthGuard] }
 ];
 
 @NgModule({
@@ -67,6 +69,7 @@ const routes: Routes = [
       AuthCanActivateChildrenGuard,
       AlreadyConfiguredCanActivateGuard,
       ConfiguredCanActivateGuard,
+      PageAuthGuard
   ]
 })
 export class AppRoutingModule { }
diff --git a/ui/deployment/base-navigation.component.mst b/ui/deployment/base-navigation.component.mst
index 457c9cf..0ba3d1e 100644
--- a/ui/deployment/base-navigation.component.mst
+++ b/ui/deployment/base-navigation.component.mst
@@ -18,6 +18,8 @@
 
 
 import {NavigationEnd, Router} from "@angular/router";
+import { PageName } from '../../_enums/page-name.enum';
+import { AuthService } from '../../services/auth.service';
 
 export abstract class BaseNavigationComponent {
 
@@ -30,14 +32,18 @@ export abstract class BaseNavigationComponent {
     {
       link: '',
       title: 'Home',
-      icon: 'home'
+      icon: 'home',
+      pagesNames: [PageName.HOME],
+      visible: false
     },
     {{#modulesActive}}
     {{^admin}}
     {
         link: '{{{link}}}',
         title: '{{{title}}}',
-        icon: '{{{icon}}}'
+        icon: '{{{icon}}}',
+        pageNames: [{{{pageNames}}}],
+        visible: false
     },
     {{/admin}}
     {{/modulesActive}}
@@ -49,54 +55,65 @@ export abstract class BaseNavigationComponent {
     {
         link: '{{{link}}}',
         title: '{{{title}}}',
-        icon: '{{{icon}}}'
+        icon: '{{{icon}}}',
+        pageNames: [{{{pageNames}}}],
+        visible: false
     },
     {{/admin}}
     {{/modulesActive}}
   ];
 
-  constructor(protected Router: Router) {
+  constructor(protected authService: AuthService,
+                protected router: Router) {
 
-  }
+    }
 
-  onInit() {
-    this.activePage = this.Router.url.replace("/", "");
-    this.activePageName = this.getPageTitle(this.activePage);
-    this.Router.events.subscribe(event => {
-      if (event instanceof NavigationEnd) {
-        this.activePage = event.url.replace("/", "");
-        this.activePageName = this.getPageTitle(this.activePage);
-      }
-    });
-  }
+    onInit() {
+      this.authService.user$.subscribe(user => {
+        this.menu.forEach(m => m.visible = this.isNavItemVisible(m.pageNames));
+        this.admin.forEach(m => m.visible = this.isNavItemVisible(m.pageNames));
+      });
+      this.activePage = this.router.url.replace('/', '');
+      this.activePageName = this.getPageTitle(this.activePage);
+      this.router.events.subscribe(event => {
+        if (event instanceof NavigationEnd) {
+          this.activePage = event.url.replace('/', '');
+          this.activePageName = this.getPageTitle(this.activePage);
+        }
+      });
+    }
 
-  getActivePage() {
-    return this.activePage;
-  }
+    getActivePage() {
+      return this.activePage;
+    }
+
+    getPageTitle(path) {
+      const allMenuItems = this.menu.concat(this.admin);
+      let currentTitle = 'StreamPipes';
+      allMenuItems.forEach(m => {
+        if (m.link === path) {
+          currentTitle = m.title;
+        }
+      });
+      if (path === 'pipeline-details') {
+        currentTitle = 'Pipeline Details';
+      }
+      return currentTitle;
+    }
 
-  getPageTitle(path) {
-    var allMenuItems = this.menu.concat(this.admin);
-    var currentTitle = 'StreamPipes';
-    allMenuItems.forEach(m => {
-      if (m.link === path) {
-        currentTitle = m.title;
+    go(path, payload?) {
+      if (payload === undefined) {
+        this.router.navigateByUrl(path);
+        this.activePage = path;
+      } else {
+        this.router.navigateByUrl(path, payload);
+        this.activePage = path;
       }
-    });
-    if (path == 'pipeline-details') {
-      currentTitle = 'Pipeline Details';
+      this.activePageName = this.getPageTitle(this.activePage);
     }
-    return currentTitle;
-  }
 
-  go(path, payload?) {
-    if (payload === undefined) {
-      this.Router.navigateByUrl(path);
-      this.activePage = path;
-    } else {
-      this.Router.navigateByUrl(path, payload);
-      this.activePage = path;
+    public isNavItemVisible(pageNames?: PageName[]): boolean {
+      return this.authService.isAnyAccessGranted(pageNames);
     }
-    this.activePageName = this.getPageTitle(this.activePage);
-  };
 
-}
\ No newline at end of file
+}
diff --git a/ui/deployment/home.service.mst b/ui/deployment/home.service.mst
index eab84e7..8d69d72 100644
--- a/ui/deployment/home.service.mst
+++ b/ui/deployment/home.service.mst
@@ -17,11 +17,17 @@
  */
 
 import { Injectable } from '@angular/core';
+import { PageName } from '../_enums/page-name.enum';
+import { AuthService } from '../services/auth.service';
 
 @Injectable()
 export class HomeService {
 
-    constructor() {
+    constructor(private authService: AuthService) {
+    }
+
+    getFilteredServiceLinks() {
+        return this.getServiceLinks().filter(s => this.authService.isAnyAccessGranted(s.pageNames));
     }
 
     getServiceLinks() {
@@ -32,6 +38,7 @@ export class HomeService {
                description: "{{description}}",
                imageUrl: "{{{homeImage}}}",
                icon: "{{{icon}}}",
+               pageNames: [{{{pageNames}}}],
                link: {
                    newWindow: false,
                    value: "{{{link}}}"
@@ -43,6 +50,7 @@ export class HomeService {
                description: "The notification module lets you view all notifications generated by pipelines.",
                imageUrl: "assets/img/home/notifications.png",
                icon: "chat",
+               pageNames: [PageName.NOTIFICATIONS],
                link: {
                    newWindow: false,
                    value: "notifications"
@@ -50,4 +58,4 @@ export class HomeService {
            }
        ];
     }
-}
\ No newline at end of file
+}
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index 74f1189..63e1b52 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -28,6 +28,7 @@ spEditor:
   icon: 'dashboard'
   homeImage: '/assets/img/home/editor.png'
   admin: false
+  pageNames: 'PageName.PIPELINE_EDITOR'
 spConnect:
   ng5: True
   ng1_templateUrl: ''
@@ -42,6 +43,7 @@ spConnect:
   icon: 'power'
   homeImage: '/assets/img/home/editor.png'
   admin: False
+  pageNames: 'PageName.CONNECT'
 spPipelines:
   ng5: True
   ng1_templateUrl: ''
@@ -56,6 +58,7 @@ spPipelines:
   icon: 'play_arrow'
   homeImage: '/assets/img/home/pipelines.png'
   admin: False
+  pageNames: 'PageName.PIPELINE_OVERVIEW'
 spSensors:
   ng5: False
   ng1_templateUrl: '../sensors/sensors.html'
@@ -83,6 +86,7 @@ spAdd:
   icon: 'cloud_download'
   homeImage: '/assets/img/home/add.png'
   admin: True
+  pageNames: 'PageName.INSTALL_PIPELINE_ELEMENTS'
 spConfiguration:
   ng5: True
   ng1_templateUrl: ''
@@ -97,6 +101,7 @@ spConfiguration:
   description: 'In the configuration module, basic StreamPipes settings and services can be configured.'
   icon: 'settings'
   homeImage: '/assets/img/home/configuration.png'
+  pageNames: 'PageName.SETTINGS'
   admin: True
 spAppOverview:
   ng5: True
@@ -113,6 +118,7 @@ spAppOverview:
   icon: 'apps'
   homeImage: '/assets/img/home/configuration.png'
   admin: false
+  pageNames: 'PageName.APPS'
 spDashboard:
   ng5: True
   ng1_templateUrl: ''
@@ -128,6 +134,7 @@ spDashboard:
   icon: 'insert_chart'
   homeImage: '/assets/img/home/configuration.png'
   admin: false
+  pageNames: 'PageName.DASHBOARD'
 spDataExplorer:
   ng5: True
   ng1_templateUrl: ''
@@ -143,6 +150,7 @@ spDataExplorer:
   icon: 'search'
   homeImage: '/assets/img/home/configuration.png'
   admin: false
+  pageNames: 'PageName.DATA_EXPLORER'
 spFiles:
   ng5: True
   ng1_templateUrl: ''
@@ -157,4 +165,5 @@ spFiles:
   description: 'The file management module lets you upload and manage files that are used by adapters or pipeline elements.'
   icon: 'folder'
   homeImage: '/assets/img/home/configuration.png'
-  admin: true
\ No newline at end of file
+  admin: true
+  pageNames: 'PageName.FILE_UPLOAD'
diff --git a/ui/deployment/prebuild.js b/ui/deployment/prebuild.js
index fcde036..87b0f46 100644
--- a/ui/deployment/prebuild.js
+++ b/ui/deployment/prebuild.js
@@ -69,6 +69,7 @@ for (let module of config.modules) {
         ng5_componentPath: modules[module]['ng5_componentPath'],
         path: modules[module]['path'],
         link: modules[module]['link'],
+        pageNames: modules[module]['pageNames'],
         url: modules[module]['url'],
         title: modules[module]['title'],
         icon: modules[module]['icon'],
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/ui/src/app/_enums/page-name.enum.ts
similarity index 78%
copy from streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
copy to ui/src/app/_enums/page-name.enum.ts
index da1f2d2..472780a 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
+++ b/ui/src/app/_enums/page-name.enum.ts
@@ -16,14 +16,18 @@
  *
  */
 
-package org.apache.streampipes.model.client.user;
-
-public enum Role {
-  SYSTEM_ADMINISTRATOR,
-  MANAGER,
-  OPERATOR,
-  DIMENSION_OPERATOR,
-  USER_DEMO,
-  BUSINESS_ANALYST
-
+export enum PageName {
+  HOME,
+  PIPELINE_EDITOR,
+  CONNECT,
+  PIPELINE_OVERVIEW,
+  PIPELINE_DETAILS,
+  DASHBOARD,
+  DATA_EXPLORER,
+  APPS,
+  NOTIFICATIONS,
+  INSTALL_PIPELINE_ELEMENTS,
+  FILE_UPLOAD,
+  PROFILE,
+  SETTINGS,
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/ui/src/app/_enums/user-role.enum.ts
similarity index 82%
copy from streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
copy to ui/src/app/_enums/user-role.enum.ts
index da1f2d2..681f625 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
+++ b/ui/src/app/_enums/user-role.enum.ts
@@ -16,14 +16,14 @@
  *
  */
 
-package org.apache.streampipes.model.client.user;
-
-public enum Role {
-  SYSTEM_ADMINISTRATOR,
-  MANAGER,
-  OPERATOR,
-  DIMENSION_OPERATOR,
-  USER_DEMO,
-  BUSINESS_ANALYST
-
+export enum UserRole {
+  ADMIN,
+  PIPELINE_ADMIN,
+  DASHBOARD_ADMIN,
+  DATA_EXPLORER_ADMIN,
+  CONNECT_ADMIN,
+  DASHBOARD_USER,
+  DATA_EXPLORER_USER,
+  PIPELINE_USER,
+  APP_USER
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/ui/src/app/_guards/page-auth.can-active.guard.ts
similarity index 56%
copy from streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
copy to ui/src/app/_guards/page-auth.can-active.guard.ts
index da1f2d2..0fe5f05 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
+++ b/ui/src/app/_guards/page-auth.can-active.guard.ts
@@ -16,14 +16,20 @@
  *
  */
 
-package org.apache.streampipes.model.client.user;
+import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router } from '@angular/router';
+import { AuthService } from '../services/auth.service';
+import { PageName } from '../_enums/page-name.enum';
+import { Injectable } from '@angular/core';
 
-public enum Role {
-  SYSTEM_ADMINISTRATOR,
-  MANAGER,
-  OPERATOR,
-  DIMENSION_OPERATOR,
-  USER_DEMO,
-  BUSINESS_ANALYST
+@Injectable()
+export class PageAuthGuard implements CanActivateChild {
 
+  constructor(private router: Router,
+              private authService: AuthService) {}
+
+  canActivateChild(activatedRouteSnapshot: ActivatedRouteSnapshot): boolean {
+    const pageNames: PageName[] = activatedRouteSnapshot.data.authPageNames;
+
+    return this.authService.isAnyAccessGranted(pageNames);
+  }
 }
diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts
index 251238f..b9d63bb 100644
--- a/ui/src/app/app-routing.module.ts
+++ b/ui/src/app/app-routing.module.ts
@@ -32,6 +32,8 @@ import {InfoComponent} from "./info/info.component";
 import {NotificationsComponent} from "./notifications/notifications.component";
 import {ProfileComponent} from "./profile/profile.component";
 import {ApidocsComponent} from "./apidocs/apidocs.component";
+import { PageName } from './_enums/page-name.enum';
+import { PageAuthGuard } from './_guards/page-auth.can-active.guard';
 
 import { EditorComponent } from './editor/editor.component';
 import { PipelinesComponent } from './pipelines/pipelines.component';
@@ -52,20 +54,20 @@ const routes: Routes = [
   { path: 'standalone/:dashboardId', component: StandaloneDashboardComponent },
   { path: '', component: StreampipesComponent, children: [
       { path: '', component: HomeComponent, canActivate: [ConfiguredCanActivateGuard] },
-      { path: 'editor', component: EditorComponent },
-      { path: 'pipelines', component: PipelinesComponent },
-      { path: 'connect', component: ConnectComponent },
-      { path: 'dashboard', component: DashboardComponent },
-      { path: 'dataexplorer', component: DataExplorerComponent },
-      { path: 'app-overview', component: AppOverviewComponent },
-      { path: 'add', component: AddComponent },
-      { path: 'files', component: FilesComponent },
-      { path: 'configuration', component: ConfigurationComponent },
+      { path: 'editor', component: EditorComponent, data: { authPageNames: [PageName.PIPELINE_EDITOR]}},
+      { path: 'pipelines', component: PipelinesComponent, data: { authPageNames: [PageName.PIPELINE_OVERVIEW]}},
+      { path: 'connect', component: ConnectComponent, data: { authPageNames: [PageName.CONNECT]}},
+      { path: 'dashboard', component: DashboardComponent, data: { authPageNames: [PageName.DASHBOARD]}},
+      { path: 'dataexplorer', component: DataExplorerComponent, data: { authPageNames: [PageName.DATA_EXPLORER]}},
+      { path: 'app-overview', component: AppOverviewComponent, data: { authPageNames: [PageName.APPS]}},
+      { path: 'add', component: AddComponent, data: { authPageNames: [PageName.INSTALL_PIPELINE_ELEMENTS]}},
+      { path: 'files', component: FilesComponent, data: { authPageNames: [PageName.FILE_UPLOAD]}},
+      { path: 'configuration', component: ConfigurationComponent, data: { authPageNames: [PageName.SETTINGS]}},
       { path: 'notifications', component: NotificationsComponent },
       { path: 'info', component: InfoComponent },
       { path: 'pipeline-details', component: PipelineDetailsComponent },
       { path: 'profile', component: ProfileComponent},
-    ], canActivateChild: [AuthCanActivateChildrenGuard] }
+    ], canActivateChild: [AuthCanActivateChildrenGuard, PageAuthGuard] }
 ];
 
 @NgModule({
@@ -75,6 +77,7 @@ const routes: Routes = [
       AuthCanActivateChildrenGuard,
       AlreadyConfiguredCanActivateGuard,
       ConfiguredCanActivateGuard,
+      PageAuthGuard
   ]
 })
 export class AppRoutingModule { }
diff --git a/ui/src/app/core/components/base-navigation.component.ts b/ui/src/app/core/components/base-navigation.component.ts
index e1a9ab0..c1301f1 100644
--- a/ui/src/app/core/components/base-navigation.component.ts
+++ b/ui/src/app/core/components/base-navigation.component.ts
@@ -18,6 +18,8 @@
 
 
 import {NavigationEnd, Router} from "@angular/router";
+import { PageName } from '../../_enums/page-name.enum';
+import { AuthService } from '../../services/auth.service';
 
 export abstract class BaseNavigationComponent {
 
@@ -30,37 +32,51 @@ export abstract class BaseNavigationComponent {
     {
       link: '',
       title: 'Home',
-      icon: 'home'
+      icon: 'home',
+      pagesNames: [PageName.HOME],
+      visible: false
     },
     {
         link: 'editor',
         title: 'Pipeline Editor',
-        icon: 'dashboard'
+        icon: 'dashboard',
+        pageNames: [PageName.PIPELINE_EDITOR],
+        visible: false
     },
     {
         link: 'pipelines',
         title: 'Pipelines',
-        icon: 'play_arrow'
+        icon: 'play_arrow',
+        pageNames: [PageName.PIPELINE_OVERVIEW],
+        visible: false
     },
     {
         link: 'connect',
         title: 'Connect',
-        icon: 'power'
+        icon: 'power',
+        pageNames: [PageName.CONNECT],
+        visible: false
     },
     {
         link: 'dashboard',
         title: 'Dashboard',
-        icon: 'insert_chart'
+        icon: 'insert_chart',
+        pageNames: [PageName.DASHBOARD],
+        visible: false
     },
     {
         link: 'dataexplorer',
         title: 'Data Explorer',
-        icon: 'search'
+        icon: 'search',
+        pageNames: [PageName.DATA_EXPLORER],
+        visible: false
     },
     {
         link: 'app-overview',
         title: 'Apps',
-        icon: 'apps'
+        icon: 'apps',
+        pageNames: [PageName.APPS],
+        visible: false
     },
   ];
 
@@ -68,62 +84,77 @@ export abstract class BaseNavigationComponent {
     {
         link: 'add',
         title: 'Install Pipeline Elements',
-        icon: 'cloud_download'
+        icon: 'cloud_download',
+        pageNames: [PageName.INSTALL_PIPELINE_ELEMENTS],
+        visible: false
     },
     {
         link: 'files',
         title: 'File Management',
-        icon: 'folder'
+        icon: 'folder',
+        pageNames: [PageName.FILE_UPLOAD],
+        visible: false
     },
     {
         link: 'configuration',
         title: 'Configuration',
-        icon: 'settings'
+        icon: 'settings',
+        pageNames: [PageName.SETTINGS],
+        visible: false
     },
   ];
 
-  constructor(protected Router: Router) {
+  constructor(protected authService: AuthService,
+                protected router: Router) {
 
-  }
+    }
 
-  onInit() {
-    this.activePage = this.Router.url.replace("/", "");
-    this.activePageName = this.getPageTitle(this.activePage);
-    this.Router.events.subscribe(event => {
-      if (event instanceof NavigationEnd) {
-        this.activePage = event.url.replace("/", "");
-        this.activePageName = this.getPageTitle(this.activePage);
-      }
-    });
-  }
+    onInit() {
+      this.authService.user$.subscribe(user => {
+        this.menu.forEach(m => m.visible = this.isNavItemVisible(m.pageNames));
+        this.admin.forEach(m => m.visible = this.isNavItemVisible(m.pageNames));
+      });
+      this.activePage = this.router.url.replace('/', '');
+      this.activePageName = this.getPageTitle(this.activePage);
+      this.router.events.subscribe(event => {
+        if (event instanceof NavigationEnd) {
+          this.activePage = event.url.replace('/', '');
+          this.activePageName = this.getPageTitle(this.activePage);
+        }
+      });
+    }
 
-  getActivePage() {
-    return this.activePage;
-  }
+    getActivePage() {
+      return this.activePage;
+    }
+
+    getPageTitle(path) {
+      const allMenuItems = this.menu.concat(this.admin);
+      let currentTitle = 'StreamPipes';
+      allMenuItems.forEach(m => {
+        if (m.link === path) {
+          currentTitle = m.title;
+        }
+      });
+      if (path === 'pipeline-details') {
+        currentTitle = 'Pipeline Details';
+      }
+      return currentTitle;
+    }
 
-  getPageTitle(path) {
-    var allMenuItems = this.menu.concat(this.admin);
-    var currentTitle = 'StreamPipes';
-    allMenuItems.forEach(m => {
-      if (m.link === path) {
-        currentTitle = m.title;
+    go(path, payload?) {
+      if (payload === undefined) {
+        this.router.navigateByUrl(path);
+        this.activePage = path;
+      } else {
+        this.router.navigateByUrl(path, payload);
+        this.activePage = path;
       }
-    });
-    if (path == 'pipeline-details') {
-      currentTitle = 'Pipeline Details';
+      this.activePageName = this.getPageTitle(this.activePage);
     }
-    return currentTitle;
-  }
 
-  go(path, payload?) {
-    if (payload === undefined) {
-      this.Router.navigateByUrl(path);
-      this.activePage = path;
-    } else {
-      this.Router.navigateByUrl(path, payload);
-      this.activePage = path;
+    public isNavItemVisible(pageNames?: PageName[]): boolean {
+      return this.authService.isAnyAccessGranted(pageNames);
     }
-    this.activePageName = this.getPageTitle(this.activePage);
-  };
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.html b/ui/src/app/core/components/iconbar/iconbar.component.html
index b5a74ee..38ffe54 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.html
+++ b/ui/src/app/core/components/iconbar/iconbar.component.html
@@ -17,14 +17,15 @@
   -->
 
 <div style="padding-top:0px;" fxFlex="100" fxLayout="column">
-    <div [ngClass]="item.link === activePage ? 'sp-navbar-item-selected': 'sp-navbar-item'"
-         *ngFor="let item of menu" style="min-width:0px;padding:0px;padding-top:5px;padding-bottom:5px;">
+    <div *ngFor="let item of menu">
+        <div *ngIf="item.visible" style="min-width:0px;padding:0px;padding-top:5px;padding-bottom:5px;" [ngClass]="item.link === activePage ? 'sp-navbar-item-selected': 'sp-navbar-item'">
         <button mat-button mat-icon-button class="button-margin-iconbar iconbar-size" (click)="go(item.link)"
-                matTooltip="{{item.title}}" matTooltipPosition="right">
+                matTooltip="{{item.title}}" matTooltipPosition="right" >
             <mat-icon [ngClass]="item.link === activePage ? 'sp-navbar-icon-selected' : 'sp-navbar-icon'">
                 {{item.icon}}
             </mat-icon>
         </button>
+        </div>
     </div>
     <div [ngClass]="'notifications' === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'"
          style="padding-top:5px;padding-bottom:5px;">
@@ -38,13 +39,16 @@
         </button>
     </div>
     <mat-divider style="border-top-color:var(--color-navigation-text);"></mat-divider>
-    <div [ngClass]="item.link === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'"
-         *ngFor="let item of admin" style="padding-top:5px;padding-bottom:5px;">
-        <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size"
-                (click)="go(item.link)"
-                matTooltip="{{item.title}}">
-            <mat-icon
-                    [ngClass]="item.link === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'">{{item.icon}}</mat-icon>
-        </button>
+    <div *ngFor="let item of admin" >
+        <div  [ngClass]="item.link === activePage ? 'sp-navbar-item-selected' : 'sp-navbar-item'"
+              style="padding-top:5px;padding-bottom:5px;"
+              *ngIf="item.visible">
+            <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size"
+                    (click)="go(item.link)"
+                    matTooltip="{{item.title}}" >
+                <mat-icon
+                        [ngClass]="item.link === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'">{{item.icon}}</mat-icon>
+            </button>
+        </div>
     </div>
 </div>
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.ts b/ui/src/app/core/components/iconbar/iconbar.component.ts
index 8e20f84..5c818b1 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.ts
+++ b/ui/src/app/core/components/iconbar/iconbar.component.ts
@@ -34,9 +34,9 @@ export class IconbarComponent extends BaseNavigationComponent implements OnInit
   unreadNotifications = 0;
 
   constructor(router: Router,
-              private authService: AuthService,
+              authService: AuthService,
               public notificationCountService: NotificationCountService) {
-    super(router);
+    super(authService, router);
   }
 
   ngOnInit(): void {
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.ts b/ui/src/app/core/components/toolbar/toolbar.component.ts
index a8604cb..3cd5c33 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.ts
+++ b/ui/src/app/core/components/toolbar/toolbar.component.ts
@@ -47,8 +47,8 @@ export class ToolbarComponent extends BaseNavigationComponent implements OnInit
               private profileService: ProfileService,
               private restApi: RestApi,
               private overlay: OverlayContainer,
-              private authService: AuthService) {
-    super(router);
+              authService: AuthService) {
+    super(authService, router);
   }
 
   ngOnInit(): void {
@@ -89,23 +89,18 @@ export class ToolbarComponent extends BaseNavigationComponent implements OnInit
   }
 
   openInfo() {
-    this.Router.navigate(['info']);
+    this.router.navigate(['info']);
     this.activePage = 'Info';
   }
 
   openProfile() {
-    this.Router.navigate(['profile']);
+    this.router.navigate(['profile']);
     this.activePage = 'Profile';
   }
 
   logout() {
     this.authService.logout();
-    this.Router.navigate(['login']);
-    // this.RestApi.logout().subscribe(() => {
-    //   this.AuthStatusService.user = undefined;
-    //   this.AuthStatusService.authenticated = false;
-    //   this.Router.navigateByUrl('login');
-    // });
+    this.router.navigate(['login']);
   }
 
   getVersion() {
diff --git a/ui/src/app/home/home.component.ts b/ui/src/app/home/home.component.ts
index a00a516..e0fba3a 100644
--- a/ui/src/app/home/home.component.ts
+++ b/ui/src/app/home/home.component.ts
@@ -34,7 +34,7 @@ export class HomeComponent {
                 private sanitizer: DomSanitizer,
                 private router: Router,
                 public appConstants: AppConstants) {
-        this.serviceLinks = this.homeService.getServiceLinks();
+        this.serviceLinks = this.homeService.getFilteredServiceLinks();
     }
 
     getBackground(url) {
diff --git a/ui/src/app/services/auth.service.ts b/ui/src/app/services/auth.service.ts
index 209747b..cf2e33c 100644
--- a/ui/src/app/services/auth.service.ts
+++ b/ui/src/app/services/auth.service.ts
@@ -22,9 +22,11 @@ import { BehaviorSubject, Observable, timer } from 'rxjs';
 import { JwtHelperService } from '@auth0/angular-jwt';
 import { JwtTokenStorageService } from './jwt-token-storage.service';
 import { UserInfo } from '../core-model/gen/streampipes-model-client';
-import { filter, map, switchMap, tap } from 'rxjs/operators';
+import { filter, map, switchMap } from 'rxjs/operators';
 import { Router } from '@angular/router';
 import { LoginService } from '../login/services/login.service';
+import { PageName } from '../_enums/page-name.enum';
+import { UserRole } from '../_enums/user-role.enum';
 
 @Injectable()
 export class AuthService {
@@ -51,10 +53,13 @@ export class AuthService {
     }
 
     public login(data) {
+        const jwtHelper: JwtHelperService = new JwtHelperService({});
+        const decodedToken = jwtHelper.decodeToken(data.accessToken);
+        console.log(decodedToken);
         this.tokenStorage.saveToken(data.accessToken);
-        this.tokenStorage.saveUser(data.userInfo);
+        this.tokenStorage.saveUser(decodedToken.user);
         this.authToken$.next(data.accessToken);
-        this.user$.next(data.userInfo);
+        this.user$.next(decodedToken.user);
     }
 
     public logout() {
@@ -63,7 +68,7 @@ export class AuthService {
     }
 
     public getCurrentUser(): UserInfo {
-        return this.tokenStorage.getUser();
+        return this.user$.getValue() || this.tokenStorage.getUser();
     }
 
     public authenticated(): boolean {
@@ -114,4 +119,66 @@ export class AuthService {
             this.router.navigate(['login']);
         });
     }
+
+    getUserRoles(): string[] {
+        return this.getCurrentUser().roles;
+    }
+
+    public hasRole(role: UserRole): boolean {
+        return this.getUserRoles().includes(UserRole[role]);
+    }
+
+    public hasAnyRole(roles: UserRole[]): boolean {
+        if (Array.isArray(roles)) {
+            return roles.reduce((aggregator: false, role: UserRole) => aggregator || this.hasRole(role), false);
+        }
+
+        return false;
+    }
+
+    isAnyAccessGranted(pageNames: PageName[]): boolean {
+        if (!pageNames || pageNames.length === 0) {
+            return true;
+        }
+
+        const result = pageNames.some(pageName => this.isAccessGranted(pageName));
+        if (!result) {
+            this.router.navigate(['']);
+        }
+        console.log(pageNames);
+        console.log(result);
+        return result;
+    }
+
+    isAccessGranted(pageName: PageName) {
+        console.log(pageName);
+        console.log(this.hasRole(UserRole.ADMIN));
+        if (this.hasRole(UserRole.ADMIN)) {
+            return true;
+        }
+        switch (pageName) {
+            case PageName.HOME:
+                return true;
+            case PageName.PIPELINE_EDITOR:
+                return this.hasAnyRole([UserRole.PIPELINE_ADMIN]);
+            case PageName.PIPELINE_OVERVIEW:
+                return this.hasAnyRole([UserRole.PIPELINE_ADMIN]);
+            case PageName.CONNECT:
+                return this.hasAnyRole([UserRole.CONNECT_ADMIN]);
+            case PageName.DASHBOARD:
+                return this.hasAnyRole([UserRole.DASHBOARD_USER, UserRole.DASHBOARD_ADMIN]);
+            case PageName.DATA_EXPLORER:
+                return this.hasAnyRole([UserRole.DATA_EXPLORER_ADMIN, UserRole.DATA_EXPLORER_USER]);
+            case PageName.APPS:
+                return this.hasAnyRole([UserRole.APP_USER]);
+            case PageName.FILE_UPLOAD:
+                return this.hasAnyRole([UserRole.CONNECT_ADMIN, UserRole.PIPELINE_ADMIN]);
+            case PageName.INSTALL_PIPELINE_ELEMENTS:
+                return this.hasAnyRole([UserRole.ADMIN]);
+            case PageName.SETTINGS:
+                return this.hasAnyRole([UserRole.ADMIN]);
+            default:
+                return true;
+        }
+    }
 }