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]

Reply via email to