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

riemer pushed a commit to branch 3156-add-asset-browser-to-overview-pages
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit 0dfaec4a69c4afcfb8bbe18ec8961e06c6c03222
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Aug 19 22:50:25 2024 +0200

    feat(#3156): Add asset browser to adapters and pipelines
---
 .../components/sp-label/sp-label.component.scss    |   4 +-
 .../asset-details/asset-details.component.ts       |   3 +
 .../asset-overview/asset-overview.component.ts     |   5 +
 .../existing-adapters.component.html               | 500 +++++++++++----------
 .../existing-adapters.component.ts                 |  24 +-
 .../asset-browser-hierarchy.component.html         |  73 +++
 .../asset-browser-hierarchy.component.scss}        |  33 +-
 .../asset-browser-hierarchy.component.ts           |  98 ++++
 .../asset-browser-node-info.component.html         |  33 ++
 .../asset-browser-node-info.component.scss}        |  21 +-
 .../asset-browser-node-info.component.ts           |  63 +++
 .../asset-browser-node.component.html              |  64 +++
 .../asset-browser-node.component.scss}             |  43 +-
 .../asset-browser-node.component.ts                |  98 ++++
 .../asset-browser-filter-labels.component.html     |  79 ++++
 .../asset-browser-filter-labels.component.ts}      |  31 +-
 .../asset-browser-filter-outer.component.html      |  81 ++++
 .../asset-browser-filter-outer.component.ts        |  23 +
 .../asset-browser-filter-sites.component.html      |  45 ++
 .../asset-browser-filter-sites.component.ts}       |  39 +-
 .../asset-browser-filter-type.component.html       |  45 ++
 .../asset-browser-filter-type.component.ts         |  56 +++
 .../asset-browser-filter.component.html            |  51 +++
 .../asset-browser-filter.component.scss}           |  54 ++-
 .../asset-browser-filter.component.ts              |  69 +++
 .../asset-browser-toolbar.component.html           |  52 +++
 .../asset-browser-toolbar.component.ts}            |  41 +-
 .../asset-browser/asset-browser.component.html     |  77 ++++
 .../asset-browser/asset-browser.component.scss}    |  21 +-
 .../asset-browser/asset-browser.component.ts       | 110 +++++
 .../core-ui/asset-browser/asset-browser.model.ts}  |  29 +-
 .../core-ui/asset-browser/asset-browser.service.ts | 190 ++++++++
 ui/src/app/core-ui/core-ui.module.ts               |  21 +
 ui/src/app/pipelines/pipelines.component.html      | 170 +++----
 ui/src/app/pipelines/pipelines.component.ts        |  24 +-
 35 files changed, 1929 insertions(+), 441 deletions(-)

diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
index 778b5b97de..a1ac9f6d5d 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
@@ -26,6 +26,6 @@
 }
 
 .small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+    font-size: 9pt;
+    padding: 0 8px;
 }
diff --git 
a/ui/src/app/assets/components/asset-details/asset-details.component.ts 
b/ui/src/app/assets/components/asset-details/asset-details.component.ts
index cbb53dc398..5b7028ef92 100644
--- a/ui/src/app/assets/components/asset-details/asset-details.component.ts
+++ b/ui/src/app/assets/components/asset-details/asset-details.component.ts
@@ -28,6 +28,7 @@ import {
 } from '@streampipes/platform-services';
 import { SpAssetRoutes } from '../../assets.routes';
 import { zip } from 'rxjs';
+import { SpAssetBrowserService } from 
'../../../core-ui/asset-browser/asset-browser.service';
 
 @Component({
     selector: 'sp-asset-details',
@@ -48,6 +49,7 @@ export class SpAssetDetailsComponent implements OnInit {
     constructor(
         private breadcrumbService: SpBreadcrumbService,
         private genericStorageService: GenericStorageService,
+        private assetBrowserService: SpAssetBrowserService,
         private route: ActivatedRoute,
     ) {}
 
@@ -91,6 +93,7 @@ export class SpAssetDetailsComponent implements OnInit {
         this.genericStorageService
             .updateDocument(AssetConstants.ASSET_APP_DOC_NAME, this.asset)
             .subscribe(res => {
+                this.assetBrowserService.loadAssetData();
                 this.loadResources();
                 this.editMode = false;
             });
diff --git 
a/ui/src/app/assets/components/asset-overview/asset-overview.component.ts 
b/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
index 956c37fb0a..219c0551e2 100644
--- a/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
+++ b/ui/src/app/assets/components/asset-overview/asset-overview.component.ts
@@ -36,6 +36,7 @@ import { DataExportService } from 
'../../../configuration/export/data-export.ser
 import { mergeMap } from 'rxjs/operators';
 import { saveAs } from 'file-saver';
 import { IdGeneratorService } from 
'../../../core-services/id-generator/id-generator.service';
+import { SpAssetBrowserService } from 
'../../../core-ui/asset-browser/asset-browser.service';
 
 @Component({
     selector: 'sp-asset-overview',
@@ -57,6 +58,7 @@ export class SpAssetOverviewComponent implements OnInit {
         private router: Router,
         private dataExportService: DataExportService,
         private idGeneratorService: IdGeneratorService,
+        private assetBrowserService: SpAssetBrowserService,
     ) {}
 
     ngOnInit(): void {
@@ -105,6 +107,7 @@ export class SpAssetOverviewComponent implements OnInit {
 
         dialogRef.afterClosed().subscribe(() => {
             this.loadAssets();
+            this.assetBrowserService.loadAssetData();
         });
     }
 
@@ -118,6 +121,7 @@ export class SpAssetOverviewComponent implements OnInit {
         dialogRef.afterClosed().subscribe(reload => {
             if (reload) {
                 this.loadAssets();
+                this.assetBrowserService.loadAssetData();
             }
         });
     }
@@ -141,6 +145,7 @@ export class SpAssetOverviewComponent implements OnInit {
             )
             .subscribe(result => {
                 this.loadAssets();
+                this.assetBrowserService.loadAssetData();
             });
     }
 
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 d2f654bb3e..916ac6240c 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
@@ -15,272 +15,284 @@
   ~ limitations under the License.
   ~
   -->
-<sp-basic-view [showBackLink]="false" [padding]="true">
-    <div
-        nav
-        fxFlex="100"
-        fxLayoutAlign="start center"
-        fxLayout="row"
-        class="pl-10"
-    >
-        <button
-            mat-raised-button
-            color="accent"
-            data-cy="connect-create-new-adapter-button"
-            (click)="createNewAdapter()"
-        >
-            <i class="material-icons">add</i>&nbsp;New adapter
-        </button>
-        <button
-            class="mr-10"
-            mat-button
-            color="accent"
-            data-cy="start-all-adapters-btn"
-            [disabled]="checkCurrentSelectionStatus(false)"
-            (click)="startAllAdapters(true)"
-        >
-            <mat-icon>play_arrow</mat-icon><span>Start all adapters</span>
-        </button>
-        <button
-            mat-button
-            color="accent"
-            data-cy="stop-all-adapters-btn"
-            [disabled]="checkCurrentSelectionStatus(true)"
-            (click)="startAllAdapters(false)"
+
+<sp-asset-browser
+    filteredAssetLinkType="adapter"
+    [resourceCount]="existingAdapters.length"
+    (filterIdsEmitter)="applyAdapterFilters($event)"
+>
+    <sp-basic-view [showBackLink]="false" [padding]="true">
+        <div
+            nav
+            fxFlex="100"
+            fxLayoutAlign="start center"
+            fxLayout="row"
+            class="pl-10"
         >
-            <mat-icon>stop</mat-icon>
-            <span>Stop all adapters</span>
-        </button>
-        <div fxFlex fxLayout="row" fxLayoutAlign="end center">
-            <sp-connect-filter-toolbar
-                class="filter-bar-margin"
-                (filterChangedEmitter)="applyFilter($event)"
+            <button
+                mat-raised-button
+                color="accent"
+                data-cy="connect-create-new-adapter-button"
+                (click)="createNewAdapter()"
+            >
+                <i class="material-icons">add</i>&nbsp;New adapter
+            </button>
+            <button
+                class="mr-10"
+                mat-button
+                color="accent"
+                data-cy="start-all-adapters-btn"
+                [disabled]="checkCurrentSelectionStatus(false)"
+                (click)="startAllAdapters(true)"
             >
-            </sp-connect-filter-toolbar>
-            <div
-                fxFlex="100"
-                fxLayout="row"
-                fxLayoutAlign="end center"
-                class="page-container-nav"
+                <mat-icon>play_arrow</mat-icon>
+                <span>Start all adapters</span>
+            </button>
+            <button
+                mat-button
+                color="accent"
+                data-cy="stop-all-adapters-btn"
+                [disabled]="checkCurrentSelectionStatus(true)"
+                (click)="startAllAdapters(false)"
             >
+                <mat-icon>stop</mat-icon>
+                <span>Stop all adapters</span>
+            </button>
+            <div fxFlex fxLayout="row" fxLayoutAlign="end center">
+                <sp-connect-filter-toolbar
+                    class="filter-bar-margin"
+                    (filterChangedEmitter)="applyFilter($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>
                 <button
                     mat-icon-button
+                    matTooltip="Refresh adapters"
+                    matTooltipPosition="below"
                     color="accent"
-                    id="startAdapterTutorial3"
-                    (click)="startAdapterTutorial()"
-                    matTooltip="Tutorial: Generic Adapter"
-                    [disabled]="tutorialActive"
+                    (click)="getAdaptersRunning()"
                 >
-                    <mat-icon>school</mat-icon>
+                    <i class="material-icons"> refresh </i>
                 </button>
             </div>
-            <button
-                mat-icon-button
-                matTooltip="Refresh adapters"
-                matTooltipPosition="below"
-                color="accent"
-                (click)="getAdaptersRunning()"
-            >
-                <i class="material-icons"> refresh </i>
-            </button>
         </div>
-    </div>
-    <div fxFlex="100" fxLayout="column">
-        <sp-basic-header-title-component
-            title="Adapters"
-        ></sp-basic-header-title-component>
-        <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
-            <sp-table
-                fxFlex="90"
-                [columns]="displayedColumns"
-                [dataSource]="dataSource"
-                data-cy="all-adapters-table"
-                matSort
-            >
-                <ng-container matColumnDef="status">
-                    <th mat-header-cell mat-sort-header *matHeaderCellDef>
-                        Status
-                    </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"
-                    >
-                        <button
-                            color="accent"
-                            mat-icon-button
-                            matTooltip="Start adapter"
-                            matTooltipPosition="above"
-                            data-cy="start-adapter"
-                            (click)="startAdapter(adapter)"
-                            *ngIf="!adapter.running"
-                        >
-                            <i class="material-icons">play_arrow</i>
-                        </button>
-                        <button
-                            color="accent"
-                            mat-icon-button
-                            matTooltip="Stop adapter"
-                            matTooltipPosition="above"
-                            data-cy="stop-adapter"
-                            (click)="stopAdapter(adapter)"
-                            *ngIf="adapter.running"
-                        >
-                            <i class="material-icons">stop</i>
-                        </button>
-                    </td>
-                </ng-container>
-
-                <ng-container matColumnDef="name">
-                    <th mat-header-cell mat-sort-header *matHeaderCellDef>
-                        Name
-                    </th>
-                    <td mat-cell *matCellDef="let adapter">
-                        <div>
-                            <b
-                                style="margin-bottom: 0"
-                                data-cy="adapter-name"
-                                >{{ adapter.name }}</b
+        <div fxFlex="100" fxLayout="column">
+            <sp-basic-header-title-component
+                title="Adapters"
+            ></sp-basic-header-title-component>
+            <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
+                <sp-table
+                    fxFlex="90"
+                    [columns]="displayedColumns"
+                    [dataSource]="dataSource"
+                    data-cy="all-adapters-table"
+                    matSort
+                >
+                    <ng-container matColumnDef="status">
+                        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+                            Status
+                        </th>
+                        <td mat-cell *matCellDef="let adapter">
+                            <sp-adapter-status-light
+                                [adapterRunning]="adapter.running"
                             >
-                        </div>
-                        <span>{{
-                            adapter.description !== ''
-                                ? adapter.description
-                                : '-'
-                        }}</span>
-                    </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</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
-                    </th>
-                    <td mat-cell *matCellDef="let adapter">
-                        <h5 class="monitoring-info">
-                            {{
-                                adapterMetrics[adapter.elementId]
-                                    ? adapterMetrics[adapter.elementId]
-                                          .messagesOut.counter
-                                    : 0
-                            }}
-                        </h5>
-                    </td>
-                </ng-container>
-
-                <ng-container matColumnDef="lastMessage">
-                    <th mat-header-cell *matHeaderCellDef>Last message</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-container matColumnDef="action">
-                    <th mat-header-cell *matHeaderCellDef></th>
-                    <td mat-cell *matCellDef="let adapter">
-                        <div fxLayout="row" fxLayoutAlign="end center">
+                            </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"
+                        >
                             <button
                                 color="accent"
                                 mat-icon-button
-                                matTooltip="Show details"
+                                matTooltip="Start adapter"
                                 matTooltipPosition="above"
-                                data-cy="details-adapter"
-                                
(click)="navigateToDetailsOverviewPage(adapter)"
+                                data-cy="start-adapter"
+                                (click)="startAdapter(adapter)"
+                                *ngIf="!adapter.running"
                             >
-                                <i class="material-icons">search</i>
+                                <i class="material-icons">play_arrow</i>
                             </button>
                             <button
                                 color="accent"
                                 mat-icon-button
-                                matTooltip="Show info"
+                                matTooltip="Stop adapter"
                                 matTooltipPosition="above"
-                                data-cy="info-adapter"
-                                (click)="openHelpDialog(adapter)"
+                                data-cy="stop-adapter"
+                                (click)="stopAdapter(adapter)"
+                                *ngIf="adapter.running"
                             >
-                                <i class="material-icons">help_outline</i>
+                                <i class="material-icons">stop</i>
                             </button>
+                        </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"
-                                *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>
+                    <ng-container matColumnDef="name">
+                        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+                            Name
+                        </th>
+                        <td mat-cell *matCellDef="let adapter">
+                            <div>
+                                <b
+                                    style="margin-bottom: 0"
+                                    data-cy="adapter-name"
+                                    >{{ adapter.name }}</b
+                                >
+                            </div>
+                            <span>{{
+                                adapter.description !== ''
+                                    ? adapter.description
+                                    : '-'
+                            }}</span>
+                        </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</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
+                        </th>
+                        <td mat-cell *matCellDef="let adapter">
+                            <h5 class="monitoring-info">
+                                {{
+                                    adapterMetrics[adapter.elementId]
+                                        ? adapterMetrics[adapter.elementId]
+                                              .messagesOut.counter
+                                        : 0
+                                }}
+                            </h5>
+                        </td>
+                    </ng-container>
+
+                    <ng-container matColumnDef="lastMessage">
+                        <th mat-header-cell *matHeaderCellDef>Last message</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-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>
+                                <button
+                                    color="accent"
+                                    mat-icon-button
+                                    matTooltip="Show info"
+                                    matTooltipPosition="above"
+                                    data-cy="info-adapter"
+                                    (click)="openHelpDialog(adapter)"
+                                >
+                                    <i class="material-icons">help_outline</i>
+                                </button>
+
+                                <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"
+                                    *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>
         </div>
-    </div>
-</sp-basic-view>
+    </sp-basic-view>
+</sp-asset-browser>
diff --git 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
index fdf0c5986f..feb5cf6ab7 100644
--- 
a/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
+++ 
b/ui/src/app/connect/components/existing-adapters/existing-adapters.component.ts
@@ -271,11 +271,7 @@ export class ExistingAdaptersComponent implements OnInit, 
OnDestroy {
         this.adapterService.getAdapters().subscribe(adapters => {
             this.existingAdapters = adapters;
             this.existingAdapters.sort((a, b) => a.name.localeCompare(b.name));
-            this.filteredAdapters = this.adapterFilter.transform(
-                this.existingAdapters,
-                this.currentFilter,
-            );
-            this.dataSource.data = this.filteredAdapters;
+            this.applyAdapterFilters();
             this.getMonitoringInfos(adapters);
             setTimeout(() => {
                 this.dataSource.sort = this.sort;
@@ -283,6 +279,19 @@ export class ExistingAdaptersComponent implements OnInit, 
OnDestroy {
         });
     }
 
+    applyAdapterFilters(elementIds: Set<string> = new Set<string>()): void {
+        this.filteredAdapters = this.adapterFilter
+            .transform(this.existingAdapters, this.currentFilter)
+            .filter(a => {
+                if (elementIds.size === 0) {
+                    return true;
+                } else {
+                    return elementIds.has(a.elementId);
+                }
+            });
+        this.dataSource.data = this.filteredAdapters;
+    }
+
     startAdapterTutorial() {
         this.shepherdService.startAdapterTour();
     }
@@ -296,10 +305,7 @@ export class ExistingAdaptersComponent implements OnInit, 
OnDestroy {
     applyFilter(filter: AdapterFilterSettingsModel) {
         this.currentFilter = filter;
         if (this.dataSource) {
-            this.dataSource.data = this.adapterFilter.transform(
-                this.filteredAdapters,
-                this.currentFilter,
-            );
+            this.applyAdapterFilters();
         }
     }
 
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.html
new file mode 100644
index 0000000000..7b3735f8c2
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.html
@@ -0,0 +1,73 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="column" *ngIf="selectedAsset">
+    <mat-tree
+        [dataSource]="dataSource"
+        [treeControl]="treeControl"
+        class="sp-tree"
+        #tree
+    >
+        <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
+            <sp-asset-browser-node
+                class="w-100"
+                [node]="node"
+                [assetBrowserData]="assetBrowserData"
+                [assetSelectionMode]="assetSelectionMode"
+                [filteredAssetLinkType]="filteredAssetLinkType"
+                [resourceCount]="resourceCount"
+                [selectedAsset]="selectedAsset"
+                (selectedNodeEmitter)="selectNode($event)"
+            >
+            </sp-asset-browser-node>
+        </mat-tree-node>
+
+        <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
+            <div class="mat-tree-node">
+                <button
+                    mat-icon-button
+                    matTreeNodeToggle
+                    [attr.data-cy]="'button-' + node.nodeName"
+                    [attr.aria-label]="'Toggle ' + node.nodeName"
+                >
+                    <mat-icon class="mat-icon-rtl-mirror">
+                        {{
+                            treeControl.isExpanded(node)
+                                ? 'expand_more'
+                                : 'chevron_right'
+                        }}
+                    </mat-icon>
+                </button>
+                <sp-asset-browser-node
+                    fxFlex="100"
+                    [node]="node"
+                    [assetBrowserData]="assetBrowserData"
+                    [assetSelectionMode]="assetSelectionMode"
+                    [filteredAssetLinkType]="filteredAssetLinkType"
+                    [resourceCount]="resourceCount"
+                    [selectedAsset]="selectedAsset"
+                    (selectedNodeEmitter)="selectNode($event)"
+                >
+                </sp-asset-browser-node>
+            </div>
+            <div *ngIf="treeControl.isExpanded(node)" role="group">
+                <ng-container matTreeNodeOutlet></ng-container>
+            </div>
+        </mat-nested-tree-node>
+    </mat-tree>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.scss
similarity index 67%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.scss
index 778b5b97de..ef8b945b55 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.scss
@@ -16,16 +16,29 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
+.sp-tree-invisible {
+    display: none;
 }
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+.sp-tree ul,
+.sp-tree li {
+    margin-top: 0;
+    margin-bottom: 0;
+    list-style-type: none;
+}
+
+.sp-tree .mat-nested-tree-node div[role='group'] {
+    padding-left: 20px;
+}
+
+.sp-tree div[role='group'] > .mat-tree-node {
+    padding-left: 20px;
+}
+
+.mat-tree-node {
+    min-height: 35px;
+}
+
+.mat-tree-node:hover {
+    background: var(--color-bg-1);
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.ts
new file mode 100644
index 0000000000..18c4312478
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component.ts
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {
+    Component,
+    EventEmitter,
+    Input,
+    OnChanges,
+    Output,
+    SimpleChanges,
+    ViewChild,
+} from '@angular/core';
+import { AssetBrowserData } from '../asset-browser.model';
+import { NestedTreeControl } from '@angular/cdk/tree';
+import { SpAsset } from '@streampipes/platform-services';
+import { MatTreeNestedDataSource } from '@angular/material/tree';
+
+@Component({
+    selector: 'sp-asset-browser-hierarchy',
+    templateUrl: 'asset-browser-hierarchy.component.html',
+    styleUrls: ['./asset-browser-hierarchy.component.scss'],
+})
+export class AssetBrowserHierarchyComponent implements OnChanges {
+    @Input()
+    assetBrowserData: AssetBrowserData;
+
+    @Input()
+    assetSelectionMode = false;
+
+    @Input()
+    filteredAssetLinkType: string;
+
+    @Input()
+    resourceCount = 0;
+
+    @Output()
+    selectedAssetEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
+
+    treeControl = new NestedTreeControl<SpAsset>(node => node.assets);
+    dataSource = new MatTreeNestedDataSource<SpAsset>();
+
+    selectedAsset: SpAsset = null;
+
+    @ViewChild('tree') tree;
+
+    hasChild = (_: number, node: SpAsset) =>
+        // if asset selection mode is active, only show the direct root 
children
+        !!node.assets &&
+        node.assets.length > 0 &&
+        (!this.assetSelectionMode || node.assetId === '_root');
+
+    ngOnChanges(changes: SimpleChanges) {
+        if (changes.assetBrowserData) {
+            this.reloadTree();
+        }
+    }
+
+    reloadTree(): void {
+        this.treeControl = new NestedTreeControl<SpAsset>(node => node.assets);
+        this.dataSource = new MatTreeNestedDataSource<SpAsset>();
+        const nodes = this.makeRootNode();
+        this.selectedAsset = nodes;
+        this.dataSource.data = [nodes];
+        this.treeControl.dataNodes = [nodes];
+        this.treeControl.expandAll();
+    }
+
+    selectNode(asset: SpAsset) {
+        this.selectedAssetEmitter.emit(asset);
+        this.selectedAsset = asset;
+    }
+
+    makeRootNode(): SpAsset {
+        return {
+            assetId: '_root',
+            assetName: 'All Resources',
+            assetDescription: '',
+            assetLinks: [],
+            assets: this.assetBrowserData.assets,
+            assetType: undefined,
+        };
+    }
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.html
new file mode 100644
index 0000000000..daf001a934
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.html
@@ -0,0 +1,33 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="column" class="node-info-outer" fxLayoutGap="10px">
+    <div *ngIf="assetType">
+        <sp-label [small]="true" [labelText]="assetType"> </sp-label>
+    </div>
+    <div *ngIf="assetSite">
+        <sp-label [small]="true" [labelText]="assetSite"> </sp-label>
+    </div>
+    <div *ngFor="let label of labels" fxLayout="row wrap">
+        <sp-label
+            [small]="true"
+            [labelBackground]="label.color"
+            [labelText]="label.label"
+        ></sp-label>
+    </div>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.scss
similarity index 75%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.scss
index 778b5b97de..c6796b66d5 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.scss
@@ -16,16 +16,13 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
-}
-
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+.node-info-outer {
+    background: var(--color-bg-0);
+    min-width: 150px;
+    height: 100%;
+    border: 1px solid var(--color-bg-2);
+    padding: 10px;
+    box-shadow:
+        rgba(50, 50, 93, 0.25) 0 2px 5px -1px,
+        rgba(0, 0, 0, 0.3) 0 1px 3px -1px;
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.ts
new file mode 100644
index 0000000000..3fe8b1f551
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component.ts
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input, OnChanges, OnInit } from '@angular/core';
+import {
+    Isa95TypeService,
+    SpAsset,
+    SpLabel,
+} from '@streampipes/platform-services';
+import { AssetBrowserData } from '../../../asset-browser.model';
+import { SpAssetBrowserService } from '../../../asset-browser.service';
+
+@Component({
+    selector: 'sp-asset-browser-node-info',
+    templateUrl: 'asset-browser-node-info.component.html',
+    styleUrls: ['./asset-browser-node-info.component.scss'],
+})
+export class AssetBrowserNodeInfoComponent implements OnInit {
+    @Input()
+    asset: SpAsset;
+
+    @Input()
+    assetBrowserData: AssetBrowserData;
+    s;
+
+    labels: SpLabel[] = [];
+    assetType: string;
+    assetSite: string;
+
+    constructor(private isa95TypeService: Isa95TypeService) {}
+
+    ngOnInit() {
+        this.labels =
+            this.assetBrowserData.labels.filter(
+                l => this.asset.labelIds?.find(a => a === l._id) !== undefined,
+            ) || [];
+        if (this.asset.assetType?.isa95AssetType !== undefined) {
+            this.assetType = this.isa95TypeService.toLabel(
+                this.asset.assetType.isa95AssetType,
+            );
+        }
+        if (this.asset.assetSite?.siteId) {
+            this.assetSite = this.assetBrowserData.sites.find(
+                site => site._id === this.asset.assetSite.siteId,
+            )?.label;
+        }
+    }
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.html
new file mode 100644
index 0000000000..2cee505d44
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.html
@@ -0,0 +1,64 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div
+    [ngClass]="
+        node.assetId === selectedAsset.assetId
+            ? 'asset-node selected-node'
+            : 'asset-node'
+    "
+    fxLayout="row"
+    fxFlex="100"
+    (click)="emitSelectedNode(node)"
+>
+    <div fxFlex [ngClass]="nodeResourceCount > 0 ? '' : 'asset-node-disabled'">
+        <span fxLayoutAlign="start center">{{ node.assetName }} </span>
+    </div>
+    <div fxLayoutAlign="end center">
+        <div fxLayoutAlign="center center" fxLayout="column">
+            <mat-icon
+                *ngIf="hasContextInfo"
+                (mouseover)="infoOpen = true"
+                (mouseout)="infoOpen = false"
+                cdkOverlayOrigin
+                #trigger="cdkOverlayOrigin"
+                color="primary"
+                class="mr-5 info-icon"
+                fxLayoutAlign="center center"
+            >
+                info
+                <ng-template
+                    cdkConnectedOverlay
+                    [cdkConnectedOverlayOrigin]="trigger"
+                    [cdkConnectedOverlayOpen]="infoOpen"
+                >
+                    <sp-asset-browser-node-info
+                        [asset]="node"
+                        [assetBrowserData]="assetBrowserData"
+                    ></sp-asset-browser-node-info>
+                </ng-template>
+            </mat-icon>
+        </div>
+        <span
+            *ngIf="!assetSelectionMode"
+            class="resource-count"
+            [ngClass]="nodeResourceCount > 0 ? '' : 'resource-count-disabled'"
+            >{{ nodeResourceCount }}</span
+        >
+    </div>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.scss
similarity index 55%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.scss
index 778b5b97de..3a4970dd5c 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.scss
@@ -16,16 +16,41 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
+.asset-node {
+    font-weight: normal;
+    cursor: pointer;
+    width: 100%;
+}
+
+.asset-node-disabled {
+    color: var(--color-bg-3);
+    cursor: default;
+}
+
+.selected-node {
+    font-family: 'Roboto-Bold', serif;
+    font-weight: bolder;
+}
+
+.resource-count {
+    margin-right: 8px;
+    min-width: 20px;
     text-align: center;
+    font-size: smaller;
+    font-weight: bolder;
+    font-family: 'Roboto-Bold', serif;
+    padding: 3px;
+    border-radius: 3px;
+    background: var(--color-bg-3);
+    color: var(--color-default-text);
+}
+
+.resource-count-disabled {
+    background: var(--color-bg-2);
+    color: var(--color-bg-3);
 }
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+.info-icon {
+    color: var(--color-accent);
+    font-size: 12pt;
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.ts
new file mode 100644
index 0000000000..23f53f82c1
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component.ts
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {
+    Component,
+    EventEmitter,
+    Input,
+    OnChanges,
+    OnInit,
+    Output,
+    SimpleChanges,
+} from '@angular/core';
+import { SpAsset } from '@streampipes/platform-services';
+import { SpAssetBrowserService } from '../../asset-browser.service';
+import { AssetBrowserData } from '../../asset-browser.model';
+
+@Component({
+    selector: 'sp-asset-browser-node',
+    templateUrl: 'asset-browser-node.component.html',
+    styleUrls: ['./asset-browser-node.component.scss'],
+})
+export class AssetBrowserNodeComponent implements OnInit, OnChanges {
+    @Input()
+    assetBrowserData: AssetBrowserData;
+
+    @Input()
+    assetSelectionMode = false;
+
+    @Input()
+    node: SpAsset;
+
+    @Input()
+    selectedAsset: SpAsset;
+
+    @Input()
+    filteredAssetLinkType: string;
+
+    @Input()
+    resourceCount = 0;
+
+    @Output()
+    selectedNodeEmitter: EventEmitter<SpAsset> = new EventEmitter<SpAsset>();
+
+    infoOpen = false;
+
+    nodeResourceCount = 0;
+    hasContextInfo = false;
+
+    constructor(private assetBrowserService: SpAssetBrowserService) {}
+
+    ngOnInit() {
+        this.hasContextInfo =
+            this.node.labelIds?.length > 0 ||
+            this.node.assetSite?.siteId !== undefined ||
+            this.node.assetType?.isa95AssetType !== undefined;
+    }
+
+    ngOnChanges(changes: SimpleChanges): void {
+        if (changes.filteredAssetLinkType || changes.resourceCount) {
+            this.reloadCounts();
+        }
+    }
+
+    reloadCounts(): void {
+        if (this.node.assetId !== '_root') {
+            const elementIds = new Set<string>();
+            this.assetBrowserService.collectElementIds(
+                this.node,
+                this.filteredAssetLinkType,
+                elementIds,
+            );
+            this.nodeResourceCount = elementIds.size;
+        } else {
+            this.nodeResourceCount = this.resourceCount;
+        }
+    }
+
+    emitSelectedNode(node: SpAsset): void {
+        if (this.nodeResourceCount > 0) {
+            this.selectedNodeEmitter.emit(node);
+        }
+    }
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.html
new file mode 100644
index 0000000000..f376628dfa
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.html
@@ -0,0 +1,79 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div
+    fxLayout="row"
+    fxFlex="100"
+    fxLayoutAlign="start center"
+    class="filter-section"
+>
+    <div
+        fxFlex="50"
+        fxLayout="row"
+        fxLayoutAlign="start center"
+        fxLayoutGap="10px"
+    >
+        <div
+            class="filter-header"
+            fxLayout="row"
+            fxLayoutAlign="start center"
+            fxFlex="100"
+        >
+            <div
+                fxLayoutAlign="center center"
+                class="active-filters mr-5"
+                *ngIf="activeFilters.selectedLabels.length > 0"
+            >
+                <i class="material-icons fs-icon">filter_alt</i>
+            </div>
+            <span>Labels</span>
+        </div>
+    </div>
+    <div
+        fxFlex="50"
+        class="filter-selection"
+        fxLayout="column"
+        (click)="$event.stopPropagation()"
+        fxLayoutAlign="end center"
+    >
+        <mat-form-field
+            appearance="outline"
+            class="form-field-small filter-selection"
+            color="accent"
+        >
+            <mat-select
+                multiple
+                [compareWith]="compare"
+                [(ngModel)]="activeFilters.selectedLabels"
+            >
+                <mat-option
+                    *ngFor="let label of labels; let i = index"
+                    [value]="label"
+                    class="smaller-font-size"
+                >
+                    <sp-label
+                        [labelText]="label.label"
+                        [small]="true"
+                        [labelBackground]="label.color"
+                    >
+                    </sp-label>
+                </mat-option>
+            </mat-select>
+        </mat-form-field>
+    </div>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.ts
similarity index 57%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.ts
index 778b5b97de..0b84a97997 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component.ts
@@ -1,4 +1,4 @@
-/*!
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,16 +16,23 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
-}
+import { Component, Input } from '@angular/core';
+import { SpLabel } from '@streampipes/platform-services';
+import { AssetFilter } from '../../../asset-browser.model';
+
+@Component({
+    selector: 'sp-asset-browser-filter-labels',
+    templateUrl: 'asset-browser-filter-labels.component.html',
+    styleUrls: ['../asset-browser-filter.component.scss'],
+})
+export class AssetBrowserFilterLabelsComponent {
+    @Input()
+    labels: SpLabel[] = [];
+
+    @Input()
+    activeFilters: AssetFilter;
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+    compare(o1: SpLabel, o2: SpLabel): boolean {
+        return o1._id === o2._id;
+    }
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.html
new file mode 100644
index 0000000000..d7e6848f49
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.html
@@ -0,0 +1,81 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div
+    fxLayout="row"
+    fxFlex="100"
+    fxLayoutAlign="start center"
+    class="filter-section"
+>
+    <div
+        fxFlex="50"
+        fxLayout="row"
+        fxLayoutAlign="start center"
+        fxLayoutGap="10px"
+    >
+        <div
+            class="filter-header"
+            fxLayout="row"
+            fxLayoutAlign="start center"
+            fxFlex="100"
+        >
+            <div
+                fxLayoutAlign="center center"
+                class="active-filters mr-5"
+                *ngIf="selectedItems.length !== allItems.length"
+            >
+                <i class="material-icons fs-icon">filter_alt</i>
+            </div>
+            <span>{{ title }}</span>
+            <div
+                fxLayout="row"
+                fxLayoutAlign="end center"
+                fxLayoutGap="5px"
+                class="mr-10"
+                fxFlex
+            >
+                <button
+                    mat-button
+                    mat-raised-button
+                    color="accent"
+                    class="small-button btn-margin"
+                    (click)="selectAllEmitter.emit()"
+                >
+                    All
+                </button>
+                <button
+                    mat-button
+                    mat-raised-button
+                    class="small-button mat-basic btn-margin"
+                    (click)="deselectAllEmitter.emit()"
+                >
+                    None
+                </button>
+            </div>
+        </div>
+    </div>
+    <div
+        fxFlex="50"
+        class="filter-selection"
+        fxLayout="column"
+        (click)="$event.stopPropagation()"
+        fxLayoutAlign="end center"
+    >
+        <ng-content> </ng-content>
+    </div>
+</div>
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.ts
new file mode 100644
index 0000000000..b33e698e04
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component.ts
@@ -0,0 +1,23 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+    selector: 'sp-asset-browser-filter-outer',
+    templateUrl: 'asset-browser-filter-outer.component.html',
+    styleUrls: ['../asset-browser-filter.component.scss'],
+})
+export class AssetBrowserFilterOuterComponent {
+    @Input()
+    selectedItems: any[];
+
+    @Input()
+    allItems: any[];
+
+    @Input()
+    title: string = '';
+
+    @Output()
+    selectAllEmitter = new EventEmitter();
+
+    @Output()
+    deselectAllEmitter = new EventEmitter();
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.html
new file mode 100644
index 0000000000..ca4f1eefa1
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.html
@@ -0,0 +1,45 @@
+<!--
+  ~ 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-asset-browser-filter-outer
+    [selectedItems]="activeFilters.selectedSites"
+    [allItems]="sites"
+    title="Sites"
+    (selectAllEmitter)="selectAll()"
+    (deselectAllEmitter)="selectNone()"
+>
+    <mat-form-field
+        appearance="outline"
+        class="form-field-small filter-selection"
+        color="accent"
+    >
+        <mat-select
+            multiple
+            [compareWith]="compare"
+            [(ngModel)]="activeFilters.selectedSites"
+        >
+            <mat-option
+                *ngFor="let site of sites; let i = index"
+                [value]="site"
+                class="smaller-font-size"
+            >
+                {{ site.label }}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+</sp-asset-browser-filter-outer>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.ts
similarity index 51%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.ts
index 778b5b97de..6bb6c6e501 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component.ts
@@ -1,4 +1,4 @@
-/*!
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,16 +16,31 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
-}
+import { Component, Input } from '@angular/core';
+import { AssetSiteDesc } from '@streampipes/platform-services';
+import { AssetFilter } from '../../../asset-browser.model';
+
+@Component({
+    selector: 'sp-asset-browser-filter-sites',
+    templateUrl: 'asset-browser-filter-sites.component.html',
+    styleUrls: ['../asset-browser-filter.component.scss'],
+})
+export class AssetBrowserFilterSitesComponent {
+    @Input()
+    sites: AssetSiteDesc[] = [];
+
+    @Input()
+    activeFilters: AssetFilter;
+
+    selectAll(): void {
+        this.activeFilters.selectedSites = [...this.sites];
+    }
+
+    selectNone(): void {
+        this.activeFilters.selectedSites = [];
+    }
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+    compare(o1: AssetSiteDesc, o2: AssetSiteDesc): boolean {
+        return o1._id === o2._id;
+    }
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.html
new file mode 100644
index 0000000000..fd0ee9ebf0
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.html
@@ -0,0 +1,45 @@
+<!--
+  ~ 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-asset-browser-filter-outer
+    [selectedItems]="activeFilters.selectedTypes"
+    [allItems]="allAssetTypes"
+    title="Type"
+    (selectAllEmitter)="selectAll()"
+    (deselectAllEmitter)="selectNone()"
+>
+    <mat-form-field
+        appearance="outline"
+        class="form-field-small filter-selection"
+        color="accent"
+    >
+        <mat-select
+            multiple
+            [compareWith]="compare"
+            [(ngModel)]="activeFilters.selectedTypes"
+        >
+            <mat-option
+                *ngFor="let assetType of allAssetTypes; let i = index"
+                [value]="assetType"
+                class="smaller-font-size"
+            >
+                {{ assetType.label }}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+</sp-asset-browser-filter-outer>
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.ts
new file mode 100644
index 0000000000..7c78f320a9
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component.ts
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input, OnInit } from '@angular/core';
+import {
+    Isa95TypeDesc,
+    Isa95TypeService,
+} from '@streampipes/platform-services';
+import { AssetFilter } from '../../../asset-browser.model';
+
+@Component({
+    selector: 'sp-asset-browser-filter-type',
+    templateUrl: 'asset-browser-filter-type.component.html',
+    styleUrls: ['../asset-browser-filter.component.scss'],
+})
+export class AssetBrowserFilterTypeComponent implements OnInit {
+    allAssetTypes: Isa95TypeDesc[] = [];
+
+    @Input()
+    activeFilters: AssetFilter;
+
+    constructor(private typeService: Isa95TypeService) {}
+
+    ngOnInit() {
+        this.allAssetTypes = this.typeService
+            .getTypeDescriptions()
+            .sort((a, b) => a.label.localeCompare(b.label));
+    }
+
+    compare(o1: Isa95TypeDesc, o2: Isa95TypeDesc): boolean {
+        return o1.type === o2.type;
+    }
+
+    selectAll(): void {
+        this.activeFilters.selectedTypes = [...this.allAssetTypes];
+    }
+
+    selectNone(): void {
+        this.activeFilters.selectedTypes = [];
+    }
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.html
new file mode 100644
index 0000000000..fa78b95f08
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.html
@@ -0,0 +1,51 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div
+    class="menu-content"
+    (click)="$event.stopPropagation()"
+    *ngIf="activeFilters"
+>
+    <div fxLayout="column" fxLayoutGap="10px">
+        <sp-asset-browser-filter-type [activeFilters]="activeFilters">
+        </sp-asset-browser-filter-type>
+        <sp-asset-browser-filter-sites
+            [sites]="assetBrowserData.sites"
+            [activeFilters]="activeFilters"
+        >
+        </sp-asset-browser-filter-sites>
+        <sp-asset-browser-filter-labels
+            [labels]="assetBrowserData.labels"
+            [activeFilters]="activeFilters"
+        >
+        </sp-asset-browser-filter-labels>
+        <mat-divider></mat-divider>
+        <div fxLayout="row" fxLayoutAlign="end center">
+            <button
+                mat-raised-button
+                class="mat-basic"
+                (click)="resetFilters()"
+            >
+                Reset filters
+            </button>
+            <button mat-raised-button color="accent" (click)="applyFilters()">
+                Apply
+            </button>
+        </div>
+    </div>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.scss
similarity index 54%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.scss
index 778b5b97de..4b836ee4f5 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.scss
@@ -16,16 +16,46 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
-}
-
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+.menu-content {
+    padding: 10px;
+    min-width: 550px;
+}
+
+.filter-header {
+    font-weight: bold;
+    white-space: nowrap;
+}
+
+.filter-section {
+    padding: 5px 10px 5px 5px;
+    border: 1px solid var(--color-bg-3);
+    background: var(--color-bg-1);
+}
+
+.smaller-font-size {
+    font-size: smaller;
+}
+
+.filter-selection {
+    min-width: 300px;
+    margin-bottom: -10px;
+}
+
+.fs-icon {
+    font-size: 16px;
+}
+
+.active-filters {
+    border-radius: 50%;
+    background: var(--color-primary);
+    color: var(--color-accent);
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+    font-weight: bold;
+}
+
+.empty {
+    background: var(--color-bg-2);
+    color: var(--color-bg-3);
 }
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.ts
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.ts
new file mode 100644
index 0000000000..d18e37ff19
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component.ts
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {
+    Component,
+    EventEmitter,
+    Input,
+    OnDestroy,
+    OnInit,
+    Output,
+} from '@angular/core';
+import { AssetBrowserData, AssetFilter } from '../../asset-browser.model';
+import { Subscription } from 'rxjs';
+import { SpAssetBrowserService } from '../../asset-browser.service';
+
+@Component({
+    selector: 'sp-asset-browser-filter',
+    templateUrl: 'asset-browser-filter.component.html',
+    styleUrl: 'asset-browser-filter.component.scss',
+})
+export class AssetBrowserFilterComponent implements OnInit, OnDestroy {
+    @Input()
+    assetBrowserData: AssetBrowserData;
+    activeFilters: AssetFilter;
+
+    filterSub: Subscription;
+
+    @Output()
+    closeMenu: EventEmitter<void> = new EventEmitter();
+
+    constructor(private assetBrowserService: SpAssetBrowserService) {}
+
+    ngOnInit() {
+        this.filterSub = this.assetBrowserService.filter$.subscribe(
+            activeFilters => {
+                this.activeFilters = activeFilters;
+            },
+        );
+    }
+
+    applyFilters(): void {
+        this.assetBrowserService.applyFilters(this.activeFilters);
+        this.closeMenu.emit();
+    }
+
+    resetFilters(): void {
+        this.assetBrowserService.resetFilters();
+        this.closeMenu.emit();
+    }
+
+    ngOnDestroy() {
+        this.filterSub?.unsubscribe();
+    }
+}
diff --git 
a/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
new file mode 100644
index 0000000000..dce9bb6e8d
--- /dev/null
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.html
@@ -0,0 +1,52 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxFlex fxLayoutAlign="start center" *ngIf="expanded">
+    <h4 class="ml-5">Browse assets</h4>
+</div>
+<div fxLayoutAlign="end center">
+    <button
+        mat-icon-button
+        *ngIf="expanded"
+        color="accent"
+        [matMenuTriggerFor]="menu"
+        #menuTrigger="matMenuTrigger"
+        matTooltip="Filter assets"
+        (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"
+        >
+        </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>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
similarity index 55%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to 
ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
index 778b5b97de..965f6d6d74 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ 
b/ui/src/app/core-ui/asset-browser/asset-browser-toolbar/asset-browser-toolbar.component.ts
@@ -1,4 +1,4 @@
-/*!
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,16 +16,33 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
-}
+import {
+    Component,
+    EventEmitter,
+    Input,
+    Output,
+    ViewChild,
+} from '@angular/core';
+import { AssetBrowserData } from '../asset-browser.model';
+import { MatMenuTrigger } from '@angular/material/menu';
+
+@Component({
+    selector: 'sp-asset-browser-toolbar',
+    templateUrl: 'asset-browser-toolbar.component.html',
+})
+export class AssetBrowserToolbarComponent {
+    @Input()
+    expanded: boolean;
+
+    @Output()
+    toggleExpanded = new EventEmitter<boolean>();
+
+    @Input()
+    assetBrowserData: AssetBrowserData;
+
+    @ViewChild('menuTrigger') menu: MatMenuTrigger;
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+    closeMenu(): void {
+        this.menu.closeMenu();
+    }
 }
diff --git a/ui/src/app/core-ui/asset-browser/asset-browser.component.html 
b/ui/src/app/core-ui/asset-browser/asset-browser.component.html
new file mode 100644
index 0000000000..0f19da89e8
--- /dev/null
+++ b/ui/src/app/core-ui/asset-browser/asset-browser.component.html
@@ -0,0 +1,77 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="row" fxFlex="100">
+    <div [fxFlex]="expanded ? browserWidth : '75px'">
+        <sp-basic-view [showBackLink]="false">
+            <div nav fxLayoutAlign="start center" fxFlex="100">
+                @if (assetBrowserData) {
+                    <sp-asset-browser-toolbar
+                        fxFlex="100"
+                        [assetBrowserData]="assetBrowserData"
+                        [expanded]="expanded"
+                        (toggleExpanded)="toggleExpanded($event)"
+                    >
+                    </sp-asset-browser-toolbar>
+                }
+            </div>
+            @if (assetBrowserData?.assets?.length > 0 && expanded) {
+                <sp-asset-browser-hierarchy
+                    [assetBrowserData]="assetBrowserData"
+                    [assetSelectionMode]="assetSelectionMode"
+                    [resourceCount]="resourceCount"
+                    [filteredAssetLinkType]="filteredAssetLinkType"
+                    (selectedAssetEmitter)="applyAssetFilter($event)"
+                    class="asset-hierarchy"
+                >
+                </sp-asset-browser-hierarchy>
+            } @else if (assetBrowserData?.assets?.length === 0 && expanded) {
+                <div
+                    fxLayoutAlign="center center"
+                    fxLayout="column"
+                    fxFlex="100"
+                >
+                    <span class="asset-creation-hint"
+                        >No assets configured yet - use assets to better
+                        organize resources!</span
+                    >
+                    <button
+                        mat-button
+                        color="accent"
+                        class="mt-10"
+                        (click)="navigateToAssetManagement()"
+                    >
+                        Manage assets
+                    </button>
+                </div>
+            }
+            @if (!expanded) {
+                <div
+                    *ngIf="!expanded"
+                    class="asset-hierarchy asset-browser-text"
+                    fxLayoutAlign="center center"
+                >
+                    Asset Browser
+                </div>
+            }
+        </sp-basic-view>
+    </div>
+    <div fxFlex>
+        <ng-content> </ng-content>
+    </div>
+</div>
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 b/ui/src/app/core-ui/asset-browser/asset-browser.component.scss
similarity index 75%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to ui/src/app/core-ui/asset-browser/asset-browser.component.scss
index 778b5b97de..1f145dbcb4 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ b/ui/src/app/core-ui/asset-browser/asset-browser.component.scss
@@ -16,16 +16,21 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
+.asset-hierarchy {
+    height: calc(100vh - 145px);
+    max-height: calc(100vh - 145px);
+    overflow-y: auto;
+    margin-left: 5px;
+    margin-top: 5px;
+}
+
+.asset-browser-text {
+    text-orientation: mixed;
+    writing-mode: tb-rl;
     text-align: center;
 }
 
-.small-label {
+.asset-creation-hint {
     font-size: 10pt;
-    padding: 2px 8px;
+    text-align: center;
 }
diff --git a/ui/src/app/core-ui/asset-browser/asset-browser.component.ts 
b/ui/src/app/core-ui/asset-browser/asset-browser.component.ts
new file mode 100644
index 0000000000..4884f8a052
--- /dev/null
+++ b/ui/src/app/core-ui/asset-browser/asset-browser.component.ts
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import {
+    Component,
+    EventEmitter,
+    Input,
+    OnDestroy,
+    OnInit,
+    Output,
+} from '@angular/core';
+import { SpAssetBrowserService } from './asset-browser.service';
+import { AssetBrowserData } from './asset-browser.model';
+import { Subscription } from 'rxjs';
+import { SpAsset } from '@streampipes/platform-services';
+import { Router } from '@angular/router';
+
+@Component({
+    selector: 'sp-asset-browser',
+    templateUrl: 'asset-browser.component.html',
+    styleUrls: ['./asset-browser.component.scss'],
+})
+export class AssetBrowserComponent implements OnInit, OnDestroy {
+    @Input()
+    showResources = false;
+
+    @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;
+
+    assetBrowserDataSub: Subscription;
+    expandedSub: Subscription;
+
+    expanded = true;
+
+    constructor(
+        private assetBrowserService: SpAssetBrowserService,
+        private router: Router,
+    ) {}
+
+    ngOnInit(): void {
+        this.assetBrowserDataSub =
+            this.assetBrowserService.assetData$.subscribe(assetData => {
+                this.assetBrowserData = assetData;
+            });
+        this.expandedSub = this.assetBrowserService.expanded$.subscribe(
+            expanded => (this.expanded = expanded),
+        );
+    }
+
+    toggleExpanded(event: boolean): void {
+        this.assetBrowserService.expanded$.next(event);
+    }
+
+    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);
+    }
+
+    navigateToAssetManagement(): void {
+        this.router.navigate(['assets', 'overview']);
+    }
+
+    ngOnDestroy(): void {
+        this.assetBrowserDataSub?.unsubscribe();
+        this.expandedSub?.unsubscribe();
+    }
+}
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
 b/ui/src/app/core-ui/asset-browser/asset-browser.model.ts
similarity index 66%
copy from 
ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
copy to ui/src/app/core-ui/asset-browser/asset-browser.model.ts
index 778b5b97de..4523873e0e 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/sp-label/sp-label.component.scss
+++ b/ui/src/app/core-ui/asset-browser/asset-browser.model.ts
@@ -1,4 +1,4 @@
-/*!
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,16 +16,23 @@
  *
  */
 
-.basic-label {
-    border-radius: 15px;
-    min-width: 50px;
-    padding: 5px 7px;
-    border: 1px solid;
-    display: inline-block;
-    text-align: center;
+import {
+    AssetLink,
+    AssetSiteDesc,
+    Isa95TypeDesc,
+    SpAsset,
+    SpLabel,
+} from '@streampipes/platform-services';
+
+export interface AssetBrowserData {
+    assets: SpAsset[];
+    assetLinks: AssetLink[];
+    sites: AssetSiteDesc[];
+    labels: SpLabel[];
 }
 
-.small-label {
-    font-size: 10pt;
-    padding: 2px 8px;
+export interface AssetFilter {
+    selectedSites: AssetSiteDesc[];
+    selectedTypes: Isa95TypeDesc[];
+    selectedLabels: SpLabel[];
 }
diff --git a/ui/src/app/core-ui/asset-browser/asset-browser.service.ts 
b/ui/src/app/core-ui/asset-browser/asset-browser.service.ts
new file mode 100644
index 0000000000..01ff24133e
--- /dev/null
+++ b/ui/src/app/core-ui/asset-browser/asset-browser.service.ts
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, zip } from 'rxjs';
+import {
+    AssetSiteDesc,
+    GenericStorageService,
+    Isa95TypeDesc,
+    Isa95TypeService,
+    SpAsset,
+    SpLabel,
+} from '@streampipes/platform-services';
+import { AssetConstants } from '../../assets/constants/asset.constants';
+import { AssetBrowserData, AssetFilter } from './asset-browser.model';
+
+@Injectable({ providedIn: 'root' })
+export class SpAssetBrowserService {
+    assetData$ = new BehaviorSubject<AssetBrowserData>(undefined);
+    expanded$ = new BehaviorSubject<boolean>(true);
+    filter$ = new BehaviorSubject<AssetFilter>(undefined);
+
+    loadedAssetData: AssetBrowserData;
+
+    constructor(
+        private genericStorageService: GenericStorageService,
+        private typeService: Isa95TypeService,
+    ) {
+        this.loadAssetData();
+    }
+
+    loadAssetData(): void {
+        const assetsReq = this.genericStorageService.getAllDocuments(
+            AssetConstants.ASSET_APP_DOC_NAME,
+        );
+        const assetLinksReq = this.genericStorageService.getAllDocuments(
+            AssetConstants.ASSET_LINK_TYPES_DOC_NAME,
+        );
+        const sitesReq = this.genericStorageService.getAllDocuments(
+            AssetConstants.ASSET_SITES_APP_DOC_NAME,
+        );
+        const labelsReq =
+            this.genericStorageService.getAllDocuments('sp-labels');
+
+        zip([assetsReq, assetLinksReq, sitesReq, labelsReq]).subscribe(res => {
+            this.loadedAssetData = {
+                assets: res[0].sort((a, b) =>
+                    a.assetName.localeCompare(b.assetName),
+                ),
+                assetLinks: res[1],
+                sites: res[2],
+                labels: res[3].sort((a, b) => a.label.localeCompare(b.label)),
+            };
+            this.assetData$.next(this.loadedAssetData);
+            this.reloadFilters();
+        });
+    }
+
+    private reloadFilters(): void {
+        const data = this.assetData$.getValue();
+        const filters: AssetFilter = {
+            selectedSites: [...data.sites].sort((a, b) =>
+                a.label.localeCompare(b.label),
+            ),
+            selectedLabels: [],
+            selectedTypes: [...this.typeService.getTypeDescriptions()],
+        };
+        this.filter$.next(filters);
+    }
+
+    resetFilters(): void {
+        this.assetData$.next(this.loadedAssetData);
+        this.reloadFilters();
+    }
+
+    applyFilters(filter: AssetFilter) {
+        const clonedLoadedAssetData = JSON.parse(
+            JSON.stringify(this.loadedAssetData),
+        ) as AssetBrowserData;
+        const filteredAssets = clonedLoadedAssetData.assets
+            .filter(
+                a =>
+                    this.allSelected(
+                        this.typeService.getTypeDescriptions(),
+                        filter.selectedTypes,
+                    ) || this.filterType(a, filter.selectedTypes),
+            )
+            .filter(
+                a =>
+                    this.allSelected(
+                        clonedLoadedAssetData.sites,
+                        filter.selectedSites,
+                    ) || this.filterSites(a, filter.selectedSites),
+            )
+            .filter(a => this.filterLabels(a, filter.selectedLabels));
+
+        this.assetData$.next({
+            assets: filteredAssets,
+            assetLinks: clonedLoadedAssetData.assetLinks,
+            sites: clonedLoadedAssetData.sites,
+            labels: clonedLoadedAssetData.labels,
+        });
+    }
+
+    private allSelected(items: any[], selected: any[]) {
+        return items.length === selected.length;
+    }
+
+    private filterType(
+        asset: SpAsset,
+        selectedTypes: Isa95TypeDesc[],
+    ): boolean {
+        const matchesSelf = selectedTypes.some(
+            type => type.type === asset.assetType?.isa95AssetType,
+        );
+
+        if (asset.assets?.length) {
+            asset.assets = asset.assets
+                .map(a => ({ ...a }))
+                .filter(a => this.filterType(a, selectedTypes));
+            return matchesSelf || asset.assets.length > 0;
+        }
+
+        return matchesSelf;
+    }
+
+    private filterSites(
+        asset: SpAsset,
+        selectedSites: AssetSiteDesc[],
+    ): boolean {
+        return (
+            selectedSites.find(site => asset.assetSite?.siteId === site._id) 
!==
+            undefined
+        );
+    }
+
+    private filterLabels(asset: SpAsset, selectedLabels: SpLabel[]): boolean {
+        const labelIds = asset.labelIds || [];
+        const matchesSelf = selectedLabels.every(label =>
+            labelIds.includes(label._id),
+        );
+
+        if (asset.assets?.length) {
+            asset.assets = asset.assets
+                .map(a => ({ ...a }))
+                .filter(a => this.filterLabels(a, selectedLabels));
+            return matchesSelf || asset.assets.length > 0;
+        }
+
+        return matchesSelf;
+    }
+
+    collectElementIds(
+        asset: SpAsset,
+        filteredLinkType: string,
+        elementIds: Set<string>,
+    ): void {
+        const assetLinkValues = this.findAssetLinkValues(
+            asset,
+            filteredLinkType,
+        );
+        assetLinkValues.forEach(v => elementIds.add(v));
+        if (asset.assets !== undefined) {
+            asset.assets.forEach((a: SpAsset) => {
+                this.collectElementIds(a, filteredLinkType, elementIds);
+            });
+        }
+    }
+
+    findAssetLinkValues(asset: SpAsset, filteredLinkType: string): string[] {
+        return asset.assetLinks
+            .filter(a => a.linkType === filteredLinkType)
+            .map(a => a.resourceId);
+    }
+}
diff --git a/ui/src/app/core-ui/core-ui.module.ts 
b/ui/src/app/core-ui/core-ui.module.ts
index bf9a91ff30..f44ef42248 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -116,6 +116,16 @@ import { StaticTreeInputNodeDetailsComponent } from 
'./static-properties/static-
 import { SingleMarkerMapComponent } from 
'./single-marker-map/single-marker-map.component';
 import { LeafletModule } from '@asymmetrik/ngx-leaflet';
 import { StaticTreeInputTextEditorComponent } from 
'./static-properties/static-runtime-resolvable-tree-input/static-tree-input-text-editor/static-tree-input-text-editor.component';
+import { AssetBrowserComponent } from 
'./asset-browser/asset-browser.component';
+import { AssetBrowserToolbarComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-toolbar.component';
+import { AssetBrowserHierarchyComponent } from 
'./asset-browser/asset-browser-hierarchy/asset-browser-hierarchy.component';
+import { AssetBrowserNodeComponent } from 
'./asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node.component';
+import { AssetBrowserFilterComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter.component';
+import { AssetBrowserFilterLabelsComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-labels/asset-browser-filter-labels.component';
+import { AssetBrowserFilterSitesComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-sites/asset-browser-filter-sites.component';
+import { AssetBrowserFilterTypeComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-type/asset-browser-filter-type.component';
+import { AssetBrowserFilterOuterComponent } from 
'./asset-browser/asset-browser-toolbar/asset-browser-filter/asset-browser-filter-outer/asset-browser-filter-outer.component';
+import { AssetBrowserNodeInfoComponent } from 
'./asset-browser/asset-browser-hierarchy/asset-browser-node/asset-browser-node-info/asset-browser-node-info.component';
 
 @NgModule({
     imports: [
@@ -168,6 +178,16 @@ import { StaticTreeInputTextEditorComponent } from 
'./static-properties/static-r
         LeafletModule,
     ],
     declarations: [
+        AssetBrowserComponent,
+        AssetBrowserFilterComponent,
+        AssetBrowserFilterLabelsComponent,
+        AssetBrowserFilterOuterComponent,
+        AssetBrowserFilterSitesComponent,
+        AssetBrowserFilterTypeComponent,
+        AssetBrowserHierarchyComponent,
+        AssetBrowserNodeComponent,
+        AssetBrowserNodeInfoComponent,
+        AssetBrowserToolbarComponent,
         DataDownloadDialogComponent,
         DateInputComponent,
         DisplayRecommendedPipe,
@@ -223,6 +243,7 @@ import { StaticTreeInputTextEditorComponent } from 
'./static-properties/static-r
     ],
     providers: [MatDatepickerModule, DisplayRecommendedPipe],
     exports: [
+        AssetBrowserComponent,
         DataDownloadDialogComponent,
         DateInputComponent,
         PipelineElementTemplateConfigComponent,
diff --git a/ui/src/app/pipelines/pipelines.component.html 
b/ui/src/app/pipelines/pipelines.component.html
index 73338ecaba..0cb8afd7a1 100644
--- a/ui/src/app/pipelines/pipelines.component.html
+++ b/ui/src/app/pipelines/pipelines.component.html
@@ -16,92 +16,102 @@
   ~
   -->
 
-<sp-basic-view [showBackLink]="false" [padding]="true">
-    <div
-        nav
-        fxFlex="100"
-        fxLayoutAlign="start center"
-        fxLayout="row"
-        class="pl-10"
-    >
-        <button
-            mat-button
-            mat-raised-button
-            color="accent"
-            (click)="navigateToPipelineEditor()"
-            data-cy="pipelines-navigate-to-editor"
+<sp-asset-browser
+    filteredAssetLinkType="pipeline"
+    [resourceCount]="pipelines.length"
+    (filterIdsEmitter)="applyPipelineFilters($event)"
+>
+    <sp-basic-view [showBackLink]="false" [padding]="true">
+        <div
+            nav
+            fxFlex="100"
+            fxLayoutAlign="start center"
+            fxLayout="row"
+            class="pl-10"
         >
-            <i class="material-icons">add</i>&nbsp;New pipeline
-        </button>
-        <button
-            class="mr-10"
-            mat-button
-            color="accent"
-            (click)="startAllPipelines(true)"
-            [disabled]="checkCurrentSelectionStatus(false)"
-            *ngIf="hasPipelineWritePrivileges"
-        >
-            <mat-icon>play_arrow</mat-icon>
-            <span>Start all pipelines</span>
-        </button>
-        <button
-            mat-button
-            color="accent"
-            (click)="startAllPipelines(false)"
-            [disabled]="checkCurrentSelectionStatus(true)"
-            *ngIf="hasPipelineWritePrivileges"
-        >
-            <mat-icon>stop</mat-icon>
-            <span>Stop all pipelines</span>
-        </button>
-        <span fxFlex></span>
-        <button
-            mat-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)="refreshPipelines()"
-        >
-            <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="90">
-                    <sp-pipeline-overview
-                        [pipelines]="pipelines"
-                        (refreshPipelinesEmitter)="refreshPipelines()"
-                        *ngIf="pipelinesReady"
-                    ></sp-pipeline-overview>
-                </div>
-            </div>
-            <div fxFlex="100" fxLayout="column" style="margin-top: 20px">
+            <button
+                mat-button
+                mat-raised-button
+                color="accent"
+                (click)="navigateToPipelineEditor()"
+                data-cy="pipelines-navigate-to-editor"
+            >
+                <i class="material-icons">add</i>&nbsp;New pipeline
+            </button>
+            <button
+                class="mr-10"
+                mat-button
+                color="accent"
+                (click)="startAllPipelines(true)"
+                [disabled]="checkCurrentSelectionStatus(false)"
+                *ngIf="hasPipelineWritePrivileges"
+            >
+                <mat-icon>play_arrow</mat-icon>
+                <span>Start all pipelines</span>
+            </button>
+            <button
+                mat-button
+                color="accent"
+                (click)="startAllPipelines(false)"
+                [disabled]="checkCurrentSelectionStatus(true)"
+                *ngIf="hasPipelineWritePrivileges"
+            >
+                <mat-icon>stop</mat-icon>
+                <span>Stop all pipelines</span>
+            </button>
+            <span fxFlex></span>
+            <button
+                mat-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="Functions"
+                    title="Pipelines"
                 ></sp-basic-header-title-component>
                 <div fxFlex="100" fxLayout="row" fxLayoutAlign="center start">
                     <div fxFlex="90">
-                        <sp-functions-overview
-                            [functions]="functions"
-                            *ngIf="functionsReady"
-                        >
-                        </sp-functions-overview>
+                        <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="90">
+                            <sp-functions-overview
+                                [functions]="functions"
+                                *ngIf="functionsReady"
+                            >
+                            </sp-functions-overview>
+                        </div>
                     </div>
                 </div>
             </div>
         </div>
-    </div>
-</sp-basic-view>
+    </sp-basic-view>
+</sp-asset-browser>
diff --git a/ui/src/app/pipelines/pipelines.component.ts 
b/ui/src/app/pipelines/pipelines.component.ts
index 1a4ef6da47..a80eedffd3 100644
--- a/ui/src/app/pipelines/pipelines.component.ts
+++ b/ui/src/app/pipelines/pipelines.component.ts
@@ -47,6 +47,7 @@ import { Subscription } from 'rxjs';
 export class PipelinesComponent implements OnInit, OnDestroy {
     pipeline: Pipeline;
     pipelines: Pipeline[] = [];
+    filteredPipelines: Pipeline[] = [];
     starting: boolean;
     stopping: boolean;
 
@@ -111,13 +112,24 @@ export class PipelinesComponent implements OnInit, 
OnDestroy {
         this.pipelines = [];
         this.pipelineService.getPipelines().subscribe(pipelines => {
             this.pipelines = pipelines;
-            this.pipelinesReady = true;
+            this.applyPipelineFilters(new Set<string>());
         });
     }
 
+    applyPipelineFilters(elementIds: Set<string>) {
+        if (elementIds.size == 0) {
+            this.filteredPipelines = this.pipelines;
+        } else {
+            this.filteredPipelines = this.pipelines.filter(p =>
+                elementIds.has(p.elementId),
+            );
+        }
+        this.pipelinesReady = true;
+    }
+
     checkCurrentSelectionStatus(status) {
         let active = true;
-        this.pipelines.forEach(pipeline => {
+        this.filteredPipelines.forEach(pipeline => {
             if (pipeline.running === status) {
                 active = false;
             }
@@ -132,22 +144,18 @@ export class PipelinesComponent implements OnInit, 
OnDestroy {
                 title: (action ? 'Start' : 'Stop') + ' all pipelines',
                 width: '70vw',
                 data: {
-                    pipelines: this.pipelines,
+                    pipelines: this.filteredPipelines,
                     action: action,
                 },
             });
 
         dialogRef.afterClosed().subscribe(data => {
             if (data) {
-                this.refreshPipelines();
+                this.getPipelines();
             }
         });
     }
 
-    refreshPipelines() {
-        this.getPipelines();
-    }
-
     startPipelineTour(): void {
         this.shepherdService.startPipelineTour();
     }

Reply via email to