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

gongchao pushed a commit to branch select-monitors-menu
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git

commit 9bdd93e2386505ce64d3f9230ce492c30920d665
Author: tomsun28 <[email protected]>
AuthorDate: Mon Dec 1 23:16:59 2025 +0800

    feat: update add monitors pop selected menus modal
    
    Signed-off-by: tomsun28 <[email protected]>
---
 .../monitor-list/monitor-list.component.html       |  10 +-
 .../monitor-list/monitor-list.component.less       |  17 ++-
 .../monitor-select-menu.component.html             |  45 +++---
 .../monitor-select-menu.component.less             | 157 ++++++++++++++++++---
 .../monitor-select-menu.component.ts               |  21 +++
 5 files changed, 208 insertions(+), 42 deletions(-)

diff --git 
a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.html 
b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.html
index 0dbd76053d..b980116f17 100644
--- a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.html
+++ b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.html
@@ -370,16 +370,17 @@
 <nz-modal
   [(nzVisible)]="appSwitchModalVisible"
   (nzOnCancel)="onAppSwitchModalCancel()"
-  nzClosable="false"
-  nzWidth="30%"
+  nzClosable="true"
+  nzWidth="900px"
   nzWrapClassName="monitor-select-menu-modal"
+  [nzTitle]="appSwitchModalVisibleType === 1 ? ('monitor.search.app' | i18n) : 
('monitor.new-monitor' | i18n)"
   [nzFooter]="null"
   [nzOkLoading]="appSearchLoading"
+  nzCentered
 >
   <div *nzModalContent class="-inner-content">
     <app-monitor-select-menu
-      listStyle="border-right: 0px"
-      [searchPlaceholder]="(appSwitchModalVisibleType === 1 ? 
'monitor.search.app' : 'monitor.center.search.placeholder') | i18n"
+      [searchPlaceholder]="'monitor.center.search.placeholder' | i18n"
       [loading]="appSearchLoading"
       [data]="appSearchOrigin"
       (selectedChanged)="gotoMonitorAddDetail($event)"
@@ -387,7 +388,6 @@
       <ng-template let-app="item" #prefix>
         <i nz-icon [nzType]="getAppIconName(app.value)" nzTheme="outline"></i>
       </ng-template>
-      <ng-template #suffix>@if (appSwitchModalVisibleType !== 1) {<i nz-icon 
nzType="right"></i>}</ng-template>
     </app-monitor-select-menu>
   </div>
 </nz-modal>
diff --git 
a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.less 
b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.less
index 7817988a06..9a288de84b 100644
--- a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.less
+++ b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.less
@@ -2,10 +2,25 @@
 
 ::ng-deep {
   .monitor-select-menu-modal {
+    .ant-modal-body {
+      padding: 0;
+      max-height: 70vh;
+      overflow: hidden;
+    }
+
+    .-inner-content {
+      height: 70vh;
+      max-height: 70vh;
+    }
+
     .ant-spin-container {
-      max-height: 80vh;
+      max-height: 70vh;
       overflow: hidden;
     }
+
+    app-monitor-select-menu {
+      height: 100%;
+    }
   }
 }
 
diff --git 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.html
 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.html
index fd2c2b472f..44a7ddd46e 100755
--- 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.html
+++ 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.html
@@ -18,7 +18,7 @@
 -->
 
 <nz-spin [nzSpinning]="loading" style="height: 100%">
-  <div style="margin: 8px 8px -4px 8px">
+  <div class="search-container">
     <app-multi-func-input
       type="search"
       [placeholder]="searchPlaceholder || ('common.search' | i18n)"
@@ -26,22 +26,29 @@
       (valueChange)="filter($event)"
     />
   </div>
-  <nz-divider></nz-divider>
-  <ul [style]="'flex: 1; overflow: hidden; overflow-y: auto;' + listStyle" 
nz-menu nzMode="inline" nzInlineCollapsed="false">
-    <li *ngFor="let menuItem of !!search ? dataByFilter : data" nz-submenu 
[nzTitle]="menuItem[1].label" [nzOpen]="!!search">
-      <ul>
-        <li class="item" nz-menu-item *ngFor="let app of menuItem[1].child" 
[nzSelected]="app.value === selected">
-          <ng-container *ngIf="prefixTemplateRef; else noPrefixContent">
-            <ng-template [ngTemplateOutlet]="prefixTemplateRef" 
[ngTemplateOutletContext]="{ item: app }"></ng-template>
-          </ng-container>
-          <ng-template #noPrefixContent></ng-template>
-          <span class="label" [title]="app.label" 
(click)="onSelectedChanged(app.value)">{{ app.label }}</span>
-          <ng-container *ngIf="suffixTemplateRef; else noSuffixContent">
-            <ng-template [ngTemplateOutlet]="suffixTemplateRef" 
[ngTemplateOutletContext]="{ item: app }"></ng-template>
-          </ng-container>
-          <ng-template #noSuffixContent></ng-template>
-        </li>
-      </ul>
-    </li>
-  </ul>
+  <div class="category-container" [style]="listStyle">
+    <div class="category-section" *ngFor="let menuItem of !!search ? 
dataByFilter : data">
+      <div class="category-header">
+        <span>
+          <i nz-icon [nzType]="getCategoryIcon(menuItem[0])" 
nzTheme="outline"></i>
+        </span>
+        <span class="category-title">{{ menuItem[1].label }}</span>
+        <span class="category-count">{{ menuItem[1].child.length }}</span>
+      </div>
+      <div class="category-items">
+        <div
+          class="monitor-type-card"
+          *ngFor="let app of menuItem[1].child"
+          [class.selected]="app.value === selected"
+          (click)="onSelectedChanged(app.value)"
+        >
+          <span class="card-label">{{ app.label }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="empty-state" *ngIf="(!!search ? dataByFilter : data)?.length 
=== 0">
+      <i nz-icon nzType="inbox" nzTheme="outline"></i>
+      <span>{{ 'common.no-data' | i18n }}</span>
+    </div>
+  </div>
 </nz-spin>
diff --git 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.less
 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.less
index a723c9414e..89e8fc707f 100755
--- 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.less
+++ 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.less
@@ -1,31 +1,154 @@
+@import '~src/styles/theme';
+
 :host ::ng-deep {
+  .ant-spin-container {
+    height: 100%;
+    display: flex;
+    overflow: hidden;
+    flex-direction: column;
+  }
+}
 
-  .item{
-    padding-left: 32px!important;
+:host {
+  display: block;
+  height: 100%;
 
-    .ant-menu-title-content {
-      gap: 8px;
-      display: flex;
-      align-items: center;
+  .search-container {
+    padding: 16px 16px 0 16px;
+  }
 
-      :first-child {
-        flex-shrink: 0;
-      }
+  .category-container {
+    flex: 1;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding: 16px;
+  }
 
-      .label {
-        flex: 1;
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-      }
+  .category-section {
+    margin-bottom: 20px;
+
+    &:last-child {
+      margin-bottom: 0;
     }
   }
 
-  .ant-spin-container {
-    height: 100%;
+  .category-header {
     display: flex;
+    align-items: center;
+    gap: 10px;
+    margin-bottom: 12px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .category-title {
+    font-size: 15px;
+    font-weight: 600;
+    color: #1f1f1f;
+  }
+
+  .category-count {
+    font-size: 12px;
+    color: #8c8c8c;
+    background: #f5f5f5;
+    padding: 2px 8px;
+    border-radius: 10px;
+    margin-left: auto;
+  }
+
+  .category-items {
+    display: grid;
+    grid-template-columns: repeat(5, 1fr);
+    gap: 10px;
+  }
+
+  .monitor-type-card {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 10px 12px;
+    background: #fafafa;
+    border: 1px solid #e8e8e8;
+    border-radius: 6px;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    text-align: center;
+
+    &:hover {
+      border-color: @primary-color;
+      background: #e6f4ff;
+      transform: translateY(-1px);
+      box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
+    }
+
+    &.selected {
+      border-color: @primary-color;
+      background: #e6f4ff;
+      box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+    }
+  }
+
+  .card-label {
+    font-size: 13px;
+    color: #333;
     overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    line-height: 1.4;
+  }
+
+  .empty-state {
+    display: flex;
     flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 48px 0;
+    color: #8c8c8c;
+
+    i {
+      font-size: 48px;
+      margin-bottom: 12px;
+    }
   }
+}
+
+// Dark theme support
+[data-theme='dark'] {
+  :host {
+    .category-header {
+      border-bottom-color: #303030;
+    }
+
+    .category-title {
+      color: #d9d9d9;
+    }
+
+    .category-count {
+      background: #303030;
+      color: #a0a0a0;
+    }
+
+    .monitor-type-card {
+      background: #1f1f1f;
+      border-color: #303030;
 
+      &:hover {
+        border-color: @primary-color;
+        background: #111d2c;
+      }
+
+      &.selected {
+        border-color: @primary-color;
+        background: #111d2c;
+      }
+    }
+
+    .card-label {
+      color: #d9d9d9;
+    }
+
+    .empty-state {
+      color: #6c6c6c;
+    }
+  }
 }
diff --git 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.ts
 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.ts
index 20315dea20..89f42e3555 100755
--- 
a/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.ts
+++ 
b/web-app/src/app/shared/components/monitor-select-menu/monitor-select-menu.component.ts
@@ -51,4 +51,25 @@ export class MonitorSelectMenuComponent {
   onSelectedChanged(selected: string) {
     this.selectedChanged.emit(selected);
   }
+
+  getCategoryIcon(category: string): string {
+    const iconMap: Record<string, string> = {
+      os: 'desktop',
+      webserver: 'global',
+      bigdata: 'cluster',
+      cache: 'database',
+      service: 'api',
+      server: 'hdd',
+      mid: 'deployment-unit',
+      db: 'database',
+      custom: 'tool',
+      llm: 'robot',
+      network: 'wifi',
+      cn: 'cloud-server',
+      cicd: 'branches',
+      auto: 'thunderbolt',
+      program: 'code'
+    };
+    return iconMap[category] || 'appstore';
+  }
 }


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

Reply via email to