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

riemer pushed a commit to branch minor-layout-harmonization
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit fb14c03376129aea1a7c17883ddf183d8a64d0a3
Author: Dominik Riemer <[email protected]>
AuthorDate: Wed Oct 29 23:12:52 2025 +0100

    Add expandable menubar
---
 ui/deployment/base-navigation.component.mst        |  80 ++-
 ui/deployment/categories.yml                       |  12 +
 ui/deployment/modules.yml                          |  21 +-
 ui/deployment/prebuild.js                          |  15 +-
 ui/deployment/theme/_custom-variables.scss         |  32 +-
 ...asset-browser-filter-asset-model.component.html |   0
 .../asset-browser-filter-asset-model.component.ts  |   0
 .../asset-browser-toolbar.component.html           |  53 +-
 .../asset-browser-toolbar.component.ts             |  66 ++-
 .../basic-view/basic-view.component.html           |   6 +-
 .../basic-view/basic-view.component.scss           |   8 +-
 .../shared-ui/src/lib/shared-ui.module.ts          |   1 +
 .../streampipes/shared-ui/src/public-api.ts        |   1 +
 .../existing-adapters.component.html               | 565 ++++++++++-----------
 ui/src/app/core/components/bars.scss               |  34 --
 .../breadcrumb/breadcrumb.component.scss           |   5 +-
 .../core/components/iconbar/iconbar.component.html | 198 ++++++--
 .../core/components/iconbar/iconbar.component.scss | 251 +++++++++
 .../core/components/iconbar/iconbar.component.ts   |   2 +-
 .../streampipes/streampipes.component.html         |  39 +-
 .../streampipes/streampipes.component.scss         |  58 ++-
 .../core/components/toolbar/toolbar.component.html |  44 +-
 .../core/components/toolbar/toolbar.component.scss |  17 +-
 .../core/components/toolbar/toolbar.component.ts   |   2 +-
 ui/src/app/core/navigation.backup                  | 238 +++++++++
 .../overview/dashboard-overview.component.html     |  59 +--
 .../overview/data-explorer-overview.component.html |  59 +--
 ui/src/app/pipelines/pipelines.component.html      | 177 +++----
 ui/src/scss/sp/layout.scss                         |   4 +-
 ui/src/scss/sp/main.scss                           |  12 +-
 30 files changed, 1378 insertions(+), 681 deletions(-)

diff --git a/ui/deployment/base-navigation.component.mst 
b/ui/deployment/base-navigation.component.mst
index cf4a84b36d..d7d25a1ab6 100644
--- a/ui/deployment/base-navigation.component.mst
+++ b/ui/deployment/base-navigation.component.mst
@@ -23,14 +23,49 @@ import { AuthService } from '../../services/auth.service';
 import { CurrentUserService } from '@streampipes/shared-ui';
 import { AppConstants } from '../../services/app.constants';
 import { UserPrivilege } from '../../_enums/user-privilege.enum';
-import { inject } from '@angular/core';
+import { inject, signal } from '@angular/core';
+
+export interface MenuItem {
+  link: string;
+  title: string;
+  icon: string;
+  pageNames: any[];
+  privileges: any[];
+  visible?: boolean;
+  category: string;
+}
+
+export interface MenuGroup {
+  title: string;
+  items: MenuItem[];
+  collapsed?: boolean;
+}
+
+export interface MenuCategory {
+  id: string;
+  title: string;
+  collapsed: boolean;
+}
 
 export abstract class BaseNavigationComponent {
 
   activePageName: string;
-  activePage: any;
-
+  activePage = 'home';
   authenticated = true;
+  topItems: MenuItem[] = [];
+  menuGroups: MenuGroup[] = [];
+  notificationsVisible = false;
+  isCollapsed = signal<boolean>(this.loadCollapsed());
+
+  public categories: MenuCategory[] = [
+    {{#categoriesActive}}
+      {
+          id: '{{{id}}}',
+          title: '{{{title}}}',
+          collapsed: {{{collapsed}}},
+      },
+    {{/categoriesActive}}
+  ]
 
   public menu = [
     {{#modulesActive}}
@@ -40,14 +75,12 @@ export abstract class BaseNavigationComponent {
         icon: '{{{icon}}}',
         pageNames: [{{{pageNames}}}],
         privileges: {{{privileges}}},
-        visible: false
+        visible: false,
+        category: '{{{category}}}'
     },
     {{/modulesActive}}
   ];
 
-  notificationsVisible = false;
-
-
    protected authService = inject(AuthService);
    protected currentUserService = inject(CurrentUserService);
    protected router = inject(Router);
@@ -56,6 +89,16 @@ export abstract class BaseNavigationComponent {
     onInit() {
       this.currentUserService.user$.subscribe(user => {
         this.menu.forEach(m => m.visible = 
this.isNavItemVisible(m.privileges));
+        const menuGroups = this.categories.map(category => {
+          return {
+            title: category.title,
+            collapsed: category.collapsed,
+            items: this.menu.filter(m => m.category === category.id && 
m.visible)
+          }
+        }).filter(m => m.items.length > 0);
+
+        this.topItems = menuGroups.find(m => m.title === 'top')?.items || [];
+        this.menuGroups = menuGroups.filter(m => m.title !== 'top');
         this.notificationsVisible = this.isNavItemVisible([
         UserPrivilege.PRIVILEGE_READ_PIPELINE,
         UserPrivilege.PRIVILEGE_WRITE_PIPELINE
@@ -71,10 +114,6 @@ export abstract class BaseNavigationComponent {
       });
     }
 
-    getActivePage() {
-      return this.activePage;
-    }
-
     getPageTitle(path) {
       let currentTitle = this.appConstants.APP_NAME;
       this.menu.forEach(m => {
@@ -103,4 +142,23 @@ export abstract class BaseNavigationComponent {
       return this.authService.isAnyAccessGranted(privileges);
     }
 
+    toggleMenubar(): void {
+        const next = !this.isCollapsed();
+        this.isCollapsed.set(next);
+        localStorage.setItem('sp-menubar-collapsed', JSON.stringify(next));
+      }
+
+      toggleGroup(group: MenuGroup): void {
+        group.collapsed = !group.collapsed;
+      }
+
+      private loadCollapsed(): boolean {
+        try {
+          const v = localStorage.getItem('sp-menubar-collapsed');
+          return v ? JSON.parse(v) : false;
+        } catch {
+          return false;
+        }
+      }
+
 }
diff --git a/ui/deployment/categories.yml b/ui/deployment/categories.yml
new file mode 100644
index 0000000000..d6c12ef162
--- /dev/null
+++ b/ui/deployment/categories.yml
@@ -0,0 +1,12 @@
+- id: top
+  title: top
+  collapsed: false
+- id: analytics
+  title: Analytics
+  collapsed: false
+- id: visualization
+  title: Visualization
+  collapsed: false
+- id: management
+  title: Management
+  collapsed: true
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index 23564fedbb..f11fd16949 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -27,6 +27,7 @@ spAssets:
     privileges: '[UserPrivilege.PRIVILEGE_READ_ASSETS, 
UserPrivilege.PRIVILEGE_WRITE_ASSETS]'
     pageNames: 'PageName.ASSETS'
     showStatusBox: false
+    category: 'management'
 spHome:
     streamPipesModule: True
     moduleName: 'HomeModule'
@@ -40,6 +41,7 @@ spHome:
     privileges: '[]'
     guard: 'canActivate: [ConfiguredCanActivateGuard], '
     showStatusBox: false
+    category: 'top'
 spConnect:
     componentImport: False
     moduleName: 'ConnectModule'
@@ -62,6 +64,7 @@ spConnect:
         dataFns: '[this.adapterService.getAdapters()]'
         viewRoles: '[UserPrivilege.PRIVILEGE_READ_ADAPTER, 
UserPrivilege.PRIVILEGE_WRITE_ADAPTER]'
         createRoles: '[UserPrivilege.PRIVILEGE_WRITE_ADAPTER]'
+    category: 'management'
 spPipelines:
     componentImport: False
     moduleName: 'PipelinesModule'
@@ -84,6 +87,7 @@ spPipelines:
         dataFns: '[this.pipelineService.getPipelines()]'
         viewRoles: '[UserPrivilege.PRIVILEGE_READ_PIPELINE, 
UserPrivilege.PRIVILEGE_WRITE_PIPELINE]'
         createRoles: '[UserPrivilege.PRIVILEGE_WRITE_PIPELINE]'
+    category: 'analytics'
 spConfiguration:
     componentImport: False
     moduleName: 'ConfigurationModule'
@@ -98,20 +102,7 @@ spConfiguration:
     pageNames: 'PageName.SETTINGS'
     privileges: '[UserPrivilege.PRIVILEGE_WRITE_ASSETS, 
UserPrivilege.PRIVILEGE_WRITE_LABELS, UserPrivilege.PRIVILEGE_WRITE_FILES]'
     showStatusBox: false
-spAppOverview:
-    componentImport: False
-    moduleName: 'AppOverviewModule'
-    component: 'AppOverviewComponent'
-    componentPath: './app-overview/app-overview.component'
-    path: './app-overview/app-overview.module'
-    link: 'apps'
-    url: '/apps'
-    title: 'Apps'
-    description: 'The app overview lets you access additional plugins.'
-    icon: 'apps'
-    pageNames: 'PageName.APPS'
-    privileges: '[UserPrivilege.PRIVILEGE_READ_APPS, 
UserPrivilege.PRIVILEGE_WRITE_APPS]'
-    showStatusBox: false
+    category: 'management'
 spDashboard:
     componentImport: False
     moduleName: 'DashboardModule'
@@ -134,6 +125,7 @@ spDashboard:
         dataFns: '[this.dashboardService.getDashboards()]'
         viewRoles: '[UserPrivilege.PRIVILEGE_READ_DASHBOARD, 
UserPrivilege.PRIVILEGE_WRITE_DASHBOARD]'
         createRoles: '[UserPrivilege.PRIVILEGE_WRITE_DASHBOARD]'
+    category: 'visualization'
 spDataExplorer:
     componentImport: False
     moduleName: 'DataExplorerModule'
@@ -156,3 +148,4 @@ spDataExplorer:
         dataFns: '[this.chartService.getAllCharts()]'
         viewRoles: '[UserPrivilege.PRIVILEGE_READ_DATA_EXPLORER_VIEW, 
UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW]'
         createRoles: '[UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW]'
+    category: 'visualization'
diff --git a/ui/deployment/prebuild.js b/ui/deployment/prebuild.js
index 3e00297dcd..5e2448203c 100644
--- a/ui/deployment/prebuild.js
+++ b/ui/deployment/prebuild.js
@@ -54,6 +54,7 @@ try {
 
 // Read Modules-File and check if it is valid
 let modules = {};
+let categories = [];
 try {
     modules = yaml.load(fs.readFileSync('deployment/modules.yml', 'utf8'));
 } catch (error) {
@@ -61,8 +62,19 @@ try {
     process.exit(1);
 }
 
+try {
+    categories = yaml.load(
+        fs.readFileSync('deployment/categories.yml', 'utf8'),
+    );
+} catch (error) {
+    console.log(
+        'Invalid file categories.yml. Check if the file exists in your build 
configuration. Pre-Build failed.',
+    );
+    process.exit(1);
+}
+
 // Add active Modules to Template-Variable
-let modulesActive = { modulesActive: [] };
+let modulesActive = { modulesActive: [], categoriesActive: categories };
 for (let module of config.modules) {
     modulesActive['modulesActive'].push({
         module: module,
@@ -81,6 +93,7 @@ for (let module of config.modules) {
         description: modules[module]['description'],
         showStatusBox: modules[module]['showStatusBox'],
         statusBox: modules[module]['statusBox'],
+        category: modules[module]['category'],
     });
     console.log('Active Angular Module: ' + module);
 }
diff --git a/ui/deployment/theme/_custom-variables.scss 
b/ui/deployment/theme/_custom-variables.scss
index 97cdb76054..7c20248217 100644
--- a/ui/deployment/theme/_custom-variables.scss
+++ b/ui/deployment/theme/_custom-variables.scss
@@ -27,13 +27,33 @@
     --color-loading-bar: var(--color-primary);
     --color-primary-alt: rgb(59, 92, 149);
 
-    --color-navigation-bg: var(--color-secondary);
-    --color-navigation-link-text: var(--color-bg-0);
+    --color-menubar-bg: var(--color-secondary);
+    --color-menubar-bg-menu-item: var(--color-secondary);
+    --color-menubar-bg-menu-item-hover: var(--color-secondary);
+    --color-menubar-bg-menu-item-selected: var(--color-secondary);
+    --color-menubar-bg-menu-group-hover: var(--color-secondary);
+    --color-menubar-bg-menu-group-selected: var(--color-secondary);
+    --color-menubar-text-menu-item: var(--color-bg-1);
+    --color-menubar-text-menu-group: var(--color-primary);
+    --color-menubar-text-menu-item-hover: var(--color-bg-1);
+    --color-menubar-text-menu-group-hover: var(--color-primary);
+    //--color-menubar-bg: var(--color-bg-0);
+    //--color-menubar-bg-menu-item: var(--color-bg-0);
+    //--color-menubar-bg-menu-item-hover: var(--color-bg-2);
+    //--color-menubar-bg-menu-item-selected: var(--color-bg-2);
+    //--color-menubar-bg-menu-group-hover: var(--color-bg-1);
+    //--color-menubar-bg-menu-group-selected: var(--color-bg-1);
+    //--color-menubar-text-menu-item: var(--color-secondary);
+    //--color-menubar-text-menu-group: var(--color-primary);
+    //--color-menubar-text-menu-item-hover: var(--color-secondary-dark);
+    //--color-menubar-text-menu-group-hover: var(--color-bg-1);
 
-    --color-navigation-selected: var(--color-secondary);
-    --color-navigation-hover: var(--color-secondary-dark);
-    --color-navigation-bg-selected: var(--color-bg-1);
-    --color-navigation-divider: var(--color-secondary);
+    --color-toolbar-bg: var(--color-bg-0);
+    --color-toolbar-text: var(--color-secondary);
+    --color-toolbar-text-hover: var(--color-secondary-dark);
+    --color-toolbar-icon: var(--color-secondary);
+    --color-toolbar-icon-hover: var(--color-secondary-dark);
+    --color-toolbar-icon-selected: var(--color-secondary-dark);
 }
 
 .dark-mode {
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-asset-model/asset-browser-filter-asset-model.component.html
 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-asset-model/asset-browser-filter-asset-model.component.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-asset-model/asset-browser-filter-asset-model.component.ts
 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-asset-model/asset-browser-filter-asset-model.component.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
index 4ebd2f1850..cbf4d703c8 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
@@ -16,37 +16,24 @@
   ~
   -->
 
-<div fxFlex fxLayoutAlign="start center" *ngIf="expanded">
-    <span class="ml-5">{{ 'Browse assets' | translate }}</span>
-</div>
-<div fxLayoutAlign="end center">
-    <button
-        mat-icon-button
-        *ngIf="expanded"
-        color="accent"
-        [matMenuTriggerFor]="menu"
-        #menuTrigger="matMenuTrigger"
-        [matTooltip]="'Filter assets' | translate"
-        (menuClosed)="menuTrigger.closeMenu()"
-    >
-        <mat-icon>filter_alt</mat-icon>
-    </button>
-    <mat-menu #menu="matMenu" fxFlex="100" class="large-menu">
-        <sp-asset-browser-filter
-            (closeMenu)="closeMenu()"
-            [assetBrowserData]="assetBrowserData"
+@if (showAssetBrowser) {
+    <div fxLayoutAlign="end center">
+        <button
+            mat-icon-button
+            color="accent"
+            [matMenuTriggerFor]="menu"
+            #menuTrigger="matMenuTrigger"
+            [matTooltip]="'Filter assets' | translate"
+            (menuClosed)="menuTrigger.closeMenu()"
         >
-        </sp-asset-browser-filter>
-    </mat-menu>
-    <button
-        mat-icon-button
-        color="accent"
-        (click)="toggleExpanded.emit(!expanded)"
-    >
-        <mat-icon>{{
-            expanded
-                ? 'keyboard_double_arrow_left'
-                : 'keyboard_double_arrow_right'
-        }}</mat-icon>
-    </button>
-</div>
+            <mat-icon>filter_alt</mat-icon>
+        </button>
+        <mat-menu #menu="matMenu" fxFlex="100" class="large-menu">
+            <sp-asset-browser-filter
+                (closeMenu)="closeMenu()"
+                [assetBrowserData]="assetBrowserData"
+            >
+            </sp-asset-browser-filter>
+        </mat-menu>
+    </div>
+}
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
index 1352e35da8..9390c2ade1 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
@@ -19,30 +19,88 @@
 import {
     Component,
     EventEmitter,
+    inject,
     Input,
+    OnInit,
     Output,
     ViewChild,
 } from '@angular/core';
 import { AssetBrowserData } from '../asset-browser.model';
 import { MatMenuTrigger } from '@angular/material/menu';
+import { Subscription } from 'rxjs';
+import { TranslateService } from '@ngx-translate/core';
+import { CurrentUserService } from '../../../services/current-user.service';
+import { SpAssetBrowserService } from '../asset-browser.service';
+import { SpAsset } from '@streampipes/platform-services';
 
 @Component({
     selector: 'sp-asset-browser-toolbar',
     templateUrl: 'asset-browser-toolbar.component.html',
     standalone: false,
 })
-export class AssetBrowserToolbarComponent {
+export class AssetBrowserToolbarComponent implements OnInit {
+    private currentUserService = inject(CurrentUserService);
+    private assetBrowserService = inject(SpAssetBrowserService);
+    private translateService = inject(TranslateService);
+
     @Input()
-    expanded: boolean;
+    allResourcesAlias = this.translateService.instant('Resources');
 
-    @Output()
-    toggleExpanded = new EventEmitter<boolean>();
+    @Input()
+    browserWidth = 20;
+
+    @Input()
+    filteredAssetLinkType: string;
 
     @Input()
+    resourceCount = 0;
+
+    @Input()
+    assetSelectionMode = false;
+
+    @Output()
+    filterIdsEmitter: EventEmitter<Set<string>> = new EventEmitter<
+        Set<string>
+    >();
+
+    @Output()
+    selectedAssetIdEmitter: EventEmitter<string> = new EventEmitter<string>();
+
     assetBrowserData: AssetBrowserData;
+    showAssetBrowser = false;
+
+    assetBrowserDataSub: Subscription;
 
     @ViewChild('menuTrigger') menu: MatMenuTrigger;
 
+    ngOnInit() {
+        this.showAssetBrowser = this.currentUserService.hasAnyRole([
+            'PRIVILEGE_READ_ASSETS',
+            'PRIVILEGE_WRITE_ASSETS',
+        ]);
+        if (this.showAssetBrowser) {
+            this.assetBrowserDataSub =
+                this.assetBrowserService.assetData$.subscribe(assetData => {
+                    this.assetBrowserData = assetData;
+                    console.log(assetData);
+                });
+        }
+    }
+
+    applyAssetFilter(asset: SpAsset) {
+        const elementIds = new Set<string>();
+        if (asset.assetId !== '_root') {
+            this.assetBrowserService.collectElementIds(
+                asset,
+                this.filteredAssetLinkType,
+                elementIds,
+            );
+            this.filterIdsEmitter.emit(elementIds);
+        }
+        this.filterIdsEmitter.emit(elementIds);
+        this.selectedAssetIdEmitter.emit(asset.assetId);
+    }
+
     closeMenu(): void {
         this.menu.closeMenu();
     }
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html
 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html
index 868bf057b7..ae4739788b 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.html
@@ -17,11 +17,7 @@
   -->
 
 <div fxLayout="column" class="page-container">
-    <div
-        fxLayout="row"
-        class="p-0 sp-bg-lightgray page-container-nav"
-        *ngIf="!hideNavbar"
-    >
+    <div fxLayout="row" class="p-0 page-container-nav" *ngIf="!hideNavbar">
         <div fxLayout="fill" fxFlex="100" class="pl-5 pr-5">
             <div
                 fxLayout="row"
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss
 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss
index 1200a6529b..454f054f9e 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/basic-view/basic-view.component.scss
@@ -29,8 +29,8 @@
     line-height: 24px;
     height: 44px;
     border-bottom: 1px solid var(--color-bg-3);
-    border-top-left-radius: 10px;
-    border-top-right-radius: 10px;
+    border-top-left-radius: 6px;
+    border-top-right-radius: 6px;
 }
 
 .sp-bg-lightgray {
@@ -44,9 +44,9 @@
 .page-container {
     margin: 10px;
     border: 1px solid var(--color-bg-3);
-    min-height: calc(100vh - 90px);
+    min-height: calc(100vh - 75px);
     background-color: var(--color-bg-main-panel-content);
-    border-radius: 10px;
+    border-radius: 6px;
 }
 
 .page-container-padding-inner {
diff --git a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts 
b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
index 176c333794..61f40fc93c 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
+++ b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
@@ -192,6 +192,7 @@ import { AssetLinkConfigurationComponent } from 
'./components/asset-link-configu
     ],
     exports: [
         AssetBrowserComponent,
+        AssetBrowserToolbarComponent,
         AssetLinkConfigurationComponent,
         ConfirmDialogComponent,
         DataDownloadDialogComponent,
diff --git a/ui/projects/streampipes/shared-ui/src/public-api.ts 
b/ui/projects/streampipes/shared-ui/src/public-api.ts
index e25e3ad2b4..4fab61f8d4 100644
--- a/ui/projects/streampipes/shared-ui/src/public-api.ts
+++ b/ui/projects/streampipes/shared-ui/src/public-api.ts
@@ -29,6 +29,7 @@ export * from 
'./lib/dialog/standard-dialog/standard-dialog.component';
 export * from 
'./lib/dialog/pipeline-element-help/pipeline-element-help.component';
 
 export * from './lib/components/asset-browser/asset-browser.component';
+export * from 
'./lib/components/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component';
 export * from './lib/components/basic-header-title/header-title.component';
 export * from './lib/components/basic-inner-panel/basic-inner-panel.component';
 export * from 
'./lib/components/basic-field-description/basic-field-description.component';
diff --git 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
index 9b85f61375..a4b1d5caec 100644
--- 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
+++ 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.html
@@ -16,333 +16,278 @@
   ~
   -->
 
-<sp-asset-browser
-    filteredAssetLinkType="adapter"
-    [allResourcesAlias]="'Adapters' | translate"
-    [resourceCount]="existingAdapters.length"
-    (filterIdsEmitter)="applyAdapterFilters($event)"
->
-    <sp-basic-view [showBackLink]="false" [padding]="true">
-        <div
-            nav
-            fxFlex="100"
-            fxLayoutAlign="start center"
-            fxLayout="row"
-            fxLayoutGap="10px"
-            class="pl-10"
+<sp-basic-view [showBackLink]="false" [padding]="true">
+    <div
+        nav
+        fxFlex="100"
+        fxLayoutAlign="start center"
+        fxLayout="row"
+        fxLayoutGap="10px"
+        class="pl-10"
+    >
+        <button
+            mat-flat-button
+            data-cy="connect-create-new-adapter-button"
+            (click)="createNewAdapter()"
         >
-            <button
-                mat-flat-button
-                data-cy="connect-create-new-adapter-button"
-                (click)="createNewAdapter()"
-            >
-                <i class="material-icons">add</i>&nbsp;{{
-                    'New adapter' | translate
-                }}
-            </button>
-            <button
-                mat-flat-button
-                class="mat-basic"
-                data-cy="start-all-adapters-btn"
-                [disabled]="checkCurrentSelectionStatus(false)"
-                (click)="startAllAdapters(true)"
+            <i class="material-icons">add</i>&nbsp;{{
+                'New adapter' | translate
+            }}
+        </button>
+        <button
+            mat-flat-button
+            class="mat-basic"
+            data-cy="start-all-adapters-btn"
+            [disabled]="checkCurrentSelectionStatus(false)"
+            (click)="startAllAdapters(true)"
+        >
+            <mat-icon>play_arrow</mat-icon>
+            <span>{{ 'Start all adapters' | translate }}</span>
+        </button>
+        <button
+            mat-flat-button
+            class="mat-basic"
+            data-cy="stop-all-adapters-btn"
+            [disabled]="checkCurrentSelectionStatus(true)"
+            (click)="startAllAdapters(false)"
+        >
+            <mat-icon>stop</mat-icon>
+            <span>{{ 'Stop all adapters' | translate }}</span>
+        </button>
+        <div fxFlex fxLayout="row" fxLayoutAlign="end center">
+            <sp-connect-filter-toolbar
+                class="filter-bar-margin"
+                (filterChangedEmitter)="applyFilter($event)"
             >
-                <mat-icon>play_arrow</mat-icon>
-                <span>{{ 'Start all adapters' | translate }}</span>
-            </button>
-            <button
-                mat-flat-button
-                class="mat-basic"
-                data-cy="stop-all-adapters-btn"
-                [disabled]="checkCurrentSelectionStatus(true)"
-                (click)="startAllAdapters(false)"
+            </sp-connect-filter-toolbar>
+            <div
+                fxFlex="100"
+                fxLayout="row"
+                fxLayoutAlign="end center"
+                class="page-container-nav"
             >
-                <mat-icon>stop</mat-icon>
-                <span>{{ 'Stop all adapters' | translate }}</span>
-            </button>
-            <div fxFlex fxLayout="row" fxLayoutAlign="end center">
-                <sp-connect-filter-toolbar
-                    class="filter-bar-margin"
-                    (filterChangedEmitter)="applyFilter($event)"
+                <sp-asset-browser-toolbar
+                    filteredAssetLinkType="adapter"
+                    [allResourcesAlias]="'Adapters' | translate"
+                    [resourceCount]="existingAdapters.length"
+                    (filterIdsEmitter)="applyAdapterFilters($event)"
                 >
-                </sp-connect-filter-toolbar>
-                <div
-                    fxFlex="100"
-                    fxLayout="row"
-                    fxLayoutAlign="end center"
-                    class="page-container-nav"
-                >
-                    <button
-                        mat-icon-button
-                        color="accent"
-                        id="startAdapterTutorial3"
-                        (click)="startAdapterTutorial()"
-                        matTooltip="Tutorial: Generic Adapter"
-                        [disabled]="tutorialActive"
-                    >
-                        <mat-icon>school</mat-icon>
-                    </button>
-                </div>
+                </sp-asset-browser-toolbar>
                 <button
                     mat-icon-button
-                    [matTooltip]="'Refresh adapters' | translate"
-                    matTooltipPosition="below"
                     color="accent"
-                    (click)="getAdaptersRunning()"
+                    id="startAdapterTutorial3"
+                    (click)="startAdapterTutorial()"
+                    matTooltip="Tutorial: Generic Adapter"
+                    [disabled]="tutorialActive"
                 >
-                    <i class="material-icons"> refresh </i>
+                    <mat-icon>school</mat-icon>
                 </button>
             </div>
+            <button
+                mat-icon-button
+                [matTooltip]="'Refresh adapters' | translate"
+                matTooltipPosition="below"
+                color="accent"
+                (click)="getAdaptersRunning()"
+            >
+                <i class="material-icons"> refresh </i>
+            </button>
         </div>
-        <div fxFlex="100" fxLayout="column">
-            <sp-basic-header-title-component
-                [title]="'Adapters' | translate"
-            ></sp-basic-header-title-component>
-            <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
-                <sp-table
-                    fxFlex="100"
-                    [columns]="displayedColumns"
-                    [dataSource]="dataSource"
-                    [showActionsMenu]="true"
-                    [rowsClickable]="true"
-                    (rowClicked)="navigateToDetailsOverviewPage($event)"
-                    data-cy="all-adapters-table"
-                    matSort
-                >
-                    <ng-container matColumnDef="status">
-                        <th mat-header-cell mat-sort-header *matHeaderCellDef>
-                            {{ 'Status' | translate }}
-                        </th>
-                        <td mat-cell *matCellDef="let adapter">
-                            <sp-adapter-status-light
-                                [adapterRunning]="adapter.running"
-                            ></sp-adapter-status-light>
-                        </td>
-                    </ng-container>
-                    <ng-container matColumnDef="start">
-                        <th mat-header-cell *matHeaderCellDef>Start</th>
-                        <td
-                            mat-cell
-                            *matCellDef="let adapter"
-                            data-cy="adapters-table"
-                        >
-                            @if (
-                                adapter.elementId ===
-                                operationInProgressAdapterId
-                            ) {
-                                <div
-                                    
data-cy="adapter-operation-in-progress-spinner"
-                                    fxLayoutAlign="center center"
-                                >
-                                    <mat-spinner
-                                        color="accent"
-                                        [diameter]="20"
-                                    ></mat-spinner>
-                                </div>
-                            } @else if (!adapter.running) {
-                                <button
-                                    color="accent"
-                                    mat-icon-button
-                                    matTooltip="Start adapter"
-                                    matTooltipPosition="above"
-                                    data-cy="start-adapter"
-                                    (click)="
-                                        startAdapter(adapter);
-                                        $event.stopPropagation()
-                                    "
-                                >
-                                    <i class="material-icons">play_arrow</i>
-                                </button>
-                            } @else if (adapter.running) {
-                                <button
-                                    color="accent"
-                                    mat-icon-button
-                                    matTooltip="Stop adapter"
-                                    matTooltipPosition="above"
-                                    data-cy="stop-adapter"
-                                    (click)="
-                                        stopAdapter(adapter);
-                                        $event.stopPropagation()
-                                    "
-                                >
-                                    <i class="material-icons">stop</i>
-                                </button>
-                            }
-                        </td>
-                    </ng-container>
-
-                    <ng-container matColumnDef="name">
-                        <th mat-header-cell mat-sort-header *matHeaderCellDef>
-                            {{ 'Name' | translate }}
-                        </th>
-                        <td mat-cell *matCellDef="let adapter">
+    </div>
+    <div fxFlex="100" fxLayout="column">
+        <sp-basic-header-title-component
+            [title]="'Adapters' | translate"
+        ></sp-basic-header-title-component>
+        <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
+            <sp-table
+                fxFlex="100"
+                [columns]="displayedColumns"
+                [dataSource]="dataSource"
+                [showActionsMenu]="true"
+                [rowsClickable]="true"
+                (rowClicked)="navigateToDetailsOverviewPage($event)"
+                data-cy="all-adapters-table"
+                matSort
+            >
+                <ng-container matColumnDef="status">
+                    <th mat-header-cell mat-sort-header *matHeaderCellDef>
+                        {{ 'Status' | translate }}
+                    </th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <sp-adapter-status-light
+                            [adapterRunning]="adapter.running"
+                        ></sp-adapter-status-light>
+                    </td>
+                </ng-container>
+                <ng-container matColumnDef="start">
+                    <th mat-header-cell *matHeaderCellDef>Start</th>
+                    <td
+                        mat-cell
+                        *matCellDef="let adapter"
+                        data-cy="adapters-table"
+                    >
+                        @if (
+                            adapter.elementId === operationInProgressAdapterId
+                        ) {
                             <div
-                                fxLayout="column"
-                                fxLayoutAlign="start start"
-                                class="truncate"
+                                data-cy="adapter-operation-in-progress-spinner"
+                                fxLayoutAlign="center center"
                             >
-                                <b data-cy="adapter-name">{{ adapter.name 
}}</b>
-                                <small> {{ adapter.description }}</small>
+                                <mat-spinner
+                                    color="accent"
+                                    [diameter]="20"
+                                ></mat-spinner>
                             </div>
-                        </td>
-                    </ng-container>
-                    <ng-container matColumnDef="adapterBase">
-                        <th mat-header-cell *matHeaderCellDef>Adapter</th>
-                        <td mat-cell *matCellDef="let adapter">
-                            <img
-                                class="adapter-icon"
-                                *ngIf="getIconUrl(adapter) && !adapter.icon"
-                                [src]="getIconUrl(adapter)"
-                                [alt]="adapter.name"
-                            />
-                            <img
-                                class="adapter-icon"
-                                *ngIf="adapter.icon"
-                                [alt]="adapter.name"
-                                [src]="adapter.icon"
-                            />
-                        </td>
-                    </ng-container>
-                    <ng-container matColumnDef="lastModified">
-                        <th mat-header-cell *matHeaderCellDef>
-                            {{ 'Created' | translate }}
-                        </th>
-                        <td mat-cell *matCellDef="let adapter">
-                            <h5>
-                                {{
-                                    adapter.createdAt | date: 'dd.MM.yyyy 
HH:mm'
-                                }}
-                            </h5>
-                        </td>
-                    </ng-container>
-
-                    <ng-container matColumnDef="messagesSent">
-                        <th
-                            mat-header-cell
-                            *matHeaderCellDef
-                            matTooltip="Messages sent since last start"
-                        >
-                            #{{ 'Messages' | translate }}
-                        </th>
-                        <td mat-cell *matCellDef="let adapter">
-                            <sp-label
-                                size="small"
-                                [labelText]="
-                                    adapterMetrics[adapter.elementId]
-                                        ?.messagesOut.counter || 0
+                        } @else if (!adapter.running) {
+                            <button
+                                color="accent"
+                                mat-icon-button
+                                matTooltip="Start adapter"
+                                matTooltipPosition="above"
+                                data-cy="start-adapter"
+                                (click)="
+                                    startAdapter(adapter);
+                                    $event.stopPropagation()
                                 "
-                            ></sp-label>
-                        </td>
-                    </ng-container>
-
-                    <ng-container matColumnDef="lastMessage">
-                        <th mat-header-cell *matHeaderCellDef>
-                            {{ 'Last message' | translate }}
-                        </th>
-                        <td mat-cell *matCellDef="let adapter">
-                            <h5>
-                                {{
-                                    adapterMetrics[adapter.elementId] &&
-                                    adapterMetrics[adapter.elementId]
-                                        .lastTimestamp > 0
-                                        ? (adapterMetrics[adapter.elementId]
-                                              .lastTimestamp
-                                          | date: 'dd.MM.yyyy HH:mm')
-                                        : 'n/a'
-                                }}
-                            </h5>
-                        </td>
-                    </ng-container>
+                            >
+                                <i class="material-icons">play_arrow</i>
+                            </button>
+                        } @else if (adapter.running) {
+                            <button
+                                color="accent"
+                                mat-icon-button
+                                matTooltip="Stop adapter"
+                                matTooltipPosition="above"
+                                data-cy="stop-adapter"
+                                (click)="
+                                    stopAdapter(adapter);
+                                    $event.stopPropagation()
+                                "
+                            >
+                                <i class="material-icons">stop</i>
+                            </button>
+                        }
+                    </td>
+                </ng-container>
 
-                    <ng-template spTableActions let-element>
-                        <button
-                            mat-menu-item
-                            data-cy="details-adapter"
-                            (click)="navigateToDetailsOverviewPage(element)"
+                <ng-container matColumnDef="name">
+                    <th mat-header-cell mat-sort-header *matHeaderCellDef>
+                        {{ 'Name' | translate }}
+                    </th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <div
+                            fxLayout="column"
+                            fxLayoutAlign="start start"
+                            class="truncate"
                         >
-                            <mat-icon>visibility</mat-icon>
-                            <span>{{ 'Show' | translate }}</span>
-                        </button>
-                        <button
-                            mat-menu-item
-                            data-cy="edit-adapter"
-                            (click)="editAdapter(element)"
-                        >
-                            <mat-icon>edit</mat-icon>
-                            <span>{{ 'Edit' | translate }}</span>
-                        </button>
-                        <button
-                            mat-menu-item
-                            data-cy="open-manage-permissions"
-                            *ngIf="isAdmin"
-                            (click)="showPermissionsDialog(element)"
-                        >
-                            <mat-icon>share</mat-icon>
-                            <span>{{ 'Manage permissions' | translate }}</span>
-                        </button>
-                        <button
-                            mat-menu-item
-                            data-cy="delete-adapter"
-                            (click)="deleteAdapter(element)"
-                        >
-                            <mat-icon>delete</mat-icon>
-                            <span>{{ 'Delete' | translate }}</span>
-                        </button>
-                    </ng-template>
+                            <b data-cy="adapter-name">{{ adapter.name }}</b>
+                            <small> {{ adapter.description }}</small>
+                        </div>
+                    </td>
+                </ng-container>
+                <ng-container matColumnDef="adapterBase">
+                    <th mat-header-cell *matHeaderCellDef>Adapter</th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <img
+                            class="adapter-icon"
+                            *ngIf="getIconUrl(adapter) && !adapter.icon"
+                            [src]="getIconUrl(adapter)"
+                            [alt]="adapter.name"
+                        />
+                        <img
+                            class="adapter-icon"
+                            *ngIf="adapter.icon"
+                            [alt]="adapter.name"
+                            [src]="adapter.icon"
+                        />
+                    </td>
+                </ng-container>
+                <ng-container matColumnDef="lastModified">
+                    <th mat-header-cell *matHeaderCellDef>
+                        {{ 'Created' | translate }}
+                    </th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <h5>
+                            {{ adapter.createdAt | date: 'dd.MM.yyyy HH:mm' }}
+                        </h5>
+                    </td>
+                </ng-container>
 
-                    <!--                    <ng-container 
matColumnDef="action">-->
-                    <!--                        <th mat-header-cell 
*matHeaderCellDef></th>-->
-                    <!--                        <td mat-cell *matCellDef="let 
adapter">-->
-                    <!--                            <div fxLayout="row" 
fxLayoutAlign="end center">-->
-                    <!--                                <button-->
-                    <!--                                    color="accent"-->
-                    <!--                                    mat-icon-button-->
-                    <!--                                    matTooltip="Show 
details"-->
-                    <!--                                    
matTooltipPosition="above"-->
-                    <!--                                    
data-cy="details-adapter"-->
-                    <!--                                    (click)="-->
-                    <!--                                        
navigateToDetailsOverviewPage(adapter)-->
-                    <!--                                    "-->
-                    <!--                                >-->
-                    <!--                                    <i 
class="material-icons">search</i>-->
-                    <!--                                </button>-->
+                <ng-container matColumnDef="messagesSent">
+                    <th
+                        mat-header-cell
+                        *matHeaderCellDef
+                        matTooltip="Messages sent since last start"
+                    >
+                        #{{ 'Messages' | translate }}
+                    </th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <sp-label
+                            size="small"
+                            [labelText]="
+                                adapterMetrics[adapter.elementId]?.messagesOut
+                                    .counter || 0
+                            "
+                        ></sp-label>
+                    </td>
+                </ng-container>
 
-                    <!--                                <button-->
-                    <!--                                    color="accent"-->
-                    <!--                                    mat-icon-button-->
-                    <!--                                    matTooltip="Edit 
adapter"-->
-                    <!--                                    
data-cy="edit-adapter"-->
-                    <!--                                    
matTooltipPosition="above"-->
-                    <!--                                    
(click)="editAdapter(adapter)"-->
-                    <!--                                >-->
-                    <!--                                    <i 
class="material-icons">edit</i>-->
-                    <!--                                </button>-->
-                    <!--                                <button-->
-                    <!--                                    color="accent"-->
-                    <!--                                    mat-icon-button-->
-                    <!--                                    matTooltip="Manage 
permissions"-->
-                    <!--                                    
matTooltipPosition="above"-->
-                    <!--                                    
data-cy="open-manage-permissions"-->
-                    <!--                                    *ngIf="isAdmin"-->
-                    <!--                                    
(click)="showPermissionsDialog(adapter)"-->
-                    <!--                                >-->
-                    <!--                                    <i 
class="material-icons">share</i>-->
-                    <!--                                </button>-->
-                    <!--                                <button-->
-                    <!--                                    color="accent"-->
-                    <!--                                    mat-icon-button-->
-                    <!--                                    matTooltip="Delete 
adapter"-->
-                    <!--                                    
data-cy="delete-adapter"-->
-                    <!--                                    
matTooltipPosition="above"-->
-                    <!--                                    
(click)="deleteAdapter(adapter)"-->
-                    <!--                                >-->
-                    <!--                                    <i 
class="material-icons">delete</i>-->
-                    <!--                                </button>-->
-                    <!--                            </div>-->
-                    <!--                        </td>-->
-                    <!--                    </ng-container>-->
-                </sp-table>
-            </div>
+                <ng-container matColumnDef="lastMessage">
+                    <th mat-header-cell *matHeaderCellDef>
+                        {{ 'Last message' | translate }}
+                    </th>
+                    <td mat-cell *matCellDef="let adapter">
+                        <h5>
+                            {{
+                                adapterMetrics[adapter.elementId] &&
+                                adapterMetrics[adapter.elementId]
+                                    .lastTimestamp > 0
+                                    ? (adapterMetrics[adapter.elementId]
+                                          .lastTimestamp
+                                      | date: 'dd.MM.yyyy HH:mm')
+                                    : 'n/a'
+                            }}
+                        </h5>
+                    </td>
+                </ng-container>
+
+                <ng-template spTableActions let-element>
+                    <button
+                        mat-menu-item
+                        data-cy="details-adapter"
+                        (click)="navigateToDetailsOverviewPage(element)"
+                    >
+                        <mat-icon>visibility</mat-icon>
+                        <span>{{ 'Show' | translate }}</span>
+                    </button>
+                    <button
+                        mat-menu-item
+                        data-cy="edit-adapter"
+                        (click)="editAdapter(element)"
+                    >
+                        <mat-icon>edit</mat-icon>
+                        <span>{{ 'Edit' | translate }}</span>
+                    </button>
+                    <button
+                        mat-menu-item
+                        data-cy="open-manage-permissions"
+                        *ngIf="isAdmin"
+                        (click)="showPermissionsDialog(element)"
+                    >
+                        <mat-icon>share</mat-icon>
+                        <span>{{ 'Manage permissions' | translate }}</span>
+                    </button>
+                    <button
+                        mat-menu-item
+                        data-cy="delete-adapter"
+                        (click)="deleteAdapter(element)"
+                    >
+                        <mat-icon>delete</mat-icon>
+                        <span>{{ 'Delete' | translate }}</span>
+                    </button>
+                </ng-template>
+            </sp-table>
         </div>
-    </sp-basic-view>
-</sp-asset-browser>
+    </div>
+</sp-basic-view>
diff --git a/ui/src/app/core/components/bars.scss 
b/ui/src/app/core/components/bars.scss
deleted file mode 100644
index c81c822360..0000000000
--- a/ui/src/app/core/components/bars.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-.sp-navbar-item-selected {
-    background: var(--color-navigation-bg-selected);
-}
-
-.sp-navbar-icon {
-    color: var(--color-navigation-link-text);
-    background: var(--color-bg-navbar-icon);
-}
-.sp-navbar-icon-selected {
-    color: var(--color-navigation-selected);
-}
-
-.sp-navbar-item:hover {
-    color: var(--color-navigation-selected);
-    background: var(--color-navigation-hover);
-}
diff --git a/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss 
b/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss
index 6649e25cff..ae16cff034 100644
--- a/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss
+++ b/ui/src/app/core/components/breadcrumb/breadcrumb.component.scss
@@ -17,11 +17,10 @@
  */
 
 .breadcrumb-outer {
-    margin: 10px 10px 0 10px;
     max-height: 20px;
     height: 20px;
     font-size: 10pt;
-    color: var(--color-primary);
+    color: var(--color-toolbar-text);
 }
 
 .divider {
@@ -31,6 +30,6 @@
 }
 
 .bc-item:hover {
-    color: var(--color-secondary);
+    color: var(--color-toolbar-text-hover);
     cursor: pointer;
 }
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.html 
b/ui/src/app/core/components/iconbar/iconbar.component.html
index e90d1b9d12..f7a3d2b104 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.html
+++ b/ui/src/app/core/components/iconbar/iconbar.component.html
@@ -16,36 +16,176 @@
   ~
   -->
 
-<div style="padding-top: 0" fxFlex="100" fxLayout="column">
-    @for (item of menu; track item.title) {
-        @if (item.visible) {
-            <div
-                style="min-width: 0; padding: 5px 0"
-                [ngClass]="
-                    item.link === activePage
-                        ? 'sp-navbar-item-selected'
-                        : 'sp-navbar-item'
-                "
+<div class="menubar-root" [class.collapsed]="isCollapsed()" fxLayout="column">
+    <!-- Header / brand -->
+    <div
+        class="menubar-header"
+        fxLayout="row"
+        fxLayoutAlign="space-between center"
+    >
+        <div class="brand" [class.hidden]="isCollapsed()">
+            <img alt="logo" src="assets/img/sp/logo-navigation.png" />
+        </div>
+
+        <button
+            type="button"
+            class="collapse-btn"
+            (click)="toggleMenubar()"
+            [attr.aria-label]="isCollapsed() ? 'Expand menu' : 'Collapse menu'"
+            [title]="isCollapsed() ? 'Expand' : 'Collapse'"
+        >
+            <mat-icon class="collapse-icon" [class.rotated]="isCollapsed()"
+                >chevron_left</mat-icon
             >
-                <button
-                    mat-icon-button
-                    class="button-margin-iconbar iconbar-size"
-                    (click)="go(item.link)"
-                    matTooltip="{{ item.title }}"
-                    matTooltipPosition="right"
-                >
-                    <mat-icon
-                        [ngClass]="
-                            item.link === activePage
-                                ? 'sp-navbar-icon-selected'
-                                : 'sp-navbar-icon'
+        </button>
+    </div>
+
+    <!-- Scrollable content -->
+    <div class="menubar-scroll" fxFlex fxLayout="column">
+        <!-- Top items (no group) -->
+        <div class="top-items" role="list">
+            @for (item of topItems; track item.title) {
+                @if (item.visible !== false) {
+                    <button
+                        type="button"
+                        role="listitem"
+                        class="menu-item"
+                        [class.menu-item-selected]="item.link === activePage"
+                        (click)="go(item.link)"
+                        [title]="isCollapsed() ? item.title : null"
+                        [attr.aria-current]="
+                            item.link === activePage ? 'page' : null
+                        "
+                    >
+                        <mat-icon class="item-icon">{{ item.icon }}</mat-icon>
+                        <span
+                            class="item-title text-ellipsis"
+                            [class.hidden]="isCollapsed()"
+                            >{{ item.title }}</span
+                        >
+                    </button>
+                }
+            }
+        </div>
+
+        <!-- Grouped sections -->
+        <div class="groups">
+            @for (group of menuGroups; track group.title) {
+                <section class="menu-group">
+                    <!-- Group header -->
+                    <button
+                        type="button"
+                        [class.hidden]="isCollapsed()"
+                        class="menu-group-title"
+                        (click)="toggleGroup(group)"
+                        [attr.aria-expanded]="!group.collapsed"
+                        [title]="isCollapsed() ? group.title : null"
+                    >
+                        <span
+                            class="group-title-text text-ellipsis"
+                            [class.hidden]="isCollapsed()"
+                            >{{ group.title }}</span
+                        >
+                        <mat-icon
+                            class="chevron"
+                            [class.rotate]="!group.collapsed"
+                            [class.hidden]="isCollapsed()"
+                            >expand_more</mat-icon
+                        >
+                    </button>
+
+                    <!-- Group items (accordion) -->
+                    <div
+                        class="menu-group-items"
+                        [style.maxHeight]="
+                            group.collapsed && !isCollapsed() ? '0px' : '500px'
                         "
-                        [attr.data-cy]="'navigation-icon-' + item.link"
+                        [class.instant]="isCollapsed()"
+                        role="list"
                     >
-                        {{ item.icon }}
-                    </mat-icon>
-                </button>
-            </div>
-        }
-    }
+                        @for (item of group.items; track item.title) {
+                            @if (item.visible !== false) {
+                                <button
+                                    type="button"
+                                    role="listitem"
+                                    class="menu-item"
+                                    [class.menu-item-selected]="
+                                        item.link === activePage
+                                    "
+                                    (click)="go(item.link)"
+                                    [title]="isCollapsed() ? item.title : null"
+                                    [attr.aria-current]="
+                                        item.link === activePage ? 'page' : ''
+                                    "
+                                >
+                                    <mat-icon class="item-icon">{{
+                                        item.icon
+                                    }}</mat-icon>
+                                    <span
+                                        class="item-title text-ellipsis"
+                                        [class.hidden]="isCollapsed()"
+                                        >{{ item.title }}</span
+                                    >
+                                </button>
+                            }
+                        }
+                    </div>
+                </section>
+                @if (isCollapsed()) {
+                    <mat-divider></mat-divider>
+                }
+            }
+        </div>
+    </div>
 </div>
+
+<!--  <div-->
+<!--      class="md-toolbar-tools"-->
+<!--      style="height: 40px; max-height: 40px"-->
+<!--      fxFlex-->
+<!--      fxLayout="row"-->
+<!--      fxLayoutAlign="start center"-->
+<!--  >-->
+<!--    <div-->
+<!--        style="-->
+
+<!--                        border-radius: 0px;-->
+<!--                        margin-right: 15px;-->
+<!--                        position: relative;-->
+<!--                        left: 20px;-->
+<!--                    "-->
+<!--    >-->
+<!--      <img-->
+<!--          alt="icon"-->
+<!--          src="assets/img/sp/logo.png"-->
+<!--          style="max-height: 35px; max-width: 250px"-->
+<!--      />-->
+<!--    </div>-->
+<!--  </div>-->
+
+<!--  <div fxFlex="100" fxLayout="column" class="menu-bar">-->
+<!--    @for (item of menu; track item.title) {-->
+<!--      @if (item.visible) {-->
+<!--        <div-->
+<!--            style="min-width: 0; padding: 5px 10px"-->
+<!--            fxLayoutAlign="start center"-->
+<!--            fxLayoutGap="10px"-->
+<!--            (click)="go(item.link)"-->
+<!--            [ngClass]="-->
+<!--                    item.link === activePage-->
+<!--                        ? 'iconbar-item iconbar-item-selected'-->
+<!--                        : 'iconbar-item'-->
+<!--                "-->
+<!--        >-->
+
+<!--            <mat-icon-->
+
+<!--                [attr.data-cy]="'navigation-icon-' + item.link"-->
+<!--            >-->
+<!--              {{ item.icon }}-->
+<!--            </mat-icon>-->
+<!--            <span>{{ item.title }}</span>-->
+<!--        </div>-->
+<!--      }-->
+<!--    }-->
+<!--  </div>-->
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.scss 
b/ui/src/app/core/components/iconbar/iconbar.component.scss
index f02f95dffc..9483c23acd 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.scss
+++ b/ui/src/app/core/components/iconbar/iconbar.component.scss
@@ -24,3 +24,254 @@
 .mat-mdc-icon-button.iconbar-size mat-icon {
     margin-top: 5px;
 }
+
+.md-toolbar-tools {
+    width: 100%;
+    align-items: center;
+}
+
+.menu-bar {
+    margin-top: 20px;
+    margin-left: 10px;
+    margin-right: 10px;
+}
+
+.iconbar-item:hover {
+    //background: var(--color-bg-1);
+    cursor: pointer;
+}
+
+.menubar-root {
+    --mb-width: 260px;
+    --mb-width-collapsed: 62px;
+    --mb-radius: 18px;
+    --mb-gap: 10px;
+    --mb-item-h: 34px;
+    --mb-surface: color-mix(in oklab, var(--color-menubar-bg) 90%, 
transparent);
+    --mb-surface-2: color-mix(
+        in oklab,
+        var(--color-menubar-bg) 75%,
+        transparent
+    );
+    --mb-outline: rgba(255, 255, 255, 0.08);
+    --mb-outline-strong: rgba(255, 255, 255, 0.14);
+    --mb-text-dim: var(--color-primary);
+
+    position: sticky;
+    top: 0;
+    height: 100vh;
+    width: var(--mb-width);
+    background: var(--mb-surface);
+    backdrop-filter: saturate(140%) blur(8px);
+    -webkit-backdrop-filter: saturate(140%) blur(8px);
+    box-shadow:
+        0 10px 30px rgba(0, 0, 0, 0.25),
+        inset -1px 0 0 var(--mb-outline);
+    color: var(--color-menubar-link-text);
+    display: flex;
+    flex-direction: column;
+    transition: width 0.22s ease;
+    z-index: 3;
+}
+
+.menubar-root.collapsed {
+    width: var(--mb-width-collapsed);
+}
+
+/* Header */
+.menubar-header {
+    height: var(--mat-toolbar-standard-height);
+    padding: 0 10px 0 12px;
+    border-bottom: 1px solid var(--mb-outline);
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    //background: var(--color-bg-1);
+}
+
+.brand img {
+    max-width: 100%;
+    display: block;
+    padding: 10px 0px;
+}
+
+.collapse-btn {
+    border: 0;
+    background: transparent;
+    width: 36px;
+    height: 36px;
+    border-radius: 10px;
+    display: grid;
+    place-items: center;
+    cursor: pointer;
+    transition: background 0.18s ease;
+}
+
+.collapse-btn:hover {
+    background: var(--mb-surface-2);
+}
+
+.collapse-icon {
+    transition: transform 0.22s ease;
+}
+
+.menubar-root.collapsed .collapse-icon.rotated {
+    transform: rotate(180deg);
+}
+
+.hidden {
+    display: none !important;
+}
+
+/* Scroll area */
+.menubar-scroll {
+    padding: 12px 8px 14px;
+    overflow-y: auto;
+    overscroll-behavior: contain;
+}
+
+/* Ungrouped items */
+.top-items {
+    margin-top: 32px;
+}
+
+/* Group header */
+.menu-group {
+    margin: 6px 0 10px;
+}
+
+.menu-group-title {
+    width: 100%;
+    border: 0;
+    background: var(--color-menubar-bg-menu-group);
+    color: var(--color-menubar-text-menu-group);
+    font-size: 0.75rem;
+    letter-spacing: 0.05em;
+    text-transform: uppercase;
+    padding: 8px 10px;
+    border-radius: var(--mb-radius);
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    cursor: pointer;
+    transition:
+        background 0.18s ease,
+        color 0.18s ease;
+}
+
+.menu-group-title:hover {
+    background: var(--color-menubar-bg-menu-group-hover);
+    outline-color: var(--mb-outline-strong);
+}
+
+.group-icon {
+    font-size: 18px;
+    width: 18px;
+    height: 18px;
+    opacity: 0.9;
+}
+
+.chevron {
+    margin-left: auto;
+    transition:
+        transform 0.22s ease,
+        opacity 0.18s ease;
+    opacity: 0.9;
+}
+
+.chevron.rotate {
+    transform: rotate(180deg);
+}
+
+/* Accordion container */
+.menu-group-items {
+    margin-top: 4px;
+    overflow: hidden;
+    transition: max-height 0.22s ease;
+}
+
+.menu-group-items.instant {
+    transition: none;
+}
+
+/* Menu item button */
+.menu-item {
+    width: 100%;
+    height: var(--mb-item-h);
+    padding: 8px 10px;
+    margin: 3px 0;
+    border: 0;
+    border-radius: calc(var(--mb-radius) + 2px);
+    background: transparent;
+    display: inline-flex;
+    align-items: center;
+    gap: 12px;
+    cursor: pointer;
+    text-align: left;
+    transition:
+        background 0.18s ease,
+        transform 0.06s ease,
+        outline-color 0.18s ease;
+    outline: 1px solid transparent;
+    color: var(--color-menubar-text-menu-item);
+}
+
+.menu-item:hover {
+    background: var(--color-menubar-bg-menu-item-hover);
+    outline-color: var(--mb-outline-strong);
+    color: var(--color-menubar-text-menu-item-hover);
+}
+
+.menu-item:active {
+    transform: translateY(1px);
+}
+
+.menu-item-selected {
+    background: color-mix(
+        in oklab,
+        var(--color-menubar-bg-menu-item-selected) 95%,
+        transparent
+    );
+    outline-color: var(--mb-outline-strong);
+    //box-shadow:
+    //        inset 0 0 0 1px rgba(255,255,255,.05),
+    //        0 6px 16px rgba(0,0,0,.18);
+}
+
+/* Icon + text + badge */
+.item-icon {
+    font-size: 18px;
+    width: 18px;
+    height: 18px;
+    opacity: 0.96;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+.item-title {
+    font-size: 0.86rem;
+    flex: 1 1 auto;
+}
+
+.text-ellipsis {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* Collapsed (icon-only) refinements */
+.menubar-root.collapsed .iconbar-item-btn {
+    justify-content: center;
+}
+
+.menubar-root.collapsed .menu-group-title {
+    justify-content: center;
+    padding: 10px 0;
+}
+
+/* Responsive hint (optional) */
+@media (max-width: 960px) {
+    :root {
+        --mb-width: 248px;
+    }
+}
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.ts 
b/ui/src/app/core/components/iconbar/iconbar.component.ts
index 7bef05b7b2..c02d09ea20 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.ts
+++ b/ui/src/app/core/components/iconbar/iconbar.component.ts
@@ -22,7 +22,7 @@ import { BaseNavigationComponent } from 
'../base-navigation.component';
 @Component({
     selector: 'sp-iconbar',
     templateUrl: './iconbar.component.html',
-    styleUrls: ['./iconbar.component.scss', '../bars.scss'],
+    styleUrls: ['./iconbar.component.scss'],
     standalone: false,
 })
 export class IconbarComponent
diff --git a/ui/src/app/core/components/streampipes/streampipes.component.html 
b/ui/src/app/core/components/streampipes/streampipes.component.html
index 1b78eef964..b9465e5f01 100644
--- a/ui/src/app/core/components/streampipes/streampipes.component.html
+++ b/ui/src/app/core/components/streampipes/streampipes.component.html
@@ -20,16 +20,39 @@
     [ngClass]="darkMode ? 'dark-mode base-style' : 'light-mode base-style'"
     @fadeSlideInOut
 >
-    <div class="sp-toolbar-outer">
-        <sp-toolbar></sp-toolbar>
-    </div>
-    <div style="display: flex; flex-direction: row; height: calc(100vh - 
40px)">
-        <div style="color: white" class="iconbar">
+    <div class="layout-container">
+        <!-- Left Menubar -->
+        <div class="menubar">
             <sp-iconbar></sp-iconbar>
         </div>
-        <div style="width: 100%; height: 100%; overflow-y: auto" class="base">
-            <sp-breadcrumb></sp-breadcrumb>
-            <router-outlet></router-outlet>
+
+        <!-- Right Section (Toolbar + Main Content) -->
+        <div class="main-section">
+            <div class="sp-toolbar-outer">
+                <sp-toolbar></sp-toolbar>
+            </div>
+
+            <div class="content">
+                <router-outlet></router-outlet>
+            </div>
         </div>
     </div>
 </div>
+
+<!--<div-->
+<!--    [ngClass]="darkMode ? 'dark-mode base-style' : 'light-mode 
base-style'"-->
+<!--    @fadeSlideInOut-->
+<!--&gt;-->
+<!--    <div class="sp-toolbar-outer">-->
+<!--        <sp-toolbar></sp-toolbar>-->
+<!--    </div>-->
+<!--    <div style="display: flex; flex-direction: row; height: calc(100vh - 
40px)">-->
+<!--        <div style="color: white" class="iconbar">-->
+<!--            <sp-iconbar></sp-iconbar>-->
+<!--        </div>-->
+<!--        <div style="width: 100%; height: 100%; overflow-y: auto" 
class="base">-->
+<!--            <sp-breadcrumb></sp-breadcrumb>-->
+<!--            <router-outlet></router-outlet>-->
+<!--        </div>-->
+<!--    </div>-->
+<!--</div>-->
diff --git a/ui/src/app/core/components/streampipes/streampipes.component.scss 
b/ui/src/app/core/components/streampipes/streampipes.component.scss
index 4a8cc83c9f..4f4b41c6f0 100644
--- a/ui/src/app/core/components/streampipes/streampipes.component.scss
+++ b/ui/src/app/core/components/streampipes/streampipes.component.scss
@@ -16,16 +16,62 @@
  *
  */
 
-.iconbar {
-    background: var(--color-navigation-bg);
-    width: var(--iconbar-width);
+.layout-container {
+    display: flex;
+    flex-direction: row;
+    height: 100vh;
 }
 
-.base {
+.menubar {
+    background: var(--color-bg-1);
     color: var(--color-default-text);
-    background: var(--color-bg-outer);
+    display: flex;
+    flex-direction: column;
+    border-right: 1px solid var(--color-bg-3);
+    box-shadow: 0 -4px 0 0 #000;
+}
+
+.menu-header {
+    text-align: center;
+    padding: 10px 0;
+    font-weight: 600;
+    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+.menu-items {
+    flex-grow: 1;
+    display: flex;
+    flex-direction: column;
+    padding-top: 10px;
+}
+
+.menu-item {
+    padding: 10px 20px;
+    cursor: pointer;
+    transition: background 0.2s ease;
+    font-size: 14px;
+}
+
+.menu-item:hover {
+    background: rgba(255, 255, 255, 0.1);
+}
+
+/* Right side layout */
+.main-section {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+    background: var(--color-bg-1);
 }
 
 .sp-toolbar-outer {
-    height: 40px;
+    background: var(--color-toolbar-bg);
+}
+
+.content {
+    flex-grow: 1;
+    overflow-y: auto;
+    background: var(--color-bg-1);
+    color: var(--color-default-text);
 }
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.html 
b/ui/src/app/core/components/toolbar/toolbar.component.html
index d9f404272d..960d5f75b6 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.html
+++ b/ui/src/app/core/components/toolbar/toolbar.component.html
@@ -16,32 +16,10 @@
   ~
   -->
 
-<mat-toolbar class="md-primary md-hue-2 top-nav toolbar-bg">
+<mat-toolbar class="md-primary md-hue-2 toolbar">
     <div class="md-toolbar-tools sp-toolbar">
         <div fxFlex="100" fxLayout fxLayoutAlign="start center">
-            <div
-                class="md-toolbar-tools"
-                style="height: 40px; max-height: 40px"
-                fxFlex
-                fxLayout="row"
-                fxLayoutAlign="start center"
-            >
-                <div
-                    style="
-                        padding: 5px;
-                        border-radius: 0px;
-                        margin-right: 15px;
-                        position: relative;
-                        left: 20px;
-                    "
-                >
-                    <img
-                        alt="icon"
-                        src="assets/img/sp/logo-navigation.png"
-                        style="max-height: 30px; max-width: 250px"
-                    />
-                </div>
-            </div>
+            <sp-breadcrumb></sp-breadcrumb>
             <div
                 fxFlex
                 fxLayout
@@ -106,26 +84,22 @@
                             mat-icon-button
                             fxLayout
                             fxLayoutAlign="center center"
-                            [ngClass]="
+                            [class.sp-navbar-icon-button-selected]="
                                 accountMenuOpen.menuOpen
-                                    ? 'sp-icon-button-no-hover'
-                                    : 'sp-icon-button'
                             "
-                            style="min-width: 0px"
+                            style="min-width: 0"
                             [matMenuTriggerFor]="menu"
                             #accountMenuOpen="matMenuTrigger"
                             matTooltip="User Preferences"
                             matTooltipPosition="below"
                             data-cy="sp-user-preferences"
                         >
-                            <i
-                                [ngClass]="
-                                    accountMenuOpen.menuOpen
-                                        ? 'sp-navbar-icon-selected'
-                                        : 'sp-navbar-icon'
+                            <mat-icon
+                                class="sp-navbar-icon"
+                                [class.sp-navbar-icon-selected]="
+                                    accountMenuOpen
                                 "
-                                class="material-icons"
-                                >account_circle</i
+                                >account_circle</mat-icon
                             >
                         </button>
                     </div>
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.scss 
b/ui/src/app/core/components/toolbar/toolbar.component.scss
index 1e8ec24281..1b2256c490 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.scss
+++ b/ui/src/app/core/components/toolbar/toolbar.component.scss
@@ -24,6 +24,18 @@
     height: 41px;
 }
 
+.sp-navbar-icon-selected {
+    color: var(--color-toolbar-icon-selected);
+}
+
+.sp-navbar-icon {
+    color: var(--color-toolbar-icon);
+}
+
+.sp-navbar-icon:hover {
+    color: var(--color-toolbar-icon-hover);
+}
+
 .current-user {
     color: var(--color-default-text);
     display: block;
@@ -36,9 +48,8 @@
     position: relative;
 }
 
-.toolbar-bg {
-    background: var(--color-navigation-bg);
-    border-bottom: 2px solid var(--color-navigation-divider);
+.toolbar {
+    background: var(--color-bg-1);
     color: var(--color-navigation-text);
 }
 
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.ts 
b/ui/src/app/core/components/toolbar/toolbar.component.ts
index af568ad5c2..249fc23871 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.ts
+++ b/ui/src/app/core/components/toolbar/toolbar.component.ts
@@ -31,7 +31,7 @@ import { LoginService } from 
'../../../login/services/login.service';
 @Component({
     selector: 'sp-toolbar',
     templateUrl: './toolbar.component.html',
-    styleUrls: ['./toolbar.component.scss', '../bars.scss'],
+    styleUrls: ['./toolbar.component.scss'],
     standalone: false,
 })
 export class ToolbarComponent
diff --git a/ui/src/app/core/navigation.backup 
b/ui/src/app/core/navigation.backup
new file mode 100644
index 0000000000..0888e86b31
--- /dev/null
+++ b/ui/src/app/core/navigation.backup
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+import { NavigationEnd, Router } from '@angular/router';
+import { PageName } from '../../_enums/page-name.enum';
+import { AuthService } from '../../services/auth.service';
+import { CurrentUserService } from '@streampipes/shared-ui';
+import { AppConstants } from '../../services/app.constants';
+import { UserPrivilege } from '../../_enums/user-privilege.enum';
+import { inject, signal } from '@angular/core';
+
+export interface MenuItem {
+  link: string;
+  title: string;
+  icon: string;
+  pageNames: any[];
+  privileges: any[];
+  visible?: boolean;
+}
+
+export interface MenuGroup {
+  title: string;
+  items: MenuItem[];
+  collapsed?: boolean;
+}
+
+export interface MenuCategory {
+  id: string;
+  title: string;
+  collapsed: boolean;
+}
+
+export abstract class BaseNavigationComponent {
+
+  activePageName: string;
+  authenticated = true;
+  topItems: MenuItem[] = [];
+  menuGroups: MenuGroup[] = [];
+  notificationsVisible = false;
+
+  public categories: MenuCategory[] = [
+    {
+      id: 'top',
+      title: 'top',
+      collapsed: false
+    },
+    {
+      id: 'analytics',
+      title: 'Analytics',
+      collapsed: false
+    },
+    {
+      id: 'visualization',
+      title: 'Visualization',
+      collapsed: false
+    },
+    {
+      id: 'management',
+      title: 'Management',
+      collapsed: true
+    },
+  ]
+
+  public menu = [
+    {
+        link: '',
+        title: 'Home',
+        icon: 'home',
+        pageNames: [PageName.HOME],
+        privileges: [],
+        visible: false,
+        category: 'top'
+    },
+    {
+        link: 'pipelines',
+        title: 'Pipelines',
+        icon: 'play_arrow',
+        pageNames: [PageName.PIPELINE_OVERVIEW],
+        privileges: [UserPrivilege.PRIVILEGE_READ_PIPELINE, 
UserPrivilege.PRIVILEGE_WRITE_PIPELINE],
+        visible: false,
+        category: 'analytics'
+    },
+    {
+        link: 'connect',
+        title: 'Connect',
+        icon: 'power',
+        pageNames: [PageName.CONNECT],
+        privileges: [UserPrivilege.PRIVILEGE_READ_ADAPTER, 
UserPrivilege.PRIVILEGE_WRITE_ADAPTER],
+        visible: false,
+        category: 'management'
+    },
+    {
+        link: 'dashboard',
+        title: 'Dashboard',
+        icon: 'dashboard',
+        pageNames: [PageName.DASHBOARD],
+        privileges: [UserPrivilege.PRIVILEGE_READ_DASHBOARD, 
UserPrivilege.PRIVILEGE_WRITE_DASHBOARD],
+        visible: false,
+        category: 'visualization'
+    },
+    {
+        link: 'dataexplorer',
+        title: 'Data Explorer',
+        icon: 'query_stats',
+        pageNames: [PageName.DATA_EXPLORER],
+        privileges: [UserPrivilege.PRIVILEGE_READ_DATA_EXPLORER_VIEW, 
UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW],
+        visible: false,
+        category: 'visualization'
+    },
+    {
+        link: 'assets',
+        title: 'Asset Management',
+        icon: 'precision_manufacturing',
+        pageNames: [PageName.ASSETS],
+        privileges: [UserPrivilege.PRIVILEGE_READ_ASSETS, 
UserPrivilege.PRIVILEGE_WRITE_ASSETS],
+        visible: false,
+        category: 'management'
+    },
+    {
+        link: 'configuration',
+        title: 'Configuration',
+        icon: 'settings',
+        pageNames: [PageName.SETTINGS],
+        privileges: [UserPrivilege.PRIVILEGE_WRITE_ASSETS, 
UserPrivilege.PRIVILEGE_WRITE_LABELS, UserPrivilege.PRIVILEGE_WRITE_FILES],
+        visible: false,
+        category: 'management'
+    },
+  ];
+
+
+
+
+   protected authService = inject(AuthService);
+   protected currentUserService = inject(CurrentUserService);
+   protected router = inject(Router);
+   protected appConstants = inject(AppConstants);
+
+    onInit() {
+      this.currentUserService.user$.subscribe(user => {
+        this.menu.forEach(m => m.visible = 
this.isNavItemVisible(m.privileges));
+        const menuGroups = this.categories.map(category => {
+          return {
+            title: category.title,
+            collapsed: category.collapsed,
+            items: this.menu.filter(m => m.category === category.id && 
m.visible)
+          }
+        }).filter(m => m.items.length > 0);
+
+        this.topItems = menuGroups.find(m => m.title === 'top')?.items || [];
+        this.menuGroups = menuGroups.filter(m => m.title !== 'top');
+        this.notificationsVisible = this.isNavItemVisible([
+        UserPrivilege.PRIVILEGE_READ_PIPELINE,
+        UserPrivilege.PRIVILEGE_WRITE_PIPELINE
+        ]);
+      });
+      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.split('/')[1];
+          this.activePageName = this.getPageTitle(this.activePage);
+        }
+      });
+    }
+
+    getActivePage() {
+      return this.activePage;
+    }
+
+    getPageTitle(path) {
+      let currentTitle = this.appConstants.APP_NAME;
+      this.menu.forEach(m => {
+        if (m.link === path) {
+          currentTitle = m.title;
+        }
+      });
+      if (path === 'pipeline-details') {
+        currentTitle = 'Pipeline Details';
+      }
+      return currentTitle;
+    }
+
+    go(path, payload?) {
+      if (payload === undefined) {
+        this.router.navigateByUrl(path);
+        this.activePage = path;
+      } else {
+        this.router.navigateByUrl(path, payload);
+        this.activePage = path;
+      }
+      this.activePageName = this.getPageTitle(this.activePage);
+    }
+
+    public isNavItemVisible(privileges: string[]): boolean {
+      return this.authService.isAnyAccessGranted(privileges);
+    }
+
+  activePage: string = 'home';
+  isCollapsed = signal<boolean>(this.loadCollapsed());
+
+  // Collapse/expand entire menubar
+  toggleMenubar(): void {
+    const next = !this.isCollapsed();
+    this.isCollapsed.set(next);
+    localStorage.setItem('sp-menubar-collapsed', JSON.stringify(next));
+  }
+
+  // Collapse/expand a single group
+  toggleGroup(group: MenuGroup): void {
+    group.collapsed = !group.collapsed;
+  }
+
+  private loadCollapsed(): boolean {
+    try {
+      const v = localStorage.getItem('sp-menubar-collapsed');
+      return v ? JSON.parse(v) : false;
+    } catch {
+      return false;
+    }
+  }
+
+}
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview.component.html 
b/ui/src/app/dashboard/components/overview/dashboard-overview.component.html
index 843bdd968b..01afecf4f5 100644
--- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.html
+++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.html
@@ -16,37 +16,30 @@
   ~
   -->
 
-<sp-asset-browser
-    filteredAssetLinkType="dashboard"
-    allResourcesAlias="Dashboards"
-    [resourceCount]="resourceCount"
-    (filterIdsEmitter)="applyDashboardFilters($event)"
->
-    <sp-basic-view [showBackLink]="false" [padding]="true">
-        <div
-            nav
-            fxFlex="100"
-            fxLayoutAlign="start center"
-            fxLayout="row"
-            class="pl-10"
+<sp-basic-view [showBackLink]="false" [padding]="true">
+    <div
+        nav
+        fxFlex="100"
+        fxLayoutAlign="start center"
+        fxLayout="row"
+        class="pl-10"
+    >
+        <button
+            mat-button
+            mat-flat-button
+            color="accent"
+            data-cy="open-new-dashboard-dialog"
+            (click)="openNewDashboardDialog()"
+            class="mr-10"
+            *ngIf="hasDashboardWritePrivileges"
         >
-            <button
-                mat-button
-                mat-flat-button
-                color="accent"
-                data-cy="open-new-dashboard-dialog"
-                (click)="openNewDashboardDialog()"
-                class="mr-10"
-                *ngIf="hasDashboardWritePrivileges"
-            >
-                <i class="material-icons">add</i>
-                <span>{{ 'New dashboard' | translate }}</span>
-            </button>
-        </div>
-        <div fxFlex="100" fxLayout="column">
-            <sp-dashboard-overview-table
-                (resourceCountEmitter)="resourceCount = $event"
-            ></sp-dashboard-overview-table>
-        </div>
-    </sp-basic-view>
-</sp-asset-browser>
+            <i class="material-icons">add</i>
+            <span>{{ 'New dashboard' | translate }}</span>
+        </button>
+    </div>
+    <div fxFlex="100" fxLayout="column">
+        <sp-dashboard-overview-table
+            (resourceCountEmitter)="resourceCount = $event"
+        ></sp-dashboard-overview-table>
+    </div>
+</sp-basic-view>
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.html
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.html
index 26d9e355d8..ff21cb9392 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.html
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.html
@@ -16,37 +16,30 @@
   ~
   -->
 
-<sp-asset-browser
-    filteredAssetLinkType="chart"
-    [allResourcesAlias]="'Charts' | translate"
-    [resourceCount]="resourceCount"
-    (filterIdsEmitter)="applyChartFilters($event)"
->
-    <sp-basic-view [showBackLink]="false" [padding]="true">
-        <div
-            nav
-            fxFlex="100"
-            fxLayoutAlign="start center"
-            fxLayout="row"
-            class="pl-10"
+<sp-basic-view [showBackLink]="false" [padding]="true">
+    <div
+        nav
+        fxFlex="100"
+        fxLayoutAlign="start center"
+        fxLayout="row"
+        class="pl-10"
+    >
+        <button
+            mat-button
+            mat-flat-button
+            color="accent"
+            data-cy="open-new-data-view"
+            (click)="createNewDataView()"
+            class="mr-10"
+            *ngIf="hasDataExplorerWritePrivileges"
         >
-            <button
-                mat-button
-                mat-flat-button
-                color="accent"
-                data-cy="open-new-data-view"
-                (click)="createNewDataView()"
-                class="mr-10"
-                *ngIf="hasDataExplorerWritePrivileges"
-            >
-                <i class="material-icons">add</i>
-                <span>{{ 'New chart' | translate }}</span>
-            </button>
-        </div>
-        <div fxFlex="100" fxLayout="column">
-            <sp-data-explorer-overview-table
-                (resourceCountEmitter)="resourceCount = $event"
-            ></sp-data-explorer-overview-table>
-        </div>
-    </sp-basic-view>
-</sp-asset-browser>
+            <i class="material-icons">add</i>
+            <span>{{ 'New chart' | translate }}</span>
+        </button>
+    </div>
+    <div fxFlex="100" fxLayout="column">
+        <sp-data-explorer-overview-table
+            (resourceCountEmitter)="resourceCount = $event"
+        ></sp-data-explorer-overview-table>
+    </div>
+</sp-basic-view>
diff --git a/ui/src/app/pipelines/pipelines.component.html 
b/ui/src/app/pipelines/pipelines.component.html
index 150c514dbc..5ec8323d18 100644
--- a/ui/src/app/pipelines/pipelines.component.html
+++ b/ui/src/app/pipelines/pipelines.component.html
@@ -16,106 +16,95 @@
   ~
   -->
 
-<sp-asset-browser
-    filteredAssetLinkType="pipeline"
-    allResourcesAlias="Pipelines"
-    [resourceCount]="pipelines.length"
-    (filterIdsEmitter)="applyPipelineFilters($event)"
->
-    <sp-basic-view [showBackLink]="false" [padding]="true">
-        <div
-            nav
-            fxFlex="100"
-            fxLayoutAlign="start center"
-            fxLayout="row"
-            fxLayoutGap="10px"
-            class="pl-10"
+<sp-basic-view [showBackLink]="false" [padding]="true">
+    <div
+        nav
+        fxFlex="100"
+        fxLayoutAlign="start center"
+        fxLayout="row"
+        fxLayoutGap="10px"
+        class="pl-10"
+    >
+        <button
+            mat-button
+            mat-flat-button
+            color="accent"
+            *ngIf="hasPipelineWritePrivileges"
+            (click)="navigateToPipelineEditor()"
+            data-cy="pipelines-navigate-to-editor"
         >
-            <button
-                mat-button
-                mat-flat-button
-                color="accent"
-                *ngIf="hasPipelineWritePrivileges"
-                (click)="navigateToPipelineEditor()"
-                data-cy="pipelines-navigate-to-editor"
-            >
-                <i class="material-icons">add</i>&nbsp;{{
-                    'New Pipeline' | translate
-                }}
-            </button>
-            <button
-                mat-flat-button
-                class="mat-basic"
-                (click)="startAllPipelines(true)"
-                [disabled]="checkCurrentSelectionStatus(false)"
-                *ngIf="hasPipelineWritePrivileges"
-            >
-                <mat-icon>play_arrow</mat-icon>
-                <span>{{ 'Start All Pipelines' | translate }}</span>
-            </button>
-            <button
-                mat-flat-button
-                class="mat-basic"
-                (click)="startAllPipelines(false)"
-                [disabled]="checkCurrentSelectionStatus(true)"
-                *ngIf="hasPipelineWritePrivileges"
-            >
-                <mat-icon>stop</mat-icon>
-                <span>{{ 'Stop all pipelines' | translate }}</span>
-            </button>
-            <span fxFlex></span>
-            <button
-                mat-icon-button
-                color="accent"
-                (click)="startPipelineTour()"
-                [matTooltip]="'Tutorial'"
-                [disabled]="tutorialActive"
-            >
-                <i class="material-icons"> school </i>
-            </button>
-            <button
-                mat-icon-button
-                color="accent"
-                matTooltip="Refresh pipelines"
-                matTooltipPosition="above"
-                (click)="getPipelines()"
-            >
-                <i class="material-icons"> refresh </i>
-            </button>
-        </div>
-        <div fxFlex="100" fxLayout="column">
-            <div fxLayout="column">
+            <i class="material-icons">add</i>&nbsp;{{
+                'New Pipeline' | translate
+            }}
+        </button>
+        <button
+            mat-flat-button
+            class="mat-basic"
+            (click)="startAllPipelines(true)"
+            [disabled]="checkCurrentSelectionStatus(false)"
+            *ngIf="hasPipelineWritePrivileges"
+        >
+            <mat-icon>play_arrow</mat-icon>
+            <span>{{ 'Start All Pipelines' | translate }}</span>
+        </button>
+        <button
+            mat-flat-button
+            class="mat-basic"
+            (click)="startAllPipelines(false)"
+            [disabled]="checkCurrentSelectionStatus(true)"
+            *ngIf="hasPipelineWritePrivileges"
+        >
+            <mat-icon>stop</mat-icon>
+            <span>{{ 'Stop all pipelines' | translate }}</span>
+        </button>
+        <span fxFlex></span>
+        <button
+            mat-icon-button
+            color="accent"
+            (click)="startPipelineTour()"
+            [matTooltip]="'Tutorial'"
+            [disabled]="tutorialActive"
+        >
+            <i class="material-icons"> school </i>
+        </button>
+        <button
+            mat-icon-button
+            color="accent"
+            matTooltip="Refresh pipelines"
+            matTooltipPosition="above"
+            (click)="getPipelines()"
+        >
+            <i class="material-icons"> refresh </i>
+        </button>
+    </div>
+    <div fxFlex="100" fxLayout="column">
+        <div fxLayout="column">
+            <sp-basic-header-title-component
+                title="Pipelines"
+            ></sp-basic-header-title-component>
+            <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
+                <div fxFlex="100">
+                    <sp-pipeline-overview
+                        [pipelines]="filteredPipelines"
+                        (refreshPipelinesEmitter)="getPipelines()"
+                        *ngIf="pipelinesReady"
+                    ></sp-pipeline-overview>
+                </div>
+            </div>
+            <div fxFlex="100" fxLayout="column" style="margin-top: 20px">
                 <sp-basic-header-title-component
-                    title="Pipelines"
+                    title="Functions"
                 ></sp-basic-header-title-component>
                 <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
                     <div fxFlex="100">
-                        <sp-pipeline-overview
-                            [pipelines]="filteredPipelines"
-                            (refreshPipelinesEmitter)="getPipelines()"
-                            *ngIf="pipelinesReady"
-                        ></sp-pipeline-overview>
-                    </div>
-                </div>
-                <div fxFlex="100" fxLayout="column" style="margin-top: 20px">
-                    <sp-basic-header-title-component
-                        title="Functions"
-                    ></sp-basic-header-title-component>
-                    <div
-                        fxFlex="100"
-                        fxLayout="row"
-                        fxLayoutAlign="center start"
-                    >
-                        <div fxFlex="100">
-                            <sp-functions-overview
-                                [functions]="functions"
-                                *ngIf="functionsReady"
-                            >
-                            </sp-functions-overview>
-                        </div>
+                        <sp-functions-overview
+                            [functions]="functions"
+                            *ngIf="functionsReady"
+                        >
+                        </sp-functions-overview>
                     </div>
                 </div>
             </div>
         </div>
-    </sp-basic-view>
-</sp-asset-browser>
+    </div>
+</sp-basic-view>
diff --git a/ui/src/scss/sp/layout.scss b/ui/src/scss/sp/layout.scss
index 6b736888c5..0a7ae5aba8 100644
--- a/ui/src/scss/sp/layout.scss
+++ b/ui/src/scss/sp/layout.scss
@@ -139,8 +139,8 @@
 .page-container-nav {
     line-height: 24px;
     height: 44px;
-    border-bottom: 1px solid var(--color-bg-3);
-    background: var(--color-bg-main-panel-header);
+    //border-bottom: 1px solid var(--color-bg-3);
+    //background: var(--color-bg-main-panel-header);
 }
 
 .text-center {
diff --git a/ui/src/scss/sp/main.scss b/ui/src/scss/sp/main.scss
index 474e00fce5..2b6de54f6c 100644
--- a/ui/src/scss/sp/main.scss
+++ b/ui/src/scss/sp/main.scss
@@ -57,11 +57,6 @@ pre.version {
     border: 0;
 }
 
-.md-toolbar-tools {
-    width: 100%;
-    align-items: center;
-}
-
 code[class*='language-'],
 pre[class*='language-'] {
     white-space: pre-wrap;
@@ -152,7 +147,7 @@ md-content {
 
 .page-container {
     margin: 10px;
-    border: 1px solid var(--color-bg-3);
+    //border: 1px solid var(--color-bg-3);
     min-height: calc(100% - 60px);
     background: var(--color-bg-page-container);
 }
@@ -196,11 +191,6 @@ md-content {
     border-bottom-right-radius: 20em;
 }
 
-.top-nav {
-    height: 40px !important;
-    border-bottom: 0px solid var(--color-primary);
-}
-
 .angular-google-map-container {
     height: 400px;
 }


Reply via email to