This is an automated email from the ASF dual-hosted git repository.
liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 8d1f306433 [feature] implement labels-based monitors filtering in
bulletin creation flow (#3161)
8d1f306433 is described below
commit 8d1f3064333b6fbc99215a8bb0125c2a3793a87b
Author: LL-LIN <[email protected]>
AuthorDate: Mon Mar 24 10:46:52 2025 +0800
[feature] implement labels-based monitors filtering in bulletin creation
flow (#3161)
Co-authored-by: aias00 <[email protected]>
---
home/docs/help/bulletin.md | 2 +-
.../current/help/bulletin.md | 2 +-
home/static/img/docs/help/bulletin-1.png | Bin 79792 -> 80714 bytes
.../app/routes/bulletin/bulletin.component.html | 17 +++++-
.../src/app/routes/bulletin/bulletin.component.ts | 61 ++++++++++++++++++++-
5 files changed, 78 insertions(+), 4 deletions(-)
diff --git a/home/docs/help/bulletin.md b/home/docs/help/bulletin.md
index 00b5036f96..ce45f78673 100644
--- a/home/docs/help/bulletin.md
+++ b/home/docs/help/bulletin.md
@@ -9,7 +9,7 @@ keywords: [bulletin, custom]
### Add Bulletin Item
-1. Click `Add New Bulletin Item`, enter the `Bulletin Name`, scroll down to
select the `Monitoring Type`, select the associated `Monitoring Task Name`, and
then select the `Monitoring Metrics` you want to show in the shuttle box.
+1. Click `Add New Bulletin Item`, enter the `Bulletin Name`, scroll down to
select the `Monitoring Type`, select the associated `Monitoring Task Name`, You
can filter `Monitor Task Name` by `Label`, and then select the `Monitoring
Metrics` you want to show in the shuttle box.
2. Click `OK` button to finish creating the customized bulletin.
diff --git
a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/bulletin.md
b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/bulletin.md
index d6e8dd2613..527bb1292c 100644
--- a/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/bulletin.md
+++ b/home/i18n/zh-cn/docusaurus-plugin-content-docs/current/help/bulletin.md
@@ -9,7 +9,7 @@ keywords: [看板, 自定义]
### 新增看板项
-1. 点击新增看板项, 输入`看板名称`, 下拉选择`监控类型`, 再选择关联的`监控任务名称`, 最后在穿梭框中选择需要展示的`监控指标`。
+1. 点击新增看板项, 输入`看板名称`, 下拉选择`监控类型`, 可根据`标签`对`监控任务名称`进行筛选,再选择关联的`监控任务名称`,
最后在穿梭框中选择需要展示的`监控指标`。
2. 点击`确定`按钮, 即可完成自定义看板的创建。
diff --git a/home/static/img/docs/help/bulletin-1.png
b/home/static/img/docs/help/bulletin-1.png
index ae65823122..69b96e05da 100644
Binary files a/home/static/img/docs/help/bulletin-1.png and
b/home/static/img/docs/help/bulletin-1.png differ
diff --git a/web-app/src/app/routes/bulletin/bulletin.component.html
b/web-app/src/app/routes/bulletin/bulletin.component.html
index a65a988120..7c79ae6baa 100644
--- a/web-app/src/app/routes/bulletin/bulletin.component.html
+++ b/web-app/src/app/routes/bulletin/bulletin.component.html
@@ -181,6 +181,21 @@
</nz-form-control>
</nz-form-item>
+ <nz-form-item>
+ <nz-form-label nzSpan="7" [nzFor]="'filterLabels'">{{
'monitor.search.label' | i18n }} </nz-form-label>
+ <nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' |
i18n">
+ <app-form-field
+ [item]="{
+ field: 'labels',
+ type: 'labels'
+ }"
+ [name]="'labels'"
+ [(ngModel)]="filterLabels"
+ (ngModelChange)="onFilterInputChange($event)"
+ />
+ </nz-form-control>
+ </nz-form-item>
+
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{
'bulletin.monitor.name' | i18n }}</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' |
i18n">
@@ -193,7 +208,7 @@
nzMode="multiple"
required
>
- <ng-container *ngFor="let monitor of monitors">
+ <ng-container *ngFor="let monitor of filteredMonitors">
<nz-option *ngIf="isMonitorListLoading" [nzValue]="monitor.id"
[nzLabel]="monitor.name"></nz-option>
</ng-container>
</nz-select>
diff --git a/web-app/src/app/routes/bulletin/bulletin.component.ts
b/web-app/src/app/routes/bulletin/bulletin.component.ts
index 21fc346c63..fb42094883 100644
--- a/web-app/src/app/routes/bulletin/bulletin.component.ts
+++ b/web-app/src/app/routes/bulletin/bulletin.component.ts
@@ -25,7 +25,8 @@ import { NzNotificationService } from
'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
import { TransferChange } from 'ng-zorro-antd/transfer';
import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from
'ng-zorro-antd/tree';
-import { finalize } from 'rxjs/operators';
+import { Subject } from 'rxjs';
+import { finalize, debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { BulletinDefine } from '../../pojo/BulletinDefine';
import { Fields } from '../../pojo/Fields';
@@ -73,22 +74,35 @@ export class BulletinComponent implements OnInit, OnDestroy
{
refreshInterval: any;
deadline = 30;
countDownTime: number = 0;
+ filterLabels: Record<string, string> = {};
+ filteredMonitors: Monitor[] = [];
+ private filterSubject = new Subject<string>(); //filter logic debouncing
ngOnInit() {
this.loadTabs();
this.refreshInterval = setInterval(() => {
this.countDown();
}, 1000); // every 30 seconds refresh the tabs
+ this.filterSubject
+ .pipe(
+ debounceTime(300), // triggered after the user stops typing for 300ms
+ distinctUntilChanged()
+ )
+ .subscribe(value => {
+ this.filterMonitors();
+ });
}
ngOnDestroy() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
+ this.filterSubject.complete();
}
sync() {
this.loadCurrentBulletinData();
+ this.clearFilters();
}
configRefreshDeadline(deadlineTime: number) {
@@ -158,6 +172,7 @@ export class BulletinComponent implements OnInit, OnDestroy
{
this.isManageModalVisible = false;
// clear fields
this.fields = {};
+ this.clearFilters();
}
resetManageModalData() {
@@ -254,6 +269,7 @@ export class BulletinComponent implements OnInit, OnDestroy
{
message => {
if (message.code === 0) {
this.monitors = message.data;
+ this.filterMonitors();
if (this.monitors != null) {
this.isMonitorListLoading = true;
}
@@ -568,4 +584,47 @@ export class BulletinComponent implements OnInit,
OnDestroy {
}
return result;
}
+
+ onFilterInputChange(value: string): void {
+ this.filterSubject.next(value); // push the input value to the debounce
Subject
+ }
+
+ filterMonitors(): void {
+ const validLabels = this.cleanFilterLabels(this.filterLabels);
+ const activeFilters = Object.entries(validLabels).filter(([k, v]) => k !==
'' && k !== 'null'); // Second filtering ensures key validity
+
+ if (activeFilters.length === 0) {
+ this.filteredMonitors = [...this.monitors];
+ return;
+ }
+
+ this.filteredMonitors = this.monitors.filter(monitor => {
+ if (!monitor.labels || typeof monitor.labels !== 'object') return false;
+
+ return activeFilters.every(([filterKey, filterValue]) => {
+ const keyExists = Object.prototype.hasOwnProperty.call(monitor.labels,
filterKey);
+ const actualValue = (monitor.labels[filterKey] ?? '').toLowerCase();
+ return filterValue === '' ? keyExists :
actualValue.includes(filterValue.toLowerCase());
+ });
+ });
+ }
+
+ private cleanFilterLabels(labels: any): Record<string, string> {
+ const cleaned: Record<string, string> = {};
+ Object.entries(labels ?? {}).forEach(([k, v]) => {
+ if (typeof k === 'string') {
+ const trimmedKey = k.trim();
+ if (trimmedKey !== '' && trimmedKey !== 'null') {
+ cleaned[trimmedKey] = (v ?? '').toString().trim();
+ }
+ }
+ });
+ return cleaned;
+ }
+
+ clearFilters(): void {
+ this.filterLabels = {};
+ this.filterMonitors();
+ this.cdr.detectChanges();
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]