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

gongchao pushed a commit to branch alarm-1-3
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git

commit fa79d3750c07e39c71cd7a694606f01a0311fcfa
Author: tomsun28 <[email protected]>
AuthorDate: Fri Jan 3 16:50:00 2025 +0800

    [improve] update status labels
    
    Signed-off-by: tomsun28 <[email protected]>
---
 .../common/entity/manager/StatusPageComponent.java | 13 ++--
 .../manager/component/status/CalculateStatus.java  | 58 ++++++++---------
 web-app/src/app/pojo/StatusPageComponent.ts        |  2 +-
 .../routes/setting/status/status.component.html    | 22 ++-----
 .../app/routes/setting/status/status.component.ts  | 75 ++++------------------
 5 files changed, 52 insertions(+), 118 deletions(-)

diff --git 
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageComponent.java
 
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageComponent.java
index 5fe82560c..0bf6d57dd 100644
--- 
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageComponent.java
+++ 
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/entity/manager/StatusPageComponent.java
@@ -17,7 +17,9 @@
 
 package org.apache.hertzbeat.common.entity.manager;
 
+import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.persistence.Column;
 import jakarta.persistence.Convert;
 import jakarta.persistence.Entity;
 import jakarta.persistence.EntityListeners;
@@ -27,10 +29,12 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Table;
 import jakarta.validation.constraints.NotBlank;
 import java.time.LocalDateTime;
+import java.util.Map;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.apache.hertzbeat.common.entity.alerter.JsonMapAttributeConverter;
 import org.springframework.data.annotation.CreatedBy;
 import org.springframework.data.annotation.CreatedDate;
 import org.springframework.data.annotation.LastModifiedBy;
@@ -64,10 +68,11 @@ public class StatusPageComponent {
 
     @Schema(title = "component desc", example = "TanCloud Gateway")
     private String description;
-    
-    @Schema(title = "component match single tag", example = 
"{labelName:labelValue}")
-    @Convert(converter = JsonTagAttributeConverter.class)
-    private TagItem tag;
+
+    @Schema(title = "component label", example = "{env:test}", accessMode = 
READ_WRITE)
+    @Convert(converter = JsonMapAttributeConverter.class)
+    @Column(length = 4096)
+    private Map<String, String> labels;
 
     @Schema(title = "calculate status method: 0-auto 1-manual", example = "0")
     private byte method;
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/status/CalculateStatus.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/status/CalculateStatus.java
index ec37ea966..94a0d7ca0 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/status/CalculateStatus.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/component/status/CalculateStatus.java
@@ -18,8 +18,6 @@
 package org.apache.hertzbeat.manager.component.status;
 
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import jakarta.persistence.criteria.JoinType;
-import jakarta.persistence.criteria.ListJoin;
 import jakarta.persistence.criteria.Predicate;
 import java.time.Duration;
 import java.time.Instant;
@@ -37,14 +35,11 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.hertzbeat.common.constants.CommonConstants;
 import org.apache.hertzbeat.common.entity.manager.Monitor;
 import org.apache.hertzbeat.common.entity.manager.StatusPageComponent;
 import org.apache.hertzbeat.common.entity.manager.StatusPageHistory;
 import org.apache.hertzbeat.common.entity.manager.StatusPageOrg;
-import org.apache.hertzbeat.common.entity.manager.Tag;
-import org.apache.hertzbeat.common.entity.manager.TagItem;
 import org.apache.hertzbeat.manager.config.StatusProperties;
 import org.apache.hertzbeat.manager.dao.MonitorDao;
 import org.apache.hertzbeat.manager.dao.StatusPageComponentDao;
@@ -104,37 +99,34 @@ public class CalculateStatus {
                     List<StatusPageComponent> pageComponentList = 
statusPageComponentDao.findByOrgId(orgId);
                     Set<Byte> stateSet = new HashSet<>(8);
                     for (StatusPageComponent component : pageComponentList) {
-                        byte state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_NORMAL;
+                        byte state;
                         if (component.getMethod() == 
CommonConstants.STATUS_PAGE_CALCULATE_METHOD_MANUAL) {
                             state = component.getConfigState();
                         } else {
-                            TagItem tagItem = component.getTag();
-                            if (tagItem != null) {
-                                Specification<Monitor> specification = (root, 
query, criteriaBuilder) -> {
-                                    List<Predicate> andList = new 
ArrayList<>();
-                                    ListJoin<Monitor, Tag> tagJoin = root
-                                            .join(root.getModel()
-                                                    .getList("tags", 
Tag.class), JoinType.LEFT);
-                                    if 
(StringUtils.isNotBlank(tagItem.getValue())) {
-                                        
andList.add(criteriaBuilder.equal(tagJoin.get("name"), tagItem.getName()));
-                                        
andList.add(criteriaBuilder.equal(tagJoin.get("tagValue"), tagItem.getValue()));
-                                    } else {
-                                        
andList.add(criteriaBuilder.equal(tagJoin.get("name"), tagItem.getName()));
-                                    }
-                                    Predicate[] andPredicates = new 
Predicate[andList.size()];
-                                    Predicate andPredicate = 
criteriaBuilder.and(andList.toArray(andPredicates));
-                                    return 
query.where(andPredicate).getRestriction();
-                                };
-                                List<Monitor> monitorList = 
monitorDao.findAll(specification);
-                                state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_UNKNOWN;
-                                for (Monitor monitor : monitorList) {
-                                    if (monitor.getStatus() == 
CommonConstants.MONITOR_DOWN_CODE) {
-                                        state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_ABNORMAL;
-                                        break;
-                                    } else if (monitor.getStatus() == 
CommonConstants.MONITOR_UP_CODE) {
-                                        state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_NORMAL;
-                                    }
-                                }   
+                            Map<String, String> labels = component.getLabels();
+                            if (labels == null || labels.isEmpty()) {
+                                continue;
+                            }
+                            Specification<Monitor> specification = (root, 
query, criteriaBuilder) -> {
+                                List<Predicate> predicates = new ArrayList<>();
+                                // create every label condition
+                                labels.forEach((key, value) -> {
+                                    String pattern = 
String.format("%%\"%s\":\"%s\"%%", key, value);
+                                    
predicates.add(criteriaBuilder.like(root.get("labels"), pattern));
+                                });
+
+                                // use or connect them
+                                return 
criteriaBuilder.or(predicates.toArray(new Predicate[0]));
+                            };
+                            List<Monitor> monitorList = 
monitorDao.findAll(specification);
+                            state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_UNKNOWN;
+                            for (Monitor monitor : monitorList) {
+                                if (monitor.getStatus() == 
CommonConstants.MONITOR_DOWN_CODE) {
+                                    state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_ABNORMAL;
+                                    break;
+                                } else if (monitor.getStatus() == 
CommonConstants.MONITOR_UP_CODE) {
+                                    state = 
CommonConstants.STATUS_PAGE_COMPONENT_STATE_NORMAL;
+                                }
                             }
                         }
                         stateSet.add(state);
diff --git a/web-app/src/app/pojo/StatusPageComponent.ts 
b/web-app/src/app/pojo/StatusPageComponent.ts
index ac5552958..6afe004cb 100644
--- a/web-app/src/app/pojo/StatusPageComponent.ts
+++ b/web-app/src/app/pojo/StatusPageComponent.ts
@@ -24,7 +24,7 @@ export class StatusPageComponent {
   orgId!: number;
   name!: string;
   description!: string;
-  tag!: TagItem;
+  labels!: Record<string, string>;
   // calculate status method: 0-auto 1-manual
   method: number = 0;
   // config state when use manual method: 0-Normal 1-Abnormal 2-unknown
diff --git a/web-app/src/app/routes/setting/status/status.component.html 
b/web-app/src/app/routes/setting/status/status.component.html
index 06962fd73..5aee1e288 100644
--- a/web-app/src/app/routes/setting/status/status.component.html
+++ b/web-app/src/app/routes/setting/status/status.component.html
@@ -194,11 +194,9 @@
             </nz-tag>
           </td>
           <td nzAlign="center">
-            <a routerLink="/monitors" [queryParams]="{ tag: 
sliceTagName(data.tag) }">
-              <nz-tag class="hoverClass">
-                {{ sliceTagName(data.tag) }}
-              </nz-tag>
-            </a>
+            <nz-tag *ngFor="let label of data.labels | keyvalue" 
style="margin-top: 2px" [nzColor]="getLabelColor(label.key)">
+              {{ label.key }}:{{ label.value }}
+            </nz-tag>
           </td>
           <td nzAlign="center">{{ data.gmtUpdate | date : 'YYYY-MM-dd 
HH:mm:ss' }}</td>
           <td nzAlign="center">
@@ -375,19 +373,7 @@
           'status.component.tag' | i18n
         }}</nz-form-label>
         <nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | 
i18n">
-          <nz-select
-            [(ngModel)]="matchTag"
-            (nzOpenChange)="loadTagsOption()"
-            [nzOptions]="tagsOption"
-            [nzMaxTagCount]="5"
-            [nzDropdownMatchSelectWidth]="false"
-            nzShowSearch
-            [nzPlaceHolder]="'alert.notice.rule.tag.placeholder' | i18n"
-            required
-            name="tag"
-            id="tag"
-          >
-          </nz-select>
+          <app-labels-input [(ngModel)]="currentStatusComponent.labels" 
name="sourceLabels" required></app-labels-input>
         </nz-form-control>
       </nz-form-item>
       <nz-form-item *ngIf="currentStatusComponent.method == 1">
diff --git a/web-app/src/app/routes/setting/status/status.component.ts 
b/web-app/src/app/routes/setting/status/status.component.ts
index 1258c2c00..d7128996b 100644
--- a/web-app/src/app/routes/setting/status/status.component.ts
+++ b/web-app/src/app/routes/setting/status/status.component.ts
@@ -26,13 +26,11 @@ import { NzNotificationService } from 
'ng-zorro-antd/notification';
 import { switchMap } from 'rxjs';
 
 import { Message } from '../../../pojo/Message';
-import { TagItem } from '../../../pojo/NoticeRule';
 import { StatusPageComponent } from '../../../pojo/StatusPageComponent';
 import { StatusPageIncident } from '../../../pojo/StatusPageIncident';
 import { StatusPageIncidentContent } from 
'../../../pojo/StatusPageIncidentContent';
 import { StatusPageOrg } from '../../../pojo/StatusPageOrg';
 import { StatusPageService } from '../../../service/status-page.service';
-import { TagService } from '../../../service/tag.service';
 
 @Component({
   selector: 'app-status',
@@ -44,7 +42,6 @@ export class StatusComponent implements OnInit {
     private notifySvc: NzNotificationService,
     private modal: NzModalService,
     private statusPageService: StatusPageService,
-    private tagService: TagService,
     @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
   ) {}
 
@@ -70,8 +67,6 @@ export class StatusComponent implements OnInit {
   isIncidentModalAdd: boolean = true;
 
   search!: string;
-  tagsOption: any[] = [];
-  matchTag: string = '';
 
   ngOnInit(): void {
     this.loadStatusPageConfig();
@@ -182,7 +177,6 @@ export class StatusComponent implements OnInit {
   onNewStatusComponent() {
     this.isComponentModalAdd = true;
     this.currentStatusComponent = new StatusPageComponent();
-    this.matchTag = '';
     this.currentComponentVisible = true;
   }
 
@@ -220,13 +214,6 @@ export class StatusComponent implements OnInit {
   onEditOneComponent(data: StatusPageComponent) {
     this.isComponentModalAdd = false;
     this.currentStatusComponent = { ...data };
-    if (this.currentStatusComponent.tag != undefined) {
-      this.matchTag = this.sliceTagName(this.currentStatusComponent.tag);
-      this.tagsOption.push({
-        value: this.matchTag,
-        label: this.matchTag
-      });
-    }
     this.currentComponentVisible = true;
   }
 
@@ -304,17 +291,6 @@ export class StatusComponent implements OnInit {
       });
       return;
     }
-    if (this.matchTag != undefined && this.matchTag.trim() != '') {
-      let tmp: string[] = this.matchTag.split(':');
-      let tagItem = new TagItem();
-      if (tmp.length == 1) {
-        tagItem.name = tmp[0];
-      } else if (tmp.length == 2) {
-        tagItem.name = tmp[0];
-        tagItem.value = tmp[1];
-      }
-      this.currentStatusComponent.tag = tagItem;
-    }
     if (this.statusOrg.id == undefined) {
       
this.notifySvc.warning(this.i18nSvc.fanyi('status.component.notify.need-org'), 
'');
       return;
@@ -479,36 +455,6 @@ export class StatusComponent implements OnInit {
     });
   }
 
-  loadTagsOption() {
-    let tagsInit$ = this.tagService.loadTags(undefined, undefined, 0, 
1000).subscribe(
-      message => {
-        if (message.code === 0) {
-          let page = message.data;
-          this.tagsOption = [];
-          if (page.content != undefined) {
-            page.content.forEach(item => {
-              let tag = `${item.name}`;
-              if (item.tagValue != undefined) {
-                tag = `${tag}:${item.tagValue}`;
-              }
-              this.tagsOption.push({
-                value: tag,
-                label: tag
-              });
-            });
-          }
-        } else {
-          console.warn(message.msg);
-        }
-        tagsInit$.unsubscribe();
-      },
-      error => {
-        tagsInit$.unsubscribe();
-        console.error(error.msg);
-      }
-    );
-  }
-
   getLatestIncidentContentMsg(incidents: StatusPageIncidentContent[]): string {
     if (incidents == undefined || incidents.length == 0) {
       return '';
@@ -533,14 +479,19 @@ export class StatusComponent implements OnInit {
     }
   }
 
-  sliceTagName(tag: TagItem): string {
-    if (tag == undefined) {
-      return '';
-    }
-    if (tag.value != undefined && tag.value.trim() != '') {
-      return `${tag.name}:${tag.value}`;
-    } else {
-      return tag.name;
+  getLabelColor(key: string): string {
+    const colors = ['blue', 'green', 'orange', 'purple', 'cyan'];
+    const index = Math.abs(this.hashString(key)) % colors.length;
+    return colors[index];
+  }
+
+  private hashString(str: string): number {
+    let hash = 0;
+    for (let i = 0; i < str.length; i++) {
+      const char = str.charCodeAt(i);
+      hash = (hash << 5) - hash + char;
+      hash = hash & hash;
     }
+    return hash;
   }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to