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]
