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> {{ 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 {