This is an automated email from the ASF dual-hosted git repository.
Aias00 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 a54be93ff5 [fix] keep monitor selection across pages in monitor list
(#4170)
a54be93ff5 is described below
commit a54be93ff5ee849b91f4d6aed0a7c7dea40a955d
Author: Duansg <[email protected]>
AuthorDate: Sun Jun 28 00:02:18 2026 +0800
[fix] keep monitor selection across pages in monitor list (#4170)
Co-authored-by: aias00 <[email protected]>
---
.../monitor-list/monitor-list.component.html | 37 +++++++++++------
.../monitor-list/monitor-list.component.less | 16 ++++++--
.../monitor/monitor-list/monitor-list.component.ts | 48 ++++++++++++++++------
web-app/src/assets/i18n/en-US.json | 3 ++
web-app/src/assets/i18n/ja-JP.json | 3 ++
web-app/src/assets/i18n/pt-BR.json | 3 ++
web-app/src/assets/i18n/zh-CN.json | 3 ++
web-app/src/assets/i18n/zh-TW.json | 3 ++
8 files changed, 86 insertions(+), 30 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 38fa55f548..0990366e09 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
@@ -140,19 +140,6 @@
</app-toolbar>
<div class="monitor-card-list">
- <div class="monitor-list-header" *ngIf="monitors?.length">
- <div class="monitor-header-actions">
- <label nz-checkbox [(ngModel)]="checkedAll"
(ngModelChange)="onAllChecked($event)"></label>
- <nz-pagination
- [(nzPageIndex)]="pageIndex"
- [nzPageSize]="pageSize"
- [nzTotal]="total"
- (nzPageIndexChange)="onPageIndexChange($event)"
- nzSimple
- ></nz-pagination>
- </div>
- </div>
-
<nz-spin [nzSpinning]="tableLoading">
<div class="monitor-card-list-content">
<div
@@ -293,6 +280,30 @@
</div>
</div>
</nz-spin>
+
+ <div class="monitor-list-footer" *ngIf="monitors?.length">
+ <div class="monitor-footer-actions">
+ <ng-container *ngIf="checkedMonitorIds.size > 0">
+ <label nz-checkbox [ngModel]="checkedAll"
(ngModelChange)="onAllChecked($event)">
+ {{ 'monitor.select-current-page' | i18n }}
+ </label>
+ <span class="monitor-selected-count">{{ 'monitor.selected-count' |
i18n : { count: checkedMonitorIds.size } }}</span>
+ <button nz-button nzType="link" nzSize="small"
(click)="clearSelection()">
+ {{ 'monitor.clear-selection' | i18n }}
+ </button>
+ </ng-container>
+ </div>
+ <nz-pagination
+ [(nzPageIndex)]="pageIndex"
+ [nzPageSize]="pageSize"
+ [nzTotal]="total"
+ [nzShowTotal]="rangeTemplate"
+ nzShowSizeChanger
+ [nzPageSizeOptions]="pageSizeOptions"
+ (nzPageIndexChange)="onPageIndexChange($event)"
+ (nzPageSizeChange)="onPageSizeChange($event)"
+ ></nz-pagination>
+ </div>
</div>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }}
</ng-template>
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 9a288de84b..a47dbb8485 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
@@ -86,19 +86,27 @@
position: relative;
}
-.monitor-list-header {
+.monitor-selected-count {
+ color: rgba(0, 0, 0, 0.45);
+ font-size: 12px;
+}
+
+.monitor-list-footer {
display: flex;
- align-items: center;
justify-content: space-between;
- margin-bottom: 16px;
+ align-items: center;
+ margin-top: 16px;
padding: 8px 0;
flex-wrap: wrap;
gap: 8px;
}
-.monitor-header-actions {
+.monitor-footer-actions {
display: flex;
align-items: center;
+ gap: 8px;
+ // Align the select-all checkbox with the per-row checkboxes, which sit at
the card's 12px padding.
+ padding-left: 12px;
}
.monitor-card-list-content {
diff --git
a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts
b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts
index ef58fd6afd..2ab3443179 100644
--- a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts
+++ b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts
@@ -53,7 +53,8 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
app!: string | undefined;
labels!: string | undefined;
pageIndex: number = 1;
- pageSize: number = 8;
+ pageSize: number = 10;
+ pageSizeOptions: number[] = [10, 20, 50];
total: number = 0;
monitors!: Monitor[];
tableLoading: boolean = true;
@@ -98,7 +99,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
this.app = undefined;
}
this.pageIndex = 1;
- this.pageSize = 8;
+ this.pageSize = 10;
this.checkedMonitorIds = new Set<number>();
this.tableLoading = true;
this.loadMonitorTable();
@@ -134,7 +135,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
message => {
filter$.unsubscribe();
this.tableLoading = false;
- this.checkedAll = false;
+ // Filtering changes the result set, so the previous selection no
longer applies.
this.checkedMonitorIds.clear();
if (message.code === 0) {
let page = message.data;
@@ -180,8 +181,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
.subscribe(
message => {
this.tableLoading = false;
- this.checkedAll = false;
- this.checkedMonitorIds.clear();
+ // Keep the selection across reloads (pagination, auto-refresh,
post-CRUD) so multi-page checks persist (#4164).
if (message.code === 0) {
let page = message.data;
this.monitors = reconcile ?
this.reconcileMonitorStates(page.content) :
this.resetMonitorStates(page.content);
@@ -205,8 +205,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
.subscribe(
message => {
this.tableLoading = false;
- this.checkedAll = false;
- this.checkedMonitorIds.clear();
+ // Keep the selection across pagination so checks made on other
pages persist (#4164).
if (message.code === 0) {
let page = message.data;
// Pagination changes the result set, so reconcile here would flag
the previous page as "disappeared" (#4156).
@@ -305,6 +304,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
deleteMonitors$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
+ monitors.forEach(id => this.checkedMonitorIds.delete(id));
this.updatePageIndex(monitors.size);
this.loadMonitorTable();
} else {
@@ -450,6 +450,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
cancelManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.cancel-success'), '');
+ monitors.forEach(id => this.checkedMonitorIds.delete(id));
this.loadMonitorTable();
} else {
this.tableLoading = false;
@@ -511,6 +512,7 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
enableManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.enable-success'), '');
+ monitors.forEach(id => this.checkedMonitorIds.delete(id));
this.loadMonitorTable();
} else {
this.tableLoading = false;
@@ -537,14 +539,28 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
}
// begin: List multiple choice paging
- checkedAll: boolean = false;
+ // Reflects only the current page: checked when every selectable monitor on
this page is selected.
+ get checkedAll(): boolean {
+ const selectable = this.monitors?.filter(monitor =>
!this.isMonitorDisabled(monitor)) ?? [];
+ return selectable.length > 0 && selectable.every(monitor =>
this.checkedMonitorIds.has(monitor.id));
+ }
onAllChecked(checked: boolean) {
- if (checked) {
- this.monitors.forEach(monitor => this.checkedMonitorIds.add(monitor.id));
- } else {
- this.checkedMonitorIds.clear();
- }
+ // Only toggle the current page's selectable monitors, leaving selections
on other pages untouched (#4164).
+ this.monitors
+ ?.filter(monitor => !this.isMonitorDisabled(monitor))
+ .forEach(monitor => {
+ if (checked) {
+ this.checkedMonitorIds.add(monitor.id);
+ } else {
+ this.checkedMonitorIds.delete(monitor.id);
+ }
+ });
+ }
+
+ // Clear the whole cross-page selection in one click, so users aren't forced
to page back to deselect (#4164).
+ clearSelection() {
+ this.checkedMonitorIds.clear();
}
onItemChecked(monitorId: number, checked: boolean) {
@@ -566,6 +582,12 @@ export class MonitorListComponent implements OnInit,
OnDestroy {
this.changeMonitorTable(this.currentSortField, this.currentSortOrder);
}
+ onPageSizeChange(pageSize: number) {
+ this.pageSize = pageSize;
+ this.pageIndex = 1;
+ this.changeMonitorTable(this.currentSortField, this.currentSortOrder);
+ }
+
// begin: app type search filter
onSearchAppClicked() {
diff --git a/web-app/src/assets/i18n/en-US.json
b/web-app/src/assets/i18n/en-US.json
index f3a8781df1..b4ad4a6677 100644
--- a/web-app/src/assets/i18n/en-US.json
+++ b/web-app/src/assets/i18n/en-US.json
@@ -863,6 +863,9 @@
"monitor.edit.success": "Update Monitor Success",
"monitor.enable": "Enable",
"monitor.export": "Export Selected",
+ "monitor.selected-count": "{{count}} selected",
+ "monitor.clear-selection": "Clear",
+ "monitor.select-current-page": "Select this page",
"monitor.export-all": "Export All",
"monitor.export.switch-type": "Please select the export file format",
"monitor.export.use-type": "Export selected monitors in {{type}} format",
diff --git a/web-app/src/assets/i18n/ja-JP.json
b/web-app/src/assets/i18n/ja-JP.json
index 1d0fc78779..ad17160459 100644
--- a/web-app/src/assets/i18n/ja-JP.json
+++ b/web-app/src/assets/i18n/ja-JP.json
@@ -822,6 +822,9 @@
"monitor.edit.success": "モニターの更新に成功しました",
"monitor.enable": "モニターを再開",
"monitor.export": "モニターをエクスポート",
+ "monitor.selected-count": "{{count}} 件選択中",
+ "monitor.clear-selection": "クリア",
+ "monitor.select-current-page": "現在のページを全選択",
"monitor.export.switch-type": "エクスポートファイル形式を選択してください!",
"monitor.export.use-type": "{{type}}ファイル形式でモニターをエクスポート",
"monitor.grafana.enabled.label": "Grafanaを有効化",
diff --git a/web-app/src/assets/i18n/pt-BR.json
b/web-app/src/assets/i18n/pt-BR.json
index c6d1e0da48..72bff765b1 100644
--- a/web-app/src/assets/i18n/pt-BR.json
+++ b/web-app/src/assets/i18n/pt-BR.json
@@ -634,6 +634,9 @@
"monitor.edit.success": "Monitor modificado com sucesso",
"monitor.enable": "Retomar monitoramento",
"monitor.export": "Exportar monitor",
+ "monitor.selected-count": "{{count}} selecionado(s)",
+ "monitor.clear-selection": "Limpar",
+ "monitor.select-current-page": "Selecionar esta página",
"monitor.export.switch-type": "Selecione o formato do arquivo de
exportação!",
"monitor.export.use-type": "Exportar monitor no formato {{type}}",
"monitor.grafana.enabled.label": "Habilitar Grafana",
diff --git a/web-app/src/assets/i18n/zh-CN.json
b/web-app/src/assets/i18n/zh-CN.json
index 6d4a71744d..768473d64f 100644
--- a/web-app/src/assets/i18n/zh-CN.json
+++ b/web-app/src/assets/i18n/zh-CN.json
@@ -866,6 +866,9 @@
"monitor.edit.success": "修改监控成功",
"monitor.enable": "恢复监控",
"monitor.export": "导出所选",
+ "monitor.selected-count": "已选 {{count}} 项",
+ "monitor.clear-selection": "清空",
+ "monitor.select-current-page": "全选当前页",
"monitor.export-all": "导出全部",
"monitor.export.switch-type": "请选择导出文件格式!",
"monitor.export.use-type": "以 {{type}} 文件格式导出所选监控",
diff --git a/web-app/src/assets/i18n/zh-TW.json
b/web-app/src/assets/i18n/zh-TW.json
index ce8ee447ff..a05dc1b7c5 100644
--- a/web-app/src/assets/i18n/zh-TW.json
+++ b/web-app/src/assets/i18n/zh-TW.json
@@ -826,6 +826,9 @@
"monitor.edit.success": "修改監控成功",
"monitor.enable": "恢復監控",
"monitor.export": "匯出監控",
+ "monitor.selected-count": "已選 {{count}} 項",
+ "monitor.clear-selection": "清空",
+ "monitor.select-current-page": "全選當前頁",
"monitor.export.switch-type": "請選擇匯出文件格式!",
"monitor.export.use-type": "以 {{type}} 檔案格式匯出監控",
"monitor.grafana.enabled.label": "啓用Grafana監控",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]