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

zhaoqingran 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 67da9bdbba [Feature] Support copy monitoring (#2981)
67da9bdbba is described below

commit 67da9bdbba07871cd0620f3a62853e53c1ab1d0e
Author: Jast <shengh...@apache.org>
AuthorDate: Wed Jan 15 17:03:53 2025 +0800

    [Feature] Support copy monitoring (#2981)
---
 .../manager/controller/MonitorController.java      |  17 ++-
 .../hertzbeat/manager/service/MonitorService.java  |  61 +++++---
 .../manager/service/impl/MonitorServiceImpl.java   | 160 +++++++++++++++------
 .../monitor-list/monitor-list.component.html       |   6 +
 .../monitor/monitor-list/monitor-list.component.ts |  26 ++++
 web-app/src/app/service/monitor.service.ts         |   6 +-
 web-app/src/assets/i18n/en-US.json                 |   7 +-
 web-app/src/assets/i18n/zh-CN.json                 |   7 +-
 8 files changed, 226 insertions(+), 64 deletions(-)

diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/MonitorController.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/MonitorController.java
index 77b02622a9..e44ac75c4e 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/MonitorController.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/controller/MonitorController.java
@@ -17,8 +17,6 @@
 
 package org.apache.hertzbeat.manager.controller;
 
-import static 
org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_NOT_EXIST_CODE;
-import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -38,6 +36,10 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import static org.apache.hertzbeat.common.constants.CommonConstants.FAIL_CODE;
+import static 
org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_NOT_EXIST_CODE;
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
 /**
  * Monitoring management API
  */
@@ -101,4 +103,15 @@ public class MonitorController {
         monitorService.detectMonitor(monitorDto.getMonitor(), 
monitorDto.getParams(), monitorDto.getCollector());
         return ResponseEntity.ok(Message.success("Detect success."));
     }
+
+    @PostMapping("/copy/{id}")
+    @Operation(summary = "Copy Monitor", description = "Copy an existing 
monitor")
+    public ResponseEntity<Message<Void>> copyMonitor(@PathVariable("id") final 
Long id) {
+        try {
+            monitorService.copyMonitor(id);
+            return ResponseEntity.ok(Message.success("Copy monitor success"));
+        } catch (Exception e) {
+            return ResponseEntity.ok(Message.fail(FAIL_CODE, "Copy monitor 
failed: " + e.getMessage()));
+        }
+    }
 }
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/MonitorService.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/MonitorService.java
index f642a9a871..ff173393fa 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/MonitorService.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/MonitorService.java
@@ -18,9 +18,6 @@
 package org.apache.hertzbeat.manager.service;
 
 import jakarta.servlet.http.HttpServletResponse;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
 import org.apache.hertzbeat.common.entity.grafana.GrafanaDashboard;
 import org.apache.hertzbeat.common.entity.job.Job;
 import org.apache.hertzbeat.common.entity.manager.Monitor;
@@ -32,6 +29,10 @@ import 
org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
 import org.springframework.data.domain.Page;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 /**
  * Monitoring and management services
  */
@@ -39,6 +40,7 @@ public interface MonitorService {
 
     /**
      * Monitoring Availability Probes
+     *
      * @param monitor   Monitoring entity information
      * @param params    Parameter information
      * @param collector collector pinned
@@ -49,16 +51,17 @@ public interface MonitorService {
     /**
      * Add monitoring
      *
-     * @param monitor          Monitoring Entity
-     * @param params           Parameter information
-     * @param collector        collector pinned
-     * @param dashboard       grafana dashboard
+     * @param monitor   Monitoring Entity
+     * @param params    Parameter information
+     * @param collector collector pinned
+     * @param dashboard grafana dashboard
      * @throws RuntimeException Add process exception throw
      */
     void addMonitor(Monitor monitor, List<Param> params, String collector, 
GrafanaDashboard dashboard) throws RuntimeException;
 
     /**
      * Verify the correctness of request data parameters
+     *
      * @param monitorDto monitorDto
      * @param isModify   Whether it is a modification monitoring
      * @throws IllegalArgumentException Validation parameter error thrown
@@ -68,16 +71,17 @@ public interface MonitorService {
     /**
      * Modify update monitoring
      *
-     * @param monitor          Monitor Entity
-     * @param params           Parameter information
-     * @param collector        collector pinned
-     * @param dashboard        grafana dashboard
+     * @param monitor   Monitor Entity
+     * @param params    Parameter information
+     * @param collector collector pinned
+     * @param dashboard grafana dashboard
      * @throws RuntimeException Exception thrown during modification
      */
     void modifyMonitor(Monitor monitor, List<Param> params, String collector, 
GrafanaDashboard dashboard) throws RuntimeException;
 
     /**
      * Delete Monitor
+     *
      * @param id Monitor ID
      * @throws RuntimeException Exception thrown during deletion
      */
@@ -85,6 +89,7 @@ public interface MonitorService {
 
     /**
      * Batch delete monitoring
+     *
      * @param ids Monitoring ID List
      * @throws RuntimeException Exception thrown during deletion
      */
@@ -92,6 +97,7 @@ public interface MonitorService {
 
     /**
      * Get monitoring information
+     *
      * @param id Monitor ID
      * @return MonitorDto   Monitor Entity
      * @throws RuntimeException Exception thrown during query
@@ -100,39 +106,44 @@ public interface MonitorService {
 
     /**
      * Dynamic conditional query
+     *
      * @param monitorIds Monitor ID List
-     * @param app       Monitor Type
-     * @param search      Monitor Host support fuzzy query
-     * @param status    Monitor Status 0:no monitor,1:usable,2:disabled,9:all 
status
-     * @param sort      Sort Field
-     * @param order     Sort mode eg:asc desc
-     * @param pageIndex List current page
-     * @param pageSize  Number of list pagination
-     * @param labels    Monitor labels
+     * @param app        Monitor Type
+     * @param search     Monitor Host support fuzzy query
+     * @param status     Monitor Status 0:no monitor,1:usable,2:disabled,9:all 
status
+     * @param sort       Sort Field
+     * @param order      Sort mode eg:asc desc
+     * @param pageIndex  List current page
+     * @param pageSize   Number of list pagination
+     * @param labels     Monitor labels
      * @return Search Result
      */
     Page<Monitor> getMonitors(List<Long> monitorIds, String app, String 
search, Byte status, String sort, String order, int pageIndex, int pageSize, 
String labels);
 
     /**
      * Unmanaged monitoring items in batches according to the monitoring ID 
list
+     *
      * @param ids Monitoring ID List
      */
     void cancelManageMonitors(HashSet<Long> ids);
 
     /**
      * Start the managed monitoring items in batches according to the 
monitoring ID list
+     *
      * @param ids Monitoring ID List
      */
     void enableManageMonitors(HashSet<Long> ids);
 
     /**
      * Query the monitoring category and its corresponding monitoring quantity
+     *
      * @return Monitoring Category and Monitoring Quantity Mapping
      */
     List<AppCount> getAllAppMonitorsCount();
 
     /**
      * Query monitoring
+     *
      * @param monitorId Monitor ID
      * @return Monitor information
      */
@@ -140,6 +151,7 @@ public interface MonitorService {
 
     /**
      * Update the status of the specified monitor
+     *
      * @param monitorId monitorId
      * @param status    monitor status
      */
@@ -147,6 +159,7 @@ public interface MonitorService {
 
     /**
      * Query the list of all monitoring information under the specified 
monitoring type
+     *
      * @param app Monitor Type
      * @return Monitor Entity List
      */
@@ -154,6 +167,7 @@ public interface MonitorService {
 
     /**
      * Export Monitoring Configuration
+     *
      * @param ids  monitor id list
      * @param type file type
      * @param res  response
@@ -163,6 +177,7 @@ public interface MonitorService {
 
     /**
      * Import Monitoring Configuration
+     *
      * @param file configuration file
      * @throws Exception This exception will be thrown if the export fails
      */
@@ -177,9 +192,17 @@ public interface MonitorService {
 
     /**
      * update app collect job by app
+     *
      * @param job job content
      */
     void updateAppCollectJob(Job job);
 
     void addAndSaveMonitorJob(Monitor monitor, List<Param> params, String 
collector, SdMonitorParam sdMonitorParam, GrafanaDashboard grafanaDashboard);
+
+    /**
+     * Copy monitor by id
+     *
+     * @param id Monitor id
+     */
+    void copyMonitor(Long id);
 }
diff --git 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
index fd38159e0c..00f7c6fbfe 100644
--- 
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
+++ 
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/service/impl/MonitorServiceImpl.java
@@ -22,20 +22,6 @@ import com.google.common.collect.Sets;
 import jakarta.persistence.criteria.CriteriaBuilder;
 import jakarta.persistence.criteria.Predicate;
 import jakarta.servlet.http.HttpServletResponse;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hertzbeat.alert.dao.AlertDefineBindDao;
@@ -83,6 +69,7 @@ import org.apache.hertzbeat.manager.service.TagService;
 import org.apache.hertzbeat.manager.support.exception.MonitorDatabaseException;
 import org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
 import org.apache.hertzbeat.warehouse.service.WarehouseService;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 import org.springframework.data.domain.Page;
@@ -96,6 +83,21 @@ import 
org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 /**
  * Monitoring and management service implementation
  */
@@ -103,55 +105,40 @@ import org.springframework.web.multipart.MultipartFile;
 @Transactional(rollbackFor = Exception.class)
 @Slf4j
 public class MonitorServiceImpl implements MonitorService {
-    private static final Long MONITOR_ID_TMP = 1000000000L;
-
     public static final String PATTERN_HTTP = "(?i)http://";;
     public static final String PATTERN_HTTPS = "(?i)https://";;
-
+    private static final Long MONITOR_ID_TMP = 1000000000L;
     private static final byte ALL_MONITOR_STATUS = 9;
 
     private static final int TAG_LENGTH = 2;
 
     private static final String CONTENT_VALUE = 
MediaType.APPLICATION_OCTET_STREAM_VALUE + SignConstants.SINGLE_MARK + 
"charset=" + StandardCharsets.UTF_8;
-
+    private final Map<String, ImExportService> imExportServiceMap = new 
HashMap<>();
     @Autowired
     private AppService appService;
-
     @Autowired
     private TagService tagService;
-
     @Autowired
     private CollectJobScheduling collectJobScheduling;
-
     @Autowired
     private MonitorDao monitorDao;
-
     @Autowired
     private ParamDao paramDao;
-
     @Autowired
     private MonitorBindDao monitorBindDao;
-
     @Autowired
     private CollectorDao collectorDao;
-
     @Autowired
     private CollectorMonitorBindDao collectorMonitorBindDao;
-
     @Autowired
     private AlertDefineBindDao alertDefineBindDao;
-
     @Autowired
     private ApplicationContext applicationContext;
-
     @Autowired
     private WarehouseService warehouseService;
-
     @Autowired
     private DashboardService dashboardService;
 
-    private final Map<String, ImExportService> imExportServiceMap = new 
HashMap<>();
-
     public MonitorServiceImpl(List<ImExportService> imExportServiceList) {
         imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), 
it));
     }
@@ -453,7 +440,8 @@ public class MonitorServiceImpl implements MonitorService {
 
         try {
             detectMonitor(monitor, params, collector);
-        } catch (Exception ignored) {}
+        } catch (Exception ignored) {
+        }
 
         // After the update is successfully released, refresh the database
         try {
@@ -704,7 +692,8 @@ public class MonitorServiceImpl implements MonitorService {
             applicationContext.publishEvent(new 
MonitorDeletedEvent(applicationContext, monitor.getId()));
             try {
                 detectMonitor(monitor, params, collector);
-            } catch (Exception ignored) {}
+            } catch (Exception ignored) {
+            }
         }
         monitorDao.saveAll(unManagedMonitors);
     }
@@ -721,10 +710,14 @@ public class MonitorServiceImpl implements MonitorService 
{
             AppCount appCount = appCountMap.getOrDefault(item.getApp(), new 
AppCount());
             appCount.setApp(item.getApp());
             switch (item.getStatus()) {
-                case CommonConstants.MONITOR_UP_CODE -> 
appCount.setAvailableSize(appCount.getAvailableSize() + item.getSize());
-                case CommonConstants.MONITOR_DOWN_CODE -> 
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
-                case CommonConstants.MONITOR_PAUSED_CODE -> 
appCount.setUnManageSize(appCount.getUnManageSize() + item.getSize());
-                default -> {}
+                case CommonConstants.MONITOR_UP_CODE ->
+                        appCount.setAvailableSize(appCount.getAvailableSize() 
+ item.getSize());
+                case CommonConstants.MONITOR_DOWN_CODE ->
+                        
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
+                case CommonConstants.MONITOR_PAUSED_CODE ->
+                        appCount.setUnManageSize(appCount.getUnManageSize() + 
item.getSize());
+                default -> {
+                }
             }
             appCountMap.put(item.getApp(), appCount);
         }
@@ -754,7 +747,7 @@ public class MonitorServiceImpl implements MonitorService {
                 // deep copy original monitor to achieve persist in JPA
                 Monitor newMonitor = 
JsonUtil.fromJson(JsonUtil.toJson(monitor), Monitor.class);
                 if (newMonitor != null) {
-                    copyMonitor(newMonitor, params);   
+                    copyMonitor(newMonitor, params);
                 }
             }, () -> log.warn("can not find the monitor for id :{}", id));
         });
@@ -805,7 +798,7 @@ public class MonitorServiceImpl implements MonitorService {
                 // Delivering a collection task
                 long newJobId = 
collectJobScheduling.updateAsyncCollectJob(appDefine, collector);
                 monitor.setJobId(newJobId);
-                monitorDao.save(monitor);   
+                monitorDao.save(monitor);
             } catch (Exception e) {
                 log.error("update monitor job error when template modify: 
{}.continue", e.getMessage(), e);
             }
@@ -851,7 +844,8 @@ public class MonitorServiceImpl implements MonitorService {
 
         try {
             detectMonitor(monitor, params, collector);
-        } catch (Exception ignored) {}
+        } catch (Exception ignored) {
+        }
 
         try {
             if (collector != null) {
@@ -1015,4 +1009,90 @@ public class MonitorServiceImpl implements 
MonitorService {
                 .filter(tag -> 
!(tag.getName().equals(CommonConstants.TAG_MONITOR_ID) || 
tag.getName().equals(CommonConstants.TAG_MONITOR_NAME)))
                 .collect(Collectors.toList());
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void copyMonitor(Long id) {
+        // Get the source monitor information
+        Optional<Monitor> monitorOptional = monitorDao.findById(id);
+        if (monitorOptional.isEmpty()) {
+            throw new IllegalArgumentException("Monitor not found: " + id);
+        }
+        Monitor sourceMonitor = monitorOptional.get();
+
+        // Get the parameters of source monitor
+        List<Param> sourceParams = paramDao.findParamsByMonitorId(id);
+
+        // Create new monitor object
+        Monitor newMonitor = new Monitor();
+        // Copy basic properties, exclude ID, jobId and status
+        BeanUtils.copyProperties(sourceMonitor, newMonitor, "id", "jobId", 
"status");
+        // Set new name
+        newMonitor.setName(sourceMonitor.getName() + "_copy");
+        // Set initial status
+        newMonitor.setStatus(CommonConstants.MONITOR_UP_CODE);
+        // Set create and update time
+        newMonitor.setGmtCreate(LocalDateTime.now());
+        newMonitor.setGmtUpdate(LocalDateTime.now());
+        // Generate new ID using snowflake algorithm
+        newMonitor.setId(SnowFlakeIdGenerator.generateId());
+        // Save new monitor
+        newMonitor = monitorDao.save(newMonitor);
+
+        // Ensure ID is set
+        if (newMonitor.getId() == null) {
+            throw new RuntimeException("Failed to generate monitor ID");
+        }
+
+        // Copy parameters
+        if (!sourceParams.isEmpty()) {
+            List<Param> newParams = new ArrayList<>();
+            for (Param sourceParam : sourceParams) {
+                Param newParam = new Param();
+                BeanUtils.copyProperties(sourceParam, newParam, "id");
+                newParam.setMonitorId(newMonitor.getId());
+                newParams.add(newParam);
+            }
+            paramDao.saveAll(newParams);
+        }
+
+        try {
+            // Build collect job
+            Job appDefine = appService.getAppDefine(newMonitor.getApp());
+            if (CommonConstants.PROMETHEUS.equals(newMonitor.getApp())) {
+                appDefine.setApp(CommonConstants.PROMETHEUS_APP_PREFIX + 
newMonitor.getName());
+            }
+            // Ensure using correct monitor ID
+            appDefine.setMonitorId(newMonitor.getId());
+            appDefine.setDefaultInterval(newMonitor.getIntervals());
+            appDefine.setCyclic(true);
+            appDefine.setTimestamp(System.currentTimeMillis());
+            List<Configmap> configmaps = sourceParams.stream()
+                    .map(param -> new Configmap(param.getField(), 
param.getParamValue(), param.getType()))
+                    .collect(Collectors.toList());
+            appDefine.setConfigmap(configmaps);
+
+            // Get collector configuration from source monitor
+            Optional<CollectorMonitorBind> bindOptional =
+                    
collectorMonitorBindDao.findCollectorMonitorBindByMonitorId(sourceMonitor.getId());
+            String collector = 
bindOptional.map(CollectorMonitorBind::getCollector).orElse(null);
+
+            // Dispatch collect job
+            long jobId = collectJobScheduling.addAsyncCollectJob(appDefine, 
collector);
+            newMonitor.setJobId(jobId);
+            monitorDao.save(newMonitor);
+
+            // Copy collector binding if exists
+            if (collector != null) {
+                CollectorMonitorBind newBind = CollectorMonitorBind.builder()
+                        .collector(collector)
+                        .monitorId(newMonitor.getId())
+                        .build();
+                collectorMonitorBindDao.save(newBind);
+            }
+        } catch (Exception e) {
+            log.error("Create collect job error: {}", e.getMessage(), e);
+            throw new RuntimeException("Create collect job failed: " + 
e.getMessage());
+        }
+    }
 }
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 65cb0e02b1..bb9920dd27 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
@@ -85,6 +85,12 @@
             </button>
           </nz-upload>
         </li>
+        <li nz-menu-item>
+          <button nz-button (click)="copyMonitor()">
+            <i nz-icon nzType="copy" nzTheme="outline"></i>
+            {{ 'monitors.copy' | i18n }}
+          </button>
+        </li>
       </ul>
     </nz-dropdown-menu>
   </ng-template>
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 7d921d6603..04dca1effa 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
@@ -603,4 +603,30 @@ export class MonitorListComponent implements OnInit, 
OnDestroy {
     }
     return hash;
   }
+
+  copyMonitor() {
+    if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
+      
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), 
'');
+      return;
+    }
+    if (this.checkedMonitorIds.size > 1) {
+      
this.notifySvc.warning(this.i18nSvc.fanyi('monitors.copy.notify.one-select'), 
'');
+      return;
+    }
+    const monitorId = Array.from(this.checkedMonitorIds)[0];
+
+    this.monitorSvc.copyMonitor(monitorId).subscribe(
+      message => {
+        if (message.code === 0) {
+          this.notifySvc.success(this.i18nSvc.fanyi('monitors.copy.success'), 
'');
+          this.loadMonitorTable();
+        } else {
+          this.notifySvc.error(this.i18nSvc.fanyi('monitors.copy.failed'), 
message.msg);
+        }
+      },
+      error => {
+        this.notifySvc.error(this.i18nSvc.fanyi('monitors.copy.failed'), 
error.msg);
+      }
+    );
+  }
 }
diff --git a/web-app/src/app/service/monitor.service.ts 
b/web-app/src/app/service/monitor.service.ts
index 571bc4bfaa..eb576c75dd 100644
--- a/web-app/src/app/service/monitor.service.ts
+++ b/web-app/src/app/service/monitor.service.ts
@@ -166,7 +166,7 @@ export class MonitorService {
       interval: interval
     });
     const options = { params: httpParams };
-    return 
this.http.get<Message<any>>(`/monitor/${monitorId}/metric/${metricFull}`, 
options);
+    return 
this.http.get<Message<any>>(`${monitor_uri}/${monitorId}/metric/${metricFull}`, 
options);
   }
 
   public getAppsMonitorSummary(): Observable<Message<any>> {
@@ -184,4 +184,8 @@ export class MonitorService {
   public deleteGrafanaDashboard(monitorId: number): Observable<Message<any>> {
     return 
this.http.delete<Message<any>>(`${grafana_dashboard_uri}?monitorId=${monitorId}`);
   }
+
+  copyMonitor(id: number): Observable<any> {
+    return this.http.post<Message<any>>(`${monitor_uri}/copy/${id}`, null);
+  }
 }
diff --git a/web-app/src/assets/i18n/en-US.json 
b/web-app/src/assets/i18n/en-US.json
index c7d7210452..6b6c265f27 100644
--- a/web-app/src/assets/i18n/en-US.json
+++ b/web-app/src/assets/i18n/en-US.json
@@ -851,5 +851,10 @@
   "annotation": "Annotation",
   "annotation.bind": "Bind Annotation",
   "annotation.bind.tip": "You can use annotations to mark entity information, 
such as binding annotations of important events to resources.",
-  "label": "Label"
+  "label": "Label",
+  "monitors.copy": "Copy Monitor",
+  "monitors.copy-monitor": "Copy Monitor",
+  "monitors.copy.success": "Copy Monitor Success",
+  "monitors.copy.failed": "Copy Monitor Failed",
+  "monitors.copy.notify.one-select": "Only one monitor can be selected to copy"
 }
diff --git a/web-app/src/assets/i18n/zh-CN.json 
b/web-app/src/assets/i18n/zh-CN.json
index 968c73f62a..e0a88e9e55 100644
--- a/web-app/src/assets/i18n/zh-CN.json
+++ b/web-app/src/assets/i18n/zh-CN.json
@@ -859,5 +859,10 @@
   "alert.inhibit.delete": "删除抑制规则",
   "alert.help.inhibit": 
"告警抑制用于配置告警之间的抑制关系。当某个告警发生时,可以抑制其他告警的产生。例如,当服务器宕机时,可以抑制该服务器上的所有告警。",
   "alert.help.inhibit.link": 
"https://hertzbeat.apache.org/zh-cn/docs/help/alert_inhibit";,
-  "alert.center.tag.search.placeholder": "搜索标签..."
+  "alert.center.tag.search.placeholder": "搜索标签...",
+  "monitors.copy": "复制监控",
+  "monitors.copy-monitor": "复制监控",
+  "monitors.copy.success": "复制监控成功",
+  "monitors.copy.failed": "复制监控失败",
+  "monitors.copy.notify.one-select": "只能选择一个监控进行复制"
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@hertzbeat.apache.org
For additional commands, e-mail: notifications-h...@hertzbeat.apache.org

Reply via email to