thingsboard-developers

Details

diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index 19c75e7..baee889 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -143,4 +143,30 @@ public class AlarmController extends BaseController {
         }
     }
 
+    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET)
+    @ResponseBody
+    public AlarmSeverity getHighestAlarmSeverity(
+            @PathVariable("entityType") String strEntityType,
+            @PathVariable("entityId") String strEntityId,
+            @RequestParam(required = false) String searchStatus,
+            @RequestParam(required = false) String status
+    ) throws ThingsboardException {
+        checkParameter("EntityId", strEntityId);
+        checkParameter("EntityType", strEntityType);
+        EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
+        AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus);
+        AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status);
+        if (alarmSearchStatus != null && alarmStatus != null) {
+            throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " +
+                    "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
+        }
+        checkEntityId(entityId);
+        try {
+            return alarmService.findHighestAlarmSeverity(entityId, alarmSearchStatus, alarmStatus);
+        } catch (Exception e) {
+            throw handleException(e);
+        }
+    }
+
 }
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
index 3556d51..63fba03 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
@@ -16,10 +16,8 @@
 package org.thingsboard.server.dao.alarm;
 
 import com.google.common.util.concurrent.ListenableFuture;
-import org.thingsboard.server.common.data.alarm.Alarm;
-import org.thingsboard.server.common.data.alarm.AlarmId;
-import org.thingsboard.server.common.data.alarm.AlarmInfo;
-import org.thingsboard.server.common.data.alarm.AlarmQuery;
+import org.thingsboard.server.common.data.alarm.*;
+import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.page.TimePageData;
 
 /**
@@ -39,4 +37,7 @@ public interface AlarmService {
 
     ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query);
 
+    AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus,
+                                           AlarmStatus alarmStatus);
+
 }
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
index 58f7316..06a9b34 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
 import org.thingsboard.server.common.data.alarm.*;
 import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.page.TimePageData;
+import org.thingsboard.server.common.data.page.TimePageLink;
 import org.thingsboard.server.common.data.relation.EntityRelation;
 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
 import org.thingsboard.server.dao.entity.AbstractEntityService;
@@ -46,6 +47,7 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -242,6 +244,46 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
         });
     }
 
+    @Override
+    public AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus,
+                                                                    AlarmStatus alarmStatus) {
+        TimePageLink nextPageLink = new TimePageLink(100);
+        boolean hasNext = true;
+        AlarmSeverity highestSeverity = null;
+        AlarmQuery query;
+        while (hasNext) {
+            query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false);
+            List<AlarmInfo> alarms;
+            try {
+                alarms = alarmDao.findAlarms(query).get();
+            } catch (ExecutionException | InterruptedException e) {
+                log.warn("Failed to find highest alarm severity. EntityId: [{}], AlarmSearchStatus: [{}], AlarmStatus: [{}]",
+                        entityId, alarmSearchStatus, alarmStatus);
+                throw new RuntimeException(e);
+            }
+            hasNext = alarms.size() == nextPageLink.getLimit();
+            if (hasNext) {
+                nextPageLink = new TimePageData<>(alarms, nextPageLink).getNextPageLink();
+            }
+            if (alarms.isEmpty()) {
+                continue;
+            } else {
+                List<AlarmInfo> sorted = new ArrayList(alarms);
+                sorted.sort((p1, p2) -> p1.getSeverity().compareTo(p2.getSeverity()));
+                AlarmSeverity severity = sorted.get(0).getSeverity();
+                if (severity == AlarmSeverity.CRITICAL) {
+                    highestSeverity = severity;
+                    break;
+                } else if (highestSeverity == null) {
+                    highestSeverity = severity;
+                } else {
+                    highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity;
+                }
+            }
+        }
+        return highestSeverity;
+    }
+
     private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException {
         log.debug("Deleting Alarm relation: {}", alarmRelation);
         relationService.deleteRelation(alarmRelation).get();
diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js
index db4cead..3b7a735 100644
--- a/ui/src/app/api/alarm.service.js
+++ b/ui/src/app/api/alarm.service.js
@@ -48,6 +48,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) {
         ackAlarm: ackAlarm,
         clearAlarm: clearAlarm,
         getAlarms: getAlarms,
+        getHighestAlarmSeverity: getHighestAlarmSeverity,
         pollAlarms: pollAlarms,
         cancelPollAlarms: cancelPollAlarms,
         subscribeForAlarms: subscribeForAlarms,
@@ -165,6 +166,23 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) {
         return deferred.promise;
     }
 
+    function getHighestAlarmSeverity(entityType, entityId, alarmSearchStatus, alarmStatus, config) {
+        var deferred = $q.defer();
+        var url = '/api/alarm/highestSeverity/' + entityType + '/' + entityId;
+
+        if (alarmSearchStatus) {
+            url += '?searchStatus=' + alarmSearchStatus;
+        } else if (alarmStatus) {
+            url += '?status=' + alarmStatus;
+        }
+        $http.get(url, config).then(function success(response) {
+            deferred.resolve(response.data);
+        }, function fail() {
+            deferred.reject();
+        });
+        return deferred.promise;
+    }
+
     function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) {
         getAlarms(alarmsQuery.entityType, alarmsQuery.entityId,
             pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus,