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

riemer pushed a commit to branch 4062-improve-entry-page
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/4062-improve-entry-page by 
this push:
     new f023a29d56 feat(#4062): Improve entry page
f023a29d56 is described below

commit f023a29d56ee63bc95329400f0db4464d7f770f3
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Dec 16 13:54:37 2025 +0100

    feat(#4062): Improve entry page
---
 .../user/management/util/UserInfoUtil.java         |  11 +-
 ui/deployment/home.service.mst                     |   3 +-
 ui/deployment/modules.yml                          |   4 +
 .../src/lib/services/isa95-type.service.ts         |   3 +
 .../split-section/split-section.component.scss     |  20 +-
 .../app/core-ui/asset-map/asset-map.component.html |   0
 .../app/core-ui/asset-map/asset-map.component.ts   |   0
 .../asset-links/home-asset-links.component.html    |   0
 .../asset-links/home-asset-links.component.scss    |   0
 .../asset-links/home-asset-links.component.ts      |   0
 .../asset-link-chip/asset-link-chip.component.html |  26 +++
 .../asset-link-chip.component.scss}                |  59 +++---
 .../asset-link-chip/asset-link-chip.component.ts   |  50 +++++
 .../asset-map-popup/asset-map-popup.component.html |  68 +++++++
 .../asset-map-popup/asset-map-popup.component.scss | 120 ++++++++++++
 .../asset-map-popup/asset-map-popup.component.ts   |  74 ++++++++
 .../asset-map/home-asset-map.component.html        |  30 +++
 .../home-asset-map.component.scss}                 |  33 +---
 .../asset-map/home-asset-map.component.ts          | 203 +++++++++++++++++++++
 .../asset-table-link-preview.component.html        |  31 ++++
 .../asset-table-link-preview.component.scss        | 114 ++++++++++++
 .../asset-table-link-preview.component.ts          |  50 +++++
 .../asset-table/home-asset-table.component.html    |  78 ++++++++
 .../home-asset-table.component.scss}               |  39 ++--
 .../asset-table/home-asset-table.component.ts      |  94 ++++++++++
 ui/src/app/home/components/status.component.html   |  53 ++----
 ui/src/app/home/components/status.component.scss   | 129 +++++++++++--
 ui/src/app/home/components/status.component.ts     |  14 +-
 .../home/components/welcome/welcome.component.html |  24 +++
 .../welcome.component.scss}                        |  40 ++--
 .../home/components/welcome/welcome.component.ts   |  49 +++++
 ui/src/app/home/home.component.html                | 124 ++++++-------
 ui/src/app/home/home.component.scss                |  77 ++------
 ui/src/app/home/home.component.ts                  |  89 +++++----
 ui/src/app/home/home.module.ts                     |  38 +++-
 ui/src/app/home/models/home.model.ts               |   1 +
 ui/src/scss/sp/_variables.scss                     |  14 +-
 ui/src/scss/sp/main.scss                           |  16 +-
 38 files changed, 1432 insertions(+), 346 deletions(-)

diff --git 
a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
 
b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
index e89ae58afa..15bd09b576 100644
--- 
a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
+++ 
b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
@@ -23,6 +23,7 @@ import org.apache.streampipes.model.client.user.Principal;
 import org.apache.streampipes.model.client.user.ServiceAccount;
 import org.apache.streampipes.model.client.user.UserAccount;
 
+import java.util.Objects;
 import java.util.Set;
 
 public class UserInfoUtil {
@@ -35,7 +36,8 @@ public class UserInfoUtil {
 
   private static UserInfo toUserInfo(UserAccount userAccount,
                                      Set<String> roles) {
-    UserInfo userInfo = prepareUserInfo(userAccount, roles);
+    var displayName = Objects.nonNull(userAccount.getFullName()) ? 
userAccount.getFullName() : userAccount.getUsername();
+    UserInfo userInfo = prepareUserInfo(userAccount, roles, displayName);
     userInfo.setShowTutorial(!userAccount.isHideTutorial());
     userInfo.setHasAcknowledged(userAccount.isHasAcknowledged());
     userInfo.setLanguage(userAccount.getLanguage());
@@ -44,14 +46,15 @@ public class UserInfoUtil {
 
   private static UserInfo toServiceUserInfo(ServiceAccount serviceAccount,
                                             Set<String> roles) {
-    return prepareUserInfo(serviceAccount, roles);
+    return prepareUserInfo(serviceAccount, roles, 
serviceAccount.getUsername());
   }
 
   private static UserInfo prepareUserInfo(Principal principal,
-                                          Set<String> roles) {
+                                          Set<String> roles,
+                                          String displayName) {
     UserInfo userInfo = new UserInfo();
     userInfo.setUsername(principal.getUsername());
-    userInfo.setDisplayName(principal.getUsername());
+    userInfo.setDisplayName(displayName);
     userInfo.setRoles(roles);
 
     return userInfo;
diff --git a/ui/deployment/home.service.mst b/ui/deployment/home.service.mst
index 7f28bec2c0..54b71fa1a9 100644
--- a/ui/deployment/home.service.mst
+++ b/ui/deployment/home.service.mst
@@ -67,7 +67,8 @@ export class HomeService {
                     dataFns: {{{statusBox.dataFns}}},
                     viewRoles: {{{statusBox.viewRoles}}},
                     createRoles: {{{statusBox.createRoles}}},
-                    icon: '{{{icon}}}'
+                    icon: '{{{icon}}}',
+                    assetLinkTypeId: '{{{assetLinkTypeId}}}'
                }
                {{/statusBox}}
            },
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index 9021329c27..f43600590b 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -71,6 +71,7 @@ spConnect:
     showStatusBox: true
     statusBox:
         link: "['connect']"
+        assetLinkTypeId: 'adapter'
         createLinks: "['connect', 'create']"
         title: 'Adapters'
         createTitle: 'New adapter'
@@ -94,6 +95,7 @@ spPipelines:
     showStatusBox: true
     statusBox:
         link: "['pipelines']"
+        assetLinkTypeId: 'pipeline'
         createLinks: "['pipelines', 'create']"
         title: 'Pipelines'
         createTitle: 'New pipeline'
@@ -132,6 +134,7 @@ spDashboard:
     showStatusBox: true
     statusBox:
         link: "['dashboard']"
+        assetLinkTypeId: 'dashboard'
         createLinks: "['dashboard']"
         title: 'Dashboards'
         createTitle: 'New dashboard'
@@ -155,6 +158,7 @@ spChart:
     showStatusBox: true
     statusBox:
         link: "['chart']"
+        assetLinkTypeId: 'chart'
         createLinks: "['chart']"
         title: 'Charts'
         createTitle: 'New chart'
diff --git 
a/ui/projects/streampipes/platform-services/src/lib/services/isa95-type.service.ts
 
b/ui/projects/streampipes/platform-services/src/lib/services/isa95-type.service.ts
index f9a0afbdaa..27aea68633 100644
--- 
a/ui/projects/streampipes/platform-services/src/lib/services/isa95-type.service.ts
+++ 
b/ui/projects/streampipes/platform-services/src/lib/services/isa95-type.service.ts
@@ -43,6 +43,9 @@ export class Isa95TypeService {
     }
 
     toLabel(type: Isa95Type): string {
+        if (!type) {
+            return '';
+        }
         return type
             .toLocaleLowerCase()
             .replace(/_/g, ' ')
diff --git 
a/ui/projects/streampipes/shared-ui/src/lib/components/split-section/split-section.component.scss
 
b/ui/projects/streampipes/shared-ui/src/lib/components/split-section/split-section.component.scss
index cd1dfe2109..f85d4b8c5f 100644
--- 
a/ui/projects/streampipes/shared-ui/src/lib/components/split-section/split-section.component.scss
+++ 
b/ui/projects/streampipes/shared-ui/src/lib/components/split-section/split-section.component.scss
@@ -18,9 +18,11 @@
 
 :host {
     width: 100%;
-    display: block;
+    //display: block;
+    display: flex;
     --accent: hsl(221 83% 53%);
     --divider: color-mix(in oklab, currentColor 18%, transparent);
+    margin-bottom: 1rem;
 }
 
 .section-header {
@@ -46,7 +48,11 @@
 }
 
 .section-outer {
-    margin-bottom: 1rem;
+    display: flex;
+    flex-direction: column;
+    flex: 1 1 auto;
+    min-height: 0;
+    margin: 0;
 }
 
 .title {
@@ -72,10 +78,12 @@
 }
 
 .section-body {
-    margin-top: 1rem;
-    margin-bottom: 1rem;
-    margin-left: 0;
-    display: block;
+    flex: 1 1 auto;
+    min-height: 0;
+    display: flex;
+    flex-direction: column;
+    margin: 0;
+    padding: 1rem 0;
 }
 
 .section-body-compact {
diff --git a/ui/src/app/core-ui/asset-map/asset-map.component.html 
b/ui/src/app/core-ui/asset-map/asset-map.component.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/src/app/core-ui/asset-map/asset-map.component.ts 
b/ui/src/app/core-ui/asset-map/asset-map.component.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/src/app/home/components/asset-links/home-asset-links.component.html 
b/ui/src/app/home/components/asset-links/home-asset-links.component.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/src/app/home/components/asset-links/home-asset-links.component.scss 
b/ui/src/app/home/components/asset-links/home-asset-links.component.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/src/app/home/components/asset-links/home-asset-links.component.ts 
b/ui/src/app/home/components/asset-links/home-asset-links.component.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git 
a/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.html
 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.html
new file mode 100644
index 0000000000..90c4281c71
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.html
@@ -0,0 +1,26 @@
+<!--
+  ~ 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="link-chip"
+    [style.--link-color]="currentLinkType.linkColor"
+    (click)="openPreview(); $event.stopPropagation()"
+>
+    <i class="material-icons">{{ currentLinkType.linkIcon }}</i>
+    <span class="link-label">{{ assetLink.linkLabel }}</span>
+</div>
diff --git a/ui/src/app/home/components/status.component.scss 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.scss
similarity index 51%
copy from ui/src/app/home/components/status.component.scss
copy to 
ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.scss
index cb8de94ec8..1c50833509 100644
--- a/ui/src/app/home/components/status.component.scss
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,33 +16,40 @@
  *
  */
 
-.status-container {
-    height: 150px;
-    width: 100%;
-    color: var(--color-secondary);
-    border-radius: 10px;
-    margin-bottom: 20px;
-    border: 1px solid var(--color-bg-2);
-    background: var(--color-bg-1);
-}
-
-.status-container-number {
-    font-weight: bold;
-}
-
-.status-container:hover {
+.link-chip {
+    display: flex;
+    align-items: center;
+    gap: 6px;
+    background: color-mix(
+        in srgb,
+        var(--color-bg-0) 85%,
+        var(--link-color) 15%
+    );
+    border: 1px solid #e1e4e8;
+    border-radius: 6px;
+    padding: 4px 6px;
     cursor: pointer;
-    opacity: 0.8;
-}
+    transition: all 0.2s ease;
+    user-select: none;
+    color: var(--link-color, #1d2125);
 
-.status-container-create-link {
-    color: var(--color-primary);
-}
+    &:hover {
+        border-color: var(--link-color, #39b54a);
+        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+    }
 
-.status-container-create-link:hover {
-    font-weight: bold;
-}
+    i {
+        font-size: 16px;
+        color: var(--link-color, #6b778c);
+        transition: color 0.2s;
+    }
 
-.status-container-icon {
-    color: var(--mat-sys-outline-variant);
+    .link-label {
+        font-size: var(--font-size-xs);
+        font-weight: 500;
+        color: inherit;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+    }
 }
diff --git 
a/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.ts
 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.ts
new file mode 100644
index 0000000000..178ce25940
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, inject, Input, OnInit } from '@angular/core';
+import { AssetLink, AssetLinkType } from '@streampipes/platform-services';
+import { FeatureCardService } from '@streampipes/shared-ui';
+
+@Component({
+    selector: 'sp-asset-map-link-chip',
+    templateUrl: './asset-link-chip.component.html',
+    styleUrls: ['./asset-link-chip.component.scss'],
+    standalone: false,
+})
+export class AssetLinkChipComponent implements OnInit {
+    @Input()
+    assetLink: AssetLink;
+
+    @Input()
+    assetLinkTypes: Record<string, AssetLinkType> = {};
+
+    currentLinkType: AssetLinkType;
+
+    private featureCardService = inject(FeatureCardService);
+
+    ngOnInit() {
+        this.currentLinkType = this.assetLinkTypes[this.assetLink.linkType];
+    }
+
+    openPreview(): void {
+        this.featureCardService.openFeatureCard(
+            this.currentLinkType.linkType,
+            this.assetLink.resourceId,
+        );
+    }
+}
diff --git 
a/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.html
 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.html
new file mode 100644
index 0000000000..9a1838623d
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.html
@@ -0,0 +1,68 @@
+<!--
+  ~ 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="sp-map-card">
+    <div class="card-header">
+        <div class="asset-identity">
+            <i class="material-icons">precision_manufacturing</i>
+            <h4 [title]="asset.assetName">{{ asset.assetName }}</h4>
+        </div>
+        <div>
+            <sp-label
+                tone="neutral"
+                variant="soft"
+                [labelText]="isa95Type"
+                size="small"
+            ></sp-label>
+        </div>
+    </div>
+
+    <div class="card-body">
+        <div class="meta-item">
+            <label>{{ 'Location' | translate }}</label>
+            <span>{{ site.label || 'Unknown' }}</span>
+        </div>
+        <div class="meta-item">
+            <label>{{ 'Area' | translate }}</label>
+            <span>{{ asset.assetSite.area || '-' }}</span>
+        </div>
+    </div>
+
+    <div class="card-actions">
+        @if (asset.assetLinks && asset.assetLinks.length > 0) {
+            <div class="link-grid">
+                @for (link of asset.assetLinks; track $index) {
+                    <sp-asset-map-link-chip
+                        [assetLink]="link"
+                        [assetLinkTypes]="assetLinkTypes"
+                    >
+                    </sp-asset-map-link-chip>
+                }
+            </div>
+        } @else {
+            <div class="no-links">
+                <small>{{ 'No linked resources' | translate }}</small>
+            </div>
+        }
+
+        <button mat-flat-button (click)="navigateToAsset()">
+            <mat-icon>arrow_forward</mat-icon>
+            <span>{{ 'Show asset' | translate }}</span>
+        </button>
+    </div>
+</div>
diff --git 
a/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.scss
 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.scss
new file mode 100644
index 0000000000..d91d69b721
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.scss
@@ -0,0 +1,120 @@
+/*!
+ * 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.
+ *
+ */
+
+:host {
+    display: block;
+}
+
+.sp-map-card {
+    width: 380px;
+    background: var(--color-bg-0);
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+}
+
+.card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 1px solid var(--color-bg-2);
+    padding-bottom: 8px;
+}
+
+.asset-identity {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    color: var(--color-default-text);
+
+    i {
+        color: var(--fg-muted);
+        font-size: 1.1rem;
+    }
+
+    h4 {
+        margin: 0;
+        font-size: 1rem;
+        font-weight: 600;
+        color: var(--color-default-text);
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        max-width: 160px;
+    }
+}
+
+.card-body {
+    display: grid;
+    grid-template-columns: 1fr 1fr;
+    gap: 8px;
+}
+
+.meta-item {
+    display: flex;
+    flex-direction: column;
+    color: var(--color-default-text);
+
+    label {
+        font-size: 0.7rem;
+        color: var(--fg-muted);
+        text-transform: uppercase;
+        letter-spacing: 0.5px;
+        margin-bottom: 2px;
+    }
+
+    span {
+        font-size: 0.9rem;
+        color: var(--color-default-text);
+        font-weight: 500;
+    }
+}
+
+.card-actions {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    padding-top: 4px;
+}
+
+.link-grid {
+    display: grid;
+    grid-template-columns: 1fr 1fr;
+    gap: 8px;
+
+    max-height: 100px;
+    overflow-y: auto;
+    padding-right: 4px;
+
+    &::-webkit-scrollbar {
+        width: 4px;
+    }
+    &::-webkit-scrollbar-track {
+        background: transparent;
+    }
+    &::-webkit-scrollbar-thumb {
+        background: #e0e0e0;
+        border-radius: 4px;
+    }
+}
+
+.no-links {
+    text-align: center;
+    color: var(--color-default-text);
+    padding: 4px 0;
+}
diff --git 
a/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.ts
 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.ts
new file mode 100644
index 0000000000..23e4da2ac9
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-map/asset-map-popup/asset-map-popup.component.ts
@@ -0,0 +1,74 @@
+/*
+ * 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,
+    inject,
+    Input,
+    OnInit,
+    Output,
+} from '@angular/core';
+import {
+    AssetLinkType,
+    AssetSiteDesc,
+    Isa95TypeService,
+    SpAssetModel,
+} from '@streampipes/platform-services';
+import { Router } from '@angular/router';
+
+export type PopupAction = 'details' | 'pipelines' | 'dashboards';
+
+@Component({
+    selector: 'sp-asset-map-popup',
+    templateUrl: './asset-map-popup.component.html',
+    styleUrls: ['./asset-map-popup.component.scss'],
+    standalone: false,
+})
+export class AssetMapPopupComponent implements OnInit {
+    @Input()
+    asset: SpAssetModel;
+
+    @Input()
+    site: AssetSiteDesc;
+
+    @Input()
+    assetLinkTypes: Record<string, AssetLinkType> = {};
+
+    @Output() actionClicked = new EventEmitter<PopupAction>();
+
+    isa95Type: string;
+
+    private isa95TypeService = inject(Isa95TypeService);
+    private router = inject(Router);
+
+    ngOnInit() {
+        this.isa95Type = this.isa95TypeService.toLabel(
+            this.asset.assetType.isa95AssetType,
+        );
+    }
+
+    navigateToAsset(): void {
+        this.router.navigate([
+            'assets',
+            'details',
+            this.asset.elementId,
+            'view',
+        ]);
+    }
+}
diff --git a/ui/src/app/home/components/asset-map/home-asset-map.component.html 
b/ui/src/app/home/components/asset-map/home-asset-map.component.html
new file mode 100644
index 0000000000..246c50e621
--- /dev/null
+++ b/ui/src/app/home/components/asset-map/home-asset-map.component.html
@@ -0,0 +1,30 @@
+<!--
+  ~ 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="w-100 leaflet-host"
+    [ngStyle]="{ height: '100%' }"
+    leaflet
+    (leafletClick)="onMarkerClicked($event)"
+    [leafletOptions]="mapOptions"
+    (leafletMapReady)="onMapReady($event)"
+>
+    @for (layer of layers; track layer) {
+        <div [leafletLayer]="layer"></div>
+    }
+</div>
diff --git a/ui/src/app/home/components/status.component.scss 
b/ui/src/app/home/components/asset-map/home-asset-map.component.scss
similarity index 60%
copy from ui/src/app/home/components/status.component.scss
copy to ui/src/app/home/components/asset-map/home-asset-map.component.scss
index cb8de94ec8..f415e60ba1 100644
--- a/ui/src/app/home/components/status.component.scss
+++ b/ui/src/app/home/components/asset-map/home-asset-map.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,33 +16,8 @@
  *
  */
 
-.status-container {
-    height: 150px;
+.leaflet-host {
+    flex: 1 1 auto;
+    min-height: 0;
     width: 100%;
-    color: var(--color-secondary);
-    border-radius: 10px;
-    margin-bottom: 20px;
-    border: 1px solid var(--color-bg-2);
-    background: var(--color-bg-1);
-}
-
-.status-container-number {
-    font-weight: bold;
-}
-
-.status-container:hover {
-    cursor: pointer;
-    opacity: 0.8;
-}
-
-.status-container-create-link {
-    color: var(--color-primary);
-}
-
-.status-container-create-link:hover {
-    font-weight: bold;
-}
-
-.status-container-icon {
-    color: var(--mat-sys-outline-variant);
 }
diff --git a/ui/src/app/home/components/asset-map/home-asset-map.component.ts 
b/ui/src/app/home/components/asset-map/home-asset-map.component.ts
new file mode 100644
index 0000000000..527440762c
--- /dev/null
+++ b/ui/src/app/home/components/asset-map/home-asset-map.component.ts
@@ -0,0 +1,203 @@
+/*
+ * 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,
+    ComponentRef,
+    createComponent,
+    EnvironmentInjector,
+    inject,
+    Input,
+    OnInit,
+} from '@angular/core';
+import {
+    AssetLinkType,
+    AssetSiteDesc,
+    LatLng,
+    LocationConfig,
+    SpAssetModel,
+} from '@streampipes/platform-services';
+import {
+    icon,
+    latLng,
+    latLngBounds,
+    LatLngBounds,
+    LatLngExpression,
+    Layer,
+    LeafletMouseEvent,
+    Map,
+    MapOptions,
+    marker,
+    Marker,
+    popup,
+} from 'leaflet';
+import { MapLayerProviderService } from 
'../../../core-ui/services/map-layer-provider.service';
+import {
+    AssetMapPopupComponent,
+    PopupAction,
+} from './asset-map-popup/asset-map-popup.component';
+
+@Component({
+    selector: 'sp-home-asset-map',
+    templateUrl: './home-asset-map.component.html',
+    styleUrls: ['./home-asset-map.component.scss'],
+    standalone: false,
+})
+export class HomeAssetMapComponent implements OnInit {
+    @Input()
+    locationConfig: LocationConfig;
+
+    @Input()
+    assets: SpAssetModel[] = [];
+
+    @Input()
+    sites: Record<string, AssetSiteDesc> = {};
+
+    @Input()
+    assetLinkTypes: Record<string, AssetLinkType> = {};
+
+    map: Map;
+    mapOptions: MapOptions;
+    layers: Layer[];
+    marker: Marker;
+    bounds: LatLngBounds;
+
+    private currentPopupRef: ComponentRef<AssetMapPopupComponent> | null = 
null;
+
+    private mapLayerProviderService = inject(MapLayerProviderService);
+    private injector = inject(EnvironmentInjector);
+
+    ngOnInit() {
+        const result = this.getCenterAndBounds();
+        this.bounds = result.bounds;
+
+        this.mapOptions = {
+            layers: this.mapLayerProviderService.getMapLayers(
+                this.locationConfig,
+            ),
+            zoom: 10,
+            zoomControl: true,
+            center: result.center,
+        };
+    }
+
+    getCenterAndBounds(): { center: LatLngExpression; bounds: L.LatLngBounds } 
{
+        const latLngs = this.assets
+            .filter(a => a.assetSite !== null)
+            .map(s => s.assetSite.siteId)
+            .map(s => this.sites[s])
+            .map(s => s.location.coordinates)
+            .map(coordinates =>
+                latLng(coordinates.latitude, coordinates.longitude),
+            );
+
+        if (latLngs.length === 0) {
+            return {
+                center: { lat: 0, lng: 0 },
+                bounds: latLngBounds([
+                    [0, 0],
+                    [0, 0],
+                ]),
+            };
+        }
+
+        const bounds = latLngBounds(latLngs);
+        return { center: bounds.getCenter(), bounds };
+    }
+
+    onMapReady(map: Map) {
+        this.map = map;
+        this.map.attributionControl.setPrefix('');
+        this.createMarkers();
+
+        setTimeout(() => {
+            map.invalidateSize();
+            if (this.bounds && this.bounds.isValid()) {
+                map.fitBounds(this.bounds, { padding: [24, 24] });
+            }
+        }, 0);
+    }
+
+    createMarkers(): void {
+        const assetsWithSite = this.assets.filter(a => a.assetSite !== null);
+
+        assetsWithSite.forEach(asset => {
+            const site = this.sites[asset.assetSite.siteId];
+            const assetLocation = site.location.coordinates;
+            const marker = this.makeMarker({
+                latitude: assetLocation.latitude,
+                longitude: assetLocation.longitude,
+            });
+            marker.on('click', (e: LeafletMouseEvent) => {
+                this.openPopup(e, asset, site);
+            });
+            marker.addTo(this.map);
+        });
+    }
+
+    makeMarker(location: LatLng): Marker {
+        return marker(
+            { lat: location.latitude, lng: location.longitude },
+            {
+                icon: icon({
+                    iconSize: [25, 41],
+                    iconAnchor: [13, 41],
+                    iconUrl: 'assets/img/marker-icon.png',
+                    shadowUrl: 'assets/img/marker-shadow.png',
+                }),
+            },
+        );
+    }
+
+    openPopup(
+        event: LeafletMouseEvent,
+        asset: SpAssetModel,
+        site: AssetSiteDesc,
+    ) {
+        this.currentPopupRef = createComponent(AssetMapPopupComponent, {
+            environmentInjector: this.injector,
+        });
+
+        this.currentPopupRef.instance.asset = asset;
+        this.currentPopupRef.instance.site = site;
+        this.currentPopupRef.instance.assetLinkTypes = this.assetLinkTypes;
+
+        this.currentPopupRef.instance.actionClicked.subscribe(
+            (action: PopupAction) => {
+                this.handlePopupAction(action, asset);
+            },
+        );
+
+        this.currentPopupRef.changeDetectorRef.detectChanges();
+        const popupContent = this.currentPopupRef.location.nativeElement;
+
+        popup({
+            offset: [0, -20],
+            minWidth: 380,
+            closeButton: false,
+            className: 'sp-leaflet-popup-clean',
+        })
+            .setLatLng(event.latlng)
+            .setContent(popupContent)
+            .openOn(this.map);
+    }
+
+    handlePopupAction(action: PopupAction, asset: SpAssetModel) {}
+
+    onMarkerClicked(e: LeafletMouseEvent) {}
+}
diff --git 
a/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.html
 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.html
new file mode 100644
index 0000000000..1eac4b94ae
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.html
@@ -0,0 +1,31 @@
+<!--
+  ~ 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.
+  ~
+  -->
+
+<button
+    type="button"
+    class="link-chip"
+    [style.--link-color]="currentLinkType.linkColor"
+    (click)="openPreview(); $event.stopPropagation()"
+    [attr.aria-label]="assetLink.linkLabel"
+>
+    <i class="material-icons link-icon">{{ currentLinkType.linkIcon }}</i>
+
+    <span class="chip-expander">
+        <span class="link-label">{{ assetLink.linkLabel }}</span>
+    </span>
+</button>
diff --git 
a/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.scss
 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.scss
new file mode 100644
index 0000000000..b486204c07
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.scss
@@ -0,0 +1,114 @@
+/*!
+ * 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.
+ *
+ */
+
+.link-chip {
+    --lc: var(--link-color, #6b778c);
+
+    position: relative;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+
+    height: 28px;
+    padding: 4px 6px;
+
+    background: color-mix(in srgb, var(--color-bg-0) 85%, var(--lc) 15%);
+    border: 1px solid #e1e4e8;
+    border-radius: 6px;
+
+    cursor: pointer;
+    user-select: none;
+    color: var(--lc);
+
+    z-index: 0;
+
+    transition:
+        border-color 0.2s ease,
+        box-shadow 0.2s ease,
+        transform 0.15s ease;
+
+    &:hover,
+    &:focus-visible {
+        border-color: var(--lc);
+        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+        transform: translateY(-1px);
+        z-index: 50;
+        outline: none;
+    }
+
+    .link-icon {
+        font-size: 16px;
+        line-height: 1;
+        color: var(--lc);
+        position: relative;
+        z-index: 3;
+    }
+
+    .chip-expander {
+        position: absolute;
+        left: -1px;
+        top: -1px;
+        height: calc(100% + 2px);
+
+        width: max-content;
+        max-width: 340px;
+
+        display: inline-flex;
+        align-items: center;
+
+        padding-left: calc(6px + 16px + 6px);
+        padding-right: 10px;
+
+        border-radius: 6px;
+        background: color-mix(in srgb, #ffffff 85%, var(--lc) 15%);
+        border: 1px solid #e1e4e8;
+
+        box-sizing: border-box;
+        pointer-events: none;
+        clip-path: inset(0 100% 0 0 round 6px);
+        opacity: 0;
+
+        transition:
+            clip-path 220ms ease,
+            opacity 120ms ease,
+            box-shadow 220ms ease,
+            border-color 220ms ease;
+
+        z-index: 2;
+    }
+
+    .link-label {
+        font-size: var(--font-size-xs);
+        font-weight: 500;
+        color: var(--lc);
+
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        max-width: 260px;
+    }
+
+    &:hover .chip-expander,
+    &:focus-visible .chip-expander {
+        opacity: 1;
+        clip-path: inset(0 0 0 0 round 6px);
+        border-color: var(--lc);
+        box-shadow: 0 8px 18px rgba(0, 0, 0, 0.1);
+    }
+}
diff --git 
a/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.ts
 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.ts
new file mode 100644
index 0000000000..8981b9167a
--- /dev/null
+++ 
b/ui/src/app/home/components/asset-table/asset-table-link-preview/asset-table-link-preview.component.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, inject, Input, OnInit } from '@angular/core';
+import { AssetLink, AssetLinkType } from '@streampipes/platform-services';
+import { FeatureCardService } from '@streampipes/shared-ui';
+
+@Component({
+    selector: 'sp-asset-table-link-preview',
+    templateUrl: './asset-table-link-preview.component.html',
+    styleUrls: ['./asset-table-link-preview.component.scss'],
+    standalone: false,
+})
+export class AssetTableLinkPreviewComponent implements OnInit {
+    @Input()
+    assetLink: AssetLink;
+
+    @Input()
+    assetLinkTypes: Record<string, AssetLinkType> = {};
+
+    currentLinkType: AssetLinkType;
+
+    private featureCardService = inject(FeatureCardService);
+
+    ngOnInit() {
+        this.currentLinkType = this.assetLinkTypes[this.assetLink.linkType];
+    }
+
+    openPreview(): void {
+        this.featureCardService.openFeatureCard(
+            this.currentLinkType.linkType,
+            this.assetLink.resourceId,
+        );
+    }
+}
diff --git 
a/ui/src/app/home/components/asset-table/home-asset-table.component.html 
b/ui/src/app/home/components/asset-table/home-asset-table.component.html
new file mode 100644
index 0000000000..ab147fef02
--- /dev/null
+++ b/ui/src/app/home/components/asset-table/home-asset-table.component.html
@@ -0,0 +1,78 @@
+<!--
+  ~ 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-table
+    fxFlex="100"
+    [columns]="displayedColumns"
+    [dataSource]="dataSource"
+    [showActionsMenu]="true"
+    [rowsClickable]="true"
+    (rowClicked)="navigateToAsset($event)"
+    matSort
+>
+    <ng-container matColumnDef="assetName">
+        <th mat-header-cell mat-sort-header *matHeaderCellDef>Asset</th>
+        <td mat-cell *matCellDef="let asset">
+            <span class="cell-nowrap">{{ asset.assetName }}</span>
+        </td>
+    </ng-container>
+
+    <ng-container matColumnDef="assetType">
+        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+            {{ 'Type' | translate }}
+        </th>
+        <td mat-cell *matCellDef="let asset">
+            <span class="cell-nowrap">{{ getIsa95Type(asset) }}</span>
+        </td>
+    </ng-container>
+
+    <ng-container matColumnDef="location">
+        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+            {{ 'Location' | translate }}
+        </th>
+        <td mat-cell *matCellDef="let asset">
+            <span class="cell-nowrap">{{ getSite(asset) }}</span>
+        </td>
+    </ng-container>
+
+    <ng-container matColumnDef="area">
+        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+            {{ 'Area' | translate }}
+        </th>
+        <td mat-cell *matCellDef="let asset">
+            <span class="cell-nowrap">{{ asset.assetSite?.area || '-' }}</span>
+        </td>
+    </ng-container>
+
+    <ng-container matColumnDef="assetLinks">
+        <th mat-header-cell mat-sort-header *matHeaderCellDef>
+            {{ 'Links' | translate }}
+        </th>
+        <td mat-cell *matCellDef="let asset" class="cell-links">
+            <div class="asset-links p-sm">
+                @for (link of asset.assetLinks; track $index) {
+                    <sp-asset-table-link-preview
+                        [assetLink]="link"
+                        [assetLinkTypes]="assetLinkTypes"
+                    >
+                    </sp-asset-table-link-preview>
+                }
+            </div>
+        </td>
+    </ng-container>
+</sp-table>
diff --git a/ui/src/app/home/components/status.component.scss 
b/ui/src/app/home/components/asset-table/home-asset-table.component.scss
similarity index 59%
copy from ui/src/app/home/components/status.component.scss
copy to ui/src/app/home/components/asset-table/home-asset-table.component.scss
index cb8de94ec8..d044d3c589 100644
--- a/ui/src/app/home/components/status.component.scss
+++ b/ui/src/app/home/components/asset-table/home-asset-table.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,33 +16,16 @@
  *
  */
 
-.status-container {
-    height: 150px;
-    width: 100%;
-    color: var(--color-secondary);
-    border-radius: 10px;
-    margin-bottom: 20px;
-    border: 1px solid var(--color-bg-2);
-    background: var(--color-bg-1);
+.asset-links {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 5px 5px;
+    align-items: center;
 }
 
-.status-container-number {
-    font-weight: bold;
-}
-
-.status-container:hover {
-    cursor: pointer;
-    opacity: 0.8;
-}
-
-.status-container-create-link {
-    color: var(--color-primary);
-}
-
-.status-container-create-link:hover {
-    font-weight: bold;
-}
-
-.status-container-icon {
-    color: var(--mat-sys-outline-variant);
+.cell-nowrap {
+    display: block;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
 }
diff --git 
a/ui/src/app/home/components/asset-table/home-asset-table.component.ts 
b/ui/src/app/home/components/asset-table/home-asset-table.component.ts
new file mode 100644
index 0000000000..bbd401ff61
--- /dev/null
+++ b/ui/src/app/home/components/asset-table/home-asset-table.component.ts
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, inject, Input, OnInit, ViewChild } from '@angular/core';
+import {
+    AssetLinkType,
+    AssetSiteDesc,
+    Isa95TypeService,
+    LocationConfig,
+    SpAssetModel,
+} from '@streampipes/platform-services';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { Router } from '@angular/router';
+
+@Component({
+    selector: 'sp-home-asset-table',
+    templateUrl: './home-asset-table.component.html',
+    styleUrls: ['./home-asset-table.component.scss'],
+    standalone: false,
+})
+export class HomeAssetTableComponent implements OnInit {
+    @Input()
+    locationConfig: LocationConfig;
+
+    @Input()
+    assets: SpAssetModel[] = [];
+
+    @Input()
+    sites: Record<string, AssetSiteDesc> = {};
+
+    @Input()
+    assetLinkTypes: Record<string, AssetLinkType> = {};
+
+    displayedColumns: string[] = [
+        'assetName',
+        'assetType',
+        'location',
+        'area',
+        'assetLinks',
+    ];
+
+    @ViewChild(MatSort)
+    sort: MatSort;
+
+    dataSource: MatTableDataSource<SpAssetModel> =
+        new MatTableDataSource<SpAssetModel>();
+
+    private isa95TypeService = inject(Isa95TypeService);
+    private router = inject(Router);
+
+    ngOnInit() {
+        this.dataSource.data = this.assets;
+    }
+
+    getIsa95Type(asset: SpAssetModel): string {
+        return this.isa95TypeService.toLabel(asset.assetType?.isa95AssetType);
+    }
+
+    getSite(asset: SpAssetModel): string {
+        if (!asset.assetSite?.siteId) {
+            return '-';
+        } else {
+            return this.sites[asset.assetSite.siteId].label;
+        }
+    }
+
+    getArea(asset: SpAssetModel): string {
+        if (!asset.assetSite?.siteId) {
+            return '-';
+        } else {
+            return asset.assetSite.area;
+        }
+    }
+
+    navigateToAsset(asset: SpAssetModel): void {
+        this.router.navigate(['assets', 'details', asset.elementId, 'view']);
+    }
+}
diff --git a/ui/src/app/home/components/status.component.html 
b/ui/src/app/home/components/status.component.html
index 79879b43f6..e37497d5c4 100644
--- a/ui/src/app/home/components/status.component.html
+++ b/ui/src/app/home/components/status.component.html
@@ -16,40 +16,25 @@
 ~
 -->
 
-<div
-    fxFlex="100"
-    class="status-container p-10"
-    (click)="navigate(statusBox.link)"
->
-    <div fxLayout="row" fxFlex="100">
-        <div fxFlex fxLayout="column" fxLayoutAlign="start start">
-            <div fxFlex fxLayout="column">
-                <div class="status-container-number text-3xl">
-                    <span>{{ resourceCount }}</span>
-                </div>
-                <div class="text-xl" fxFlex fxLayoutAlign="end end">
-                    <span>{{ statusBox.title }}</span>
-                </div>
-            </div>
-            <div fxFlex="100" fxLayoutAlign="end end" class="w-100">
-                @if (showCreateLink) {
-                    <div fxFlex="100" fxLayoutAlign="start center">
-                        <a
-                            (click)="navigate(statusBox.createLink)"
-                            fxLayoutAlign="start center"
-                            class="status-container-create-link text-md"
-                        >
-                            <i class="material-icons">add_circle</i>
-                            <span>&nbsp;{{ statusBox.createTitle }}</span>
-                        </a>
-                    </div>
-                }
-            </div>
+<div class="status-container" (click)="navigate(statusBox.link)">
+    <div class="status-content p-sm">
+        <div class="status-main">
+            <div class="status-number">{{ resourceCount }}</div>
+            <div class="status-title">{{ statusBox.title }}</div>
+
+            @if (showCreateLink) {
+                <a
+                    class="status-action"
+                    (click)="
+                        $event.stopPropagation(); 
navigate(statusBox.createLink)
+                    "
+                >
+                    <i class="material-icons">add_circle</i>
+                    <span>{{ 'New' | translate }}</span>
+                </a>
+            }
         </div>
-    </div>
-    <div fxLayoutAlign="start start">
-        <i class="material-icons status-container-icon text-5xl">{{
-            statusBox.icon
-        }}</i>
+
+        <i class="material-icons status-icon">{{ statusBox.icon }}</i>
     </div>
 </div>
diff --git a/ui/src/app/home/components/status.component.scss 
b/ui/src/app/home/components/status.component.scss
index cb8de94ec8..95f3fa93f4 100644
--- a/ui/src/app/home/components/status.component.scss
+++ b/ui/src/app/home/components/status.component.scss
@@ -16,33 +16,132 @@
  *
  */
 
+:host {
+    --status-box-color: #2c3e50;
+    --status-box-bg: color-mix(
+        in srgb,
+        var(--status-box-color) 14%,
+        var(--color-bg-0)
+    );
+}
+
 .status-container {
-    height: 150px;
     width: 100%;
-    color: var(--color-secondary);
-    border-radius: 10px;
+    box-sizing: border-box;
+
+    min-height: 112px;
+    height: auto;
+
+    border-radius: 14px;
     margin-bottom: 20px;
+
     border: 1px solid var(--color-bg-2);
-    background: var(--color-bg-1);
+    background: var(--status-box-bg);
+    color: var(--status-box-color);
+
+    transition:
+        transform 160ms ease,
+        box-shadow 160ms ease,
+        border-color 160ms ease;
+    position: relative;
+    overflow: hidden;
 }
 
-.status-container-number {
-    font-weight: bold;
+/* Inner layout */
+.status-content {
+    height: 100%;
+    display: grid;
+    grid-template-columns: 1fr auto;
+    align-items: center;
+    gap: 16px;
 }
 
-.status-container:hover {
-    cursor: pointer;
-    opacity: 0.8;
+/* Left column */
+.status-main {
+    display: grid;
+    gap: 6px;
+    align-content: center;
+    min-width: 0; /* allows text truncation */
+}
+
+.status-number {
+    font-weight: 700;
+    font-size: 2rem; /* ~text-3xl */
+    line-height: 1;
+    letter-spacing: -0.02em;
 }
 
-.status-container-create-link {
-    color: var(--color-primary);
+.status-title {
+    font-weight: 600;
+    font-size: 1rem;
+    opacity: 0.9;
+
+    /* avoid overflow on long titles */
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* Action link */
+.status-action {
+    display: inline-flex;
+    align-items: center;
+    gap: 8px;
+
+    margin-top: 6px;
+    width: fit-content;
+
+    color: var(--status-box-color);
+    text-decoration: none;
+
+    font-weight: 600;
+    font-size: 0.9rem;
+    opacity: 0.9;
+
+    padding: 6px 10px;
+    border-radius: 999px;
+
+    /* subtle “chip” feel without changing colors */
+    background: color-mix(in srgb, var(--status-box-color) 8%, transparent);
+    transition:
+        transform 160ms ease,
+        opacity 160ms ease,
+        background 160ms ease;
+}
+
+.status-action .material-icons {
+    font-size: 18px;
+    line-height: 1;
+}
+
+/* Right icon */
+.status-icon {
+    font-size: 52px; /* big but not overpowering */
+    color: var(--status-box-color);
+    opacity: 0.5;
+    line-height: 1;
+    justify-self: end;
+
+    /* keep the icon visually tucked in */
+    transform: translateY(2px);
+    pointer-events: none;
+}
+
+/* Hover / active */
+.status-container:hover {
+    cursor: pointer;
+    opacity: 1;
+    transform: translateY(-2px);
 }
 
-.status-container-create-link:hover {
-    font-weight: bold;
+.status-container:active {
+    transform: translateY(-1px);
+    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
 }
 
-.status-container-icon {
-    color: var(--mat-sys-outline-variant);
+/* Action hover */
+.status-action:hover {
+    opacity: 1;
+    transform: translateY(-1px);
+    background: color-mix(in srgb, var(--status-box-color) 12%, transparent);
 }
diff --git a/ui/src/app/home/components/status.component.ts 
b/ui/src/app/home/components/status.component.ts
index 183ce3cb89..fc6fe103de 100644
--- a/ui/src/app/home/components/status.component.ts
+++ b/ui/src/app/home/components/status.component.ts
@@ -16,9 +16,9 @@
  *
  */
 
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, HostBinding, inject, Input, OnInit } from '@angular/core';
 import { Router } from '@angular/router';
-import { UserInfo } from '@streampipes/platform-services';
+import { AssetLinkType, UserInfo } from '@streampipes/platform-services';
 import { StatusBox } from '../models/home.model';
 import { UserRole } from '../../_enums/user-role.enum';
 import { zip } from 'rxjs';
@@ -39,11 +39,18 @@ export class StatusComponent implements OnInit {
     @Input()
     currentUser: UserInfo;
 
+    @Input()
+    assetLinkType: AssetLinkType;
+
+    @HostBinding('style.--status-box-color') statusBoxColor: string | null =
+        null;
+
     showCreateLink = true;
 
-    constructor(private router: Router) {}
+    private router = inject(Router);
 
     ngOnInit() {
+        this.statusBoxColor = this.assetLinkType.linkColor;
         zip(this.statusBox.dataFns).subscribe(res => {
             let totalLength = 0;
             res.forEach(response => {
@@ -52,6 +59,7 @@ export class StatusComponent implements OnInit {
 
             this.resourceCount = totalLength;
         });
+
         this.showCreateLink = this.shouldShowCreateLink();
     }
 
diff --git a/ui/src/app/home/components/welcome/welcome.component.html 
b/ui/src/app/home/components/welcome/welcome.component.html
new file mode 100644
index 0000000000..0aeaf8f62a
--- /dev/null
+++ b/ui/src/app/home/components/welcome/welcome.component.html
@@ -0,0 +1,24 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<sp-basic-header-title-component
+    [level]="1"
+    title="{{ greeting }}{{ displayName ? ',' : '' }} {{
+        displayName || email
+    }}!"
+></sp-basic-header-title-component>
diff --git a/ui/src/app/home/components/status.component.scss 
b/ui/src/app/home/components/welcome/welcome.component.scss
similarity index 60%
copy from ui/src/app/home/components/status.component.scss
copy to ui/src/app/home/components/welcome/welcome.component.scss
index cb8de94ec8..d9b0846cd9 100644
--- a/ui/src/app/home/components/status.component.scss
+++ b/ui/src/app/home/components/welcome/welcome.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,33 +16,29 @@
  *
  */
 
-.status-container {
-    height: 150px;
-    width: 100%;
-    color: var(--color-secondary);
-    border-radius: 10px;
-    margin-bottom: 20px;
-    border: 1px solid var(--color-bg-2);
-    background: var(--color-bg-1);
+.home-header {
+    margin-bottom: 24px;
+    padding: 4px 0;
 }
 
-.status-container-number {
-    font-weight: bold;
+.home-header-text {
+    display: flex;
+    flex-direction: column;
+    gap: 4px;
 }
 
-.status-container:hover {
-    cursor: pointer;
-    opacity: 0.8;
-}
+.home-title {
+    margin: 0;
 
-.status-container-create-link {
-    color: var(--color-primary);
+    font-size: var(--font-size-xl);
+    color: var(--color-text-primary, #0f172a);
 }
 
-.status-container-create-link:hover {
-    font-weight: bold;
-}
+.home-subtitle {
+    margin: 0;
+
+    font-size: var(--font-size-sm);
+    font-weight: 500;
 
-.status-container-icon {
-    color: var(--mat-sys-outline-variant);
+    color: var(--color-text-secondary, #64748b);
 }
diff --git a/ui/src/app/home/components/welcome/welcome.component.ts 
b/ui/src/app/home/components/welcome/welcome.component.ts
new file mode 100644
index 0000000000..2980a8981b
--- /dev/null
+++ b/ui/src/app/home/components/welcome/welcome.component.ts
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, inject, Input } from '@angular/core';
+import { UserInfo } from '@streampipes/platform-services';
+import { TranslateService } from '@ngx-translate/core';
+
+@Component({
+    selector: 'sp-welcome',
+    templateUrl: './welcome.component.html',
+    styleUrls: ['./welcome.component.scss'],
+    standalone: false,
+})
+export class WelcomeComponent {
+    @Input()
+    user: UserInfo;
+
+    private translate = inject(TranslateService);
+
+    get displayName(): string | null {
+        return this.user?.displayName?.trim() || null;
+    }
+
+    get email(): string {
+        return this.user?.username ?? '';
+    }
+
+    get greeting(): string {
+        const hour = new Date().getHours();
+        if (hour < 12) return this.translate.instant('Good morning');
+        if (hour < 18) return this.translate.instant('Good afternoon');
+        return this.translate.instant('Good evening');
+    }
+}
diff --git a/ui/src/app/home/home.component.html 
b/ui/src/app/home/home.component.html
index 451496cfab..96f390aebc 100644
--- a/ui/src/app/home/home.component.html
+++ b/ui/src/app/home/home.component.html
@@ -16,73 +16,69 @@
 ~
 -->
 
-<sp-basic-view [hideNavbar]="true">
-    <div fxFlex fxLayout="row" fxLayoutAlign="start start">
-        <div fxFlex="100">
-            <div fxFlex="100" fxLayout="column">
-                <div class="p-10 header-margin" fxLayoutAlign="center center">
-                    <span class="text-3xl font-bold"
-                        >{{ 'Welcome' | translate }}!</span
+<div fxLayout="column" class="page-container page-container-no-bg">
+    @if (currentUser) {
+        <sp-welcome [user]="currentUser"></sp-welcome>
+    }
+    @if (showStatus) {
+        <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="10px">
+            @for (box of statusBoxes; track box) {
+                <sp-status
+                    [fxFlex]="100 / statusBoxes.length"
+                    [statusBox]="box"
+                    [assetLinkType]="assetLinkTypes[box.assetLinkTypeId]"
+                    [currentUser]="currentUser"
+                ></sp-status>
+            }
+        </div>
+    }
+    <div fxFlex class="assets-wrapper">
+        @if (contentLoaded) {
+            <sp-split-section
+                fxFlex
+                [level]="2"
+                [title]="'Assets' | translate"
+                class="asset-section"
+            >
+                <div section-actions>
+                    <mat-button-toggle-group
+                        name="Asset view"
+                        aria-label="Asset view mode"
+                        [(ngModel)]="selectedView"
                     >
+                        <mat-button-toggle
+                            value="map"
+                            [disabled]="
+                                !locationConfig ||
+                                !locationConfig.locationEnabled
+                            "
+                            >{{ 'Map' | translate }}
+                        </mat-button-toggle>
+                        <mat-button-toggle value="table">{{
+                            'Table' | translate
+                        }}</mat-button-toggle>
+                    </mat-button-toggle-group>
                 </div>
-                <div fxLayout="column" fxFlex="100" class="home-margin">
-                    @if (showStatus) {
-                        <div
-                            fxFlex="100"
-                            fxLayout="row"
-                            fxLayoutAlign="start center"
-                            fxLayoutGap="10px"
+                <div fxFlexFill fxLayout="column" class="assets-content">
+                    @if (selectedView === 'map') {
+                        <sp-home-asset-map
+                            class="h-100 map"
+                            [assetLinkTypes]="assetLinkTypes"
+                            [sites]="sites"
+                            [locationConfig]="locationConfig"
+                            [assets]="assets"
+                        ></sp-home-asset-map>
+                    } @else {
+                        <sp-home-asset-table
+                            [assetLinkTypes]="assetLinkTypes"
+                            [sites]="sites"
+                            [locationConfig]="locationConfig"
+                            [assets]="assets"
                         >
-                            @for (box of statusBoxes; track box) {
-                                <sp-status
-                                    [fxFlex]="100 / statusBoxes.length"
-                                    [statusBox]="box"
-                                    [currentUser]="currentUser"
-                                ></sp-status>
-                            }
-                        </div>
+                        </sp-home-asset-table>
                     }
-                    <div fxFlex="100">
-                        <sp-basic-inner-panel
-                            innerPadding="0"
-                            panelTitle="{{ appConstants.APP_NAME }} Modules"
-                        >
-                            <div fxFlex="100" fxLayout="column">
-                                <mat-list class="modules-list">
-                                    @for (link of serviceLinks; track link) {
-                                        <mat-list-item
-                                            (click)="openLink(link)"
-                                            class="list-item"
-                                        >
-                                            <div
-                                                matListItemAvatar
-                                                class="pipeline-avatar 
sp-primary-bg"
-                                            >
-                                                <mat-icon>{{
-                                                    link.icon
-                                                }}</mat-icon>
-                                            </div>
-                                            <span
-                                                class="text-md font-bold"
-                                                matListItemTitle
-                                            >
-                                                {{ link.name }}
-                                            </span>
-                                            <span
-                                                matListItemLine
-                                                class="text-sm font-medium"
-                                            >
-                                                {{ link.description }}
-                                            </span>
-                                            <mat-divider></mat-divider>
-                                        </mat-list-item>
-                                    }
-                                </mat-list>
-                            </div>
-                        </sp-basic-inner-panel>
-                    </div>
                 </div>
-            </div>
-        </div>
+            </sp-split-section>
+        }
     </div>
-</sp-basic-view>
+</div>
diff --git a/ui/src/app/home/home.component.scss 
b/ui/src/app/home/home.component.scss
index 9486e96739..22f5d440ab 100644
--- a/ui/src/app/home/home.component.scss
+++ b/ui/src/app/home/home.component.scss
@@ -16,76 +16,21 @@
  *
  */
 
-.mt-0 {
-    margin-top: 0;
+.assets-wrapper,
+.assets-content {
+    flex: 1 1 auto;
+    min-height: 0; /* super important so children can fill and scroll 
correctly */
 }
 
-.round-border {
-    border-top-left-radius: 5px;
-    border-top-right-radius: 5px;
+.assets-wrapper > .section-body {
+    height: 100%;
 }
 
-.header-margin {
-    margin-top: 20px;
+.asset-section {
+    background: var(--color-bg-0);
 }
 
-.welcome-primary {
-    color: var(--color-secondary);
-}
-
-.welcome-accent {
-    color: var(--color-primary);
-}
-
-.home-margin {
-    margin: 10px;
-}
-
-.home-padding {
-    padding: 15px;
-}
-
-.p-10 {
-    padding: 10px;
-}
-
-.home-image-small {
-    height: 150px;
-    width: 100%;
-}
-
-.pipeline-avatar {
-    align-items: center;
-    justify-content: center;
-    display: flex;
-    color: white;
-}
-
-.mdc-list-item--with-leading-avatar .mat-mdc-list-item-avatar {
-    border-radius: 50%;
-    background-color: var(--color-primary);
-}
-
-.pt-0 {
-    padding-top: 0;
-}
-
-::ng-deep .modules-list.mat-list-base {
-    padding-top: 0;
-}
-
-.list-item:nth-child(even) {
-    background-color: var(--color-bg-1);
-}
-.list-item:nth-child(odd) {
-    background-color: var(--color-bg-0);
-}
-
-.list-item:hover {
-    background-color: var(--color-bg-2);
-    cursor: pointer;
-}
-
-.list-item {
-    --mdc-list-list-item-two-line-container-height: 68px;
+.map {
+    flex: 1 1 auto;
+    min-height: 0;
 }
diff --git a/ui/src/app/home/home.component.ts 
b/ui/src/app/home/home.component.ts
index c03da1fb70..7c2e3ce022 100644
--- a/ui/src/app/home/home.component.ts
+++ b/ui/src/app/home/home.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, OnInit } from '@angular/core';
+import { Component, inject, OnInit } from '@angular/core';
 import { HomeService } from './home.service';
 import { Router } from '@angular/router';
 import { AppConstants } from '../services/app.constants';
@@ -33,13 +33,19 @@ import { ShepherdService } from 
'../services/tour/shepherd.service';
 import {
     AdapterDescription,
     AdapterService,
+    AssetConstants,
+    AssetLinkType,
+    AssetManagementService,
+    AssetSiteDesc,
+    GenericStorageService,
+    LocationConfig,
+    LocationConfigService,
     NamedStreamPipesEntity,
-    Pipeline,
     PipelineElementService,
-    PipelineService,
+    SpAssetModel,
     UserInfo,
 } from '@streampipes/platform-services';
-import { zip } from 'rxjs';
+import { forkJoin, zip } from 'rxjs';
 import { StatusBox } from './models/home.model';
 
 @Component({
@@ -53,10 +59,12 @@ export class HomeComponent implements OnInit {
 
     availablePipelineElements: NamedStreamPipesEntity[] = [];
     availableAdapters: AdapterDescription[] = [];
-    availablePipelines: Pipeline[] = [];
-    runningPipelines: Pipeline[] = [];
 
     statusBoxes: StatusBox[] = [];
+    locationConfig: LocationConfig;
+    assets: SpAssetModel[] = [];
+    sites: Record<string, AssetSiteDesc> = {};
+    assetLinkTypes: Record<string, AssetLinkType> = {};
 
     requiredAdapterForTutorialAppId: any =
         'org.apache.streampipes.connect.iiot.adapters.simulator.machine';
@@ -68,19 +76,23 @@ export class HomeComponent implements OnInit {
 
     isTutorialOpen = false;
     currentUser: UserInfo;
-
-    constructor(
-        private homeService: HomeService,
-        private currentUserService: CurrentUserService,
-        private router: Router,
-        public appConstants: AppConstants,
-        private breadcrumbService: SpBreadcrumbService,
-        private dialogService: DialogService,
-        private shepherdService: ShepherdService,
-        private pipelineService: PipelineService,
-        private pipelineElementService: PipelineElementService,
-        private adapterService: AdapterService,
-    ) {
+    selectedView = 'table';
+    contentLoaded = false;
+
+    private homeService = inject(HomeService);
+    private currentUserService = inject(CurrentUserService);
+    private router = inject(Router);
+    public appConstants = inject(AppConstants);
+    private breadcrumbService = inject(SpBreadcrumbService);
+    private dialogService = inject(DialogService);
+    private shepherdService = inject(ShepherdService);
+    private pipelineElementService = inject(PipelineElementService);
+    private adapterService = inject(AdapterService);
+    private genericStorageService = inject(GenericStorageService);
+    private locationService = inject(LocationConfigService);
+    private assetService = inject(AssetManagementService);
+
+    constructor() {
         this.serviceLinks = this.homeService.getFilteredServiceLinks();
         this.statusBoxes = this.homeService
             .getFilteredServiceLinks()
@@ -91,7 +103,27 @@ export class HomeComponent implements OnInit {
     ngOnInit() {
         this.currentUser = this.currentUserService.getCurrentUser();
         const isAdmin = this.hasRole(UserRole.ROLE_ADMIN);
-        this.showStatus = true;
+        forkJoin([
+            this.genericStorageService.getAllDocuments(
+                AssetConstants.ASSET_LINK_TYPES_DOC_NAME,
+            ),
+            this.locationService.getLocationConfig(),
+            this.assetService.getAllAssets(),
+            this.genericStorageService.getAllDocuments(
+                AssetConstants.ASSET_SITES_APP_DOC_NAME,
+            ),
+        ]).subscribe(res => {
+            res[0].forEach(doc => {
+                this.assetLinkTypes[doc.linkType] = doc;
+            });
+            this.locationConfig = res[1];
+            this.assets = res[2];
+            res[3].forEach(doc => {
+                this.sites[doc._id] = doc;
+            });
+            this.contentLoaded = true;
+            this.showStatus = true;
+        });
         if (isAdmin) {
             this.loadResources();
         }
@@ -102,14 +134,6 @@ export class HomeComponent implements OnInit {
         return this.currentUser.roles.indexOf(role) > -1;
     }
 
-    openLink(link) {
-        if (link.link.newWindow) {
-            window.open(link.link.value);
-        } else {
-            this.router.navigate([link.link.value]);
-        }
-    }
-
     checkForTutorial() {
         if (this.currentUser.showTutorial) {
             if (this.requiredPipelineElementsForTourPresent()) {
@@ -209,19 +233,16 @@ export class HomeComponent implements OnInit {
 
     loadResources(): void {
         zip(
-            this.pipelineService.getPipelines(),
             this.adapterService.getAdapterDescriptions(),
             this.pipelineElementService.getDataStreams(),
             this.pipelineElementService.getDataProcessors(),
             this.pipelineElementService.getDataSinks(),
         ).subscribe(res => {
-            this.availablePipelines = res[0];
-            this.runningPipelines = res[0].filter(p => p.running);
-            this.availableAdapters = res[1];
+            this.availableAdapters = res[0];
             this.availablePipelineElements = this.availablePipelineElements
+                .concat(...res[1])
                 .concat(...res[2])
-                .concat(...res[3])
-                .concat(...res[4]);
+                .concat(...res[3]);
             this.checkForTutorial();
         });
     }
diff --git a/ui/src/app/home/home.module.ts b/ui/src/app/home/home.module.ts
index 9bfd0141f2..0dc059724d 100644
--- a/ui/src/app/home/home.module.ts
+++ b/ui/src/app/home/home.module.ts
@@ -32,6 +32,26 @@ import { WelcomeTourComponent } from 
'./dialog/welcome-tour/welcome-tour.compone
 import { SharedUiModule } from '@streampipes/shared-ui';
 import { RouterModule } from '@angular/router';
 import { TranslateModule } from '@ngx-translate/core';
+import { CoreUiModule } from '../core-ui/core-ui.module';
+import { MatButtonToggleModule } from '@angular/material/button-toggle';
+import { WelcomeComponent } from './components/welcome/welcome.component';
+import { HomeAssetMapComponent } from 
'./components/asset-map/home-asset-map.component';
+import { LeafletModule } from '@bluehalo/ngx-leaflet';
+import { AssetMapPopupComponent } from 
'./components/asset-map/asset-map-popup/asset-map-popup.component';
+import { AssetLinkChipComponent } from 
'./components/asset-map/asset-map-popup/asset-link-chip/asset-link-chip.component';
+import { FormsModule } from '@angular/forms';
+import { HomeAssetTableComponent } from 
'./components/asset-table/home-asset-table.component';
+import {
+    MatCell,
+    MatCellDef,
+    MatColumnDef,
+    MatHeaderCell,
+    MatHeaderCellDef,
+    MatTableModule,
+} from '@angular/material/table';
+import { MatMenuItem } from '@angular/material/menu';
+import { MatSort, MatSortHeader, MatSortModule } from '@angular/material/sort';
+import { AssetTableLinkPreviewComponent } from 
'./components/asset-table/asset-table-link-preview/asset-table-link-preview.component';
 
 @NgModule({
     imports: [
@@ -56,8 +76,24 @@ import { TranslateModule } from '@ngx-translate/core';
                 ],
             },
         ]),
+        CoreUiModule,
+        MatButtonToggleModule,
+        LeafletModule,
+        FormsModule,
+        MatSortModule,
+        MatTableModule,
+    ],
+    declarations: [
+        HomeComponent,
+        StatusComponent,
+        WelcomeTourComponent,
+        WelcomeComponent,
+        HomeAssetMapComponent,
+        AssetMapPopupComponent,
+        AssetLinkChipComponent,
+        HomeAssetTableComponent,
+        AssetTableLinkPreviewComponent,
     ],
-    declarations: [HomeComponent, StatusComponent, WelcomeTourComponent],
     providers: [HomeService],
 })
 export class HomeModule {}
diff --git a/ui/src/app/home/models/home.model.ts 
b/ui/src/app/home/models/home.model.ts
index 7bea8078c3..e69951af74 100644
--- a/ui/src/app/home/models/home.model.ts
+++ b/ui/src/app/home/models/home.model.ts
@@ -28,6 +28,7 @@ export interface StatusBox {
     viewRoles: string[];
     createRoles: string[];
     icon: string;
+    assetLinkTypeId: string;
 }
 
 export interface Link {
diff --git a/ui/src/scss/sp/_variables.scss b/ui/src/scss/sp/_variables.scss
index fde74fb333..90444c29ca 100644
--- a/ui/src/scss/sp/_variables.scss
+++ b/ui/src/scss/sp/_variables.scss
@@ -40,13 +40,13 @@ $sp-color-error: #b71c1c;
 
     --fg-muted: color-mix(in oklab, currentColor 60%, transparent);
 
-    --color-data-view: rgb(122, 206, 227);
-    --color-dashboard: rgb(76, 115, 164);
-    --color-adapter: rgb(182, 140, 97);
-    --color-data-source: #ffeb3b;
-    --color-pipeline: rgb(102, 185, 114);
-    --color-measurement: rgb(39, 164, 155);
-    --color-file: rgb(163, 98, 190);
+    --color-data-view: rgb(96, 165, 250);
+    --color-dashboard: rgb(79, 129, 189);
+    --color-adapter: rgb(180, 140, 95);
+    --color-data-source: rgb(234, 179, 8);
+    --color-pipeline: rgb(74, 182, 155);
+    --color-measurement: rgb(56, 178, 172);
+    --color-file: rgb(168, 85, 247);
 
     --button-border-radius: 5px;
     --iconbar-width: 35px;
diff --git a/ui/src/scss/sp/main.scss b/ui/src/scss/sp/main.scss
index 165a199a3e..864e87ee26 100644
--- a/ui/src/scss/sp/main.scss
+++ b/ui/src/scss/sp/main.scss
@@ -29,6 +29,10 @@ html {
     white-space: nowrap;
 }
 
+.leaflet-popup-content-wrapper {
+    background: var(--color-bg-0);
+}
+
 md-progress-linear.md-accent .md-container {
     background-color: rgb(168, 168, 168);
 }
@@ -49,10 +53,6 @@ body {
     height: auto !important;
     width: 100%;
 
-    --color-adapter: #{spThemeVars.$sp-color-adapter};
-    --color-stream: #{spThemeVars.$sp-color-stream};
-    --color-processor: #{spThemeVars.$sp-color-processor};
-    --color-sink: #{spThemeVars.$sp-color-sink};
     --color-tab-border: var(--color-bg-3);
 }
 
@@ -145,8 +145,12 @@ md-content {
 
 .page-container {
     margin: 10px;
-    min-height: calc(100% - 20px);
-    background: var(--color-bg-main-panel-content);
+    min-height: calc(100vh - 76px);
+    background: var(--color-bg-0);
+}
+
+.page-container-no-bg {
+    background: inherit;
 }
 
 .page-container-padding-inner {

Reply via email to