From 438c3e67ec4bc9826758b3848b37057a35c4232b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 31 May 2017 11:31:58 +0300 Subject: [PATCH] UI: Add alarm service. --- .../server/controller/AlarmController.java | 4 +- ui/src/app/api/alarm.service.js | 189 ++++++++++++++++++ ui/src/app/app.js | 2 + ui/src/app/common/types.constant.js | 6 + 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 ui/src/app/api/alarm.service.js 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 7d29d57dc9..7a2c273002 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -72,7 +72,7 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) public void ackAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { @@ -86,7 +86,7 @@ public class AlarmController extends BaseController { } } - @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) public void clearAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js new file mode 100644 index 0000000000..d9ab4ff338 --- /dev/null +++ b/ui/src/app/api/alarm.service.js @@ -0,0 +1,189 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export default angular.module('thingsboard.api.alarm', []) + .factory('alarmService', AlarmService) + .name; + +/*@ngInject*/ +function AlarmService($http, $q, $interval, $filter) { + var service = { + getAlarm: getAlarm, + saveAlarm: saveAlarm, + ackAlarm: ackAlarm, + clearAlarm: clearAlarm, + getAlarms: getAlarms, + pollAlarms: pollAlarms, + cancelPollAlarms: cancelPollAlarms + } + + return service; + + function getAlarm(alarmId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + alarmId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function saveAlarm(alarm, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm'; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.post(url, alarm, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function ackAlarm(alarmId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + alarmId + '/ack'; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.post(url, null, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function clearAlarm(alarmId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + alarmId + '/clear'; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.post(url, null, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getAlarms(entityType, entityId, pageLink, alarmStatus, ascOrder, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit; + + if (angular.isDefined(pageLink.startTime)) { + url += '&startTime=' + pageLink.startTime; + } + if (angular.isDefined(pageLink.endTime)) { + url += '&endTime=' + pageLink.endTime; + } + if (angular.isDefined(pageLink.idOffset)) { + url += '&offset=' + pageLink.idOffset; + } + if (alarmStatus) { + url += '&status=' + alarmStatus; + } + if (angular.isDefined(ascOrder) && ascOrder != null) { + url += '&ascOrder=' + (ascOrder ? 'true' : 'false'); + } + + $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.alarmStatus, false, {ignoreLoading: true}).then( + function success(alarms) { + if (!alarmsList) { + alarmsList = []; + } + alarmsList = alarmsList.concat(alarms.data); + if (alarms.hasNext && !alarmsQuery.limit) { + fetchAlarms(alarmsQuery, alarms.nextPageLink, deferred, alarmsList); + } else { + alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']); + deferred.resolve(alarmsList); + } + }, + function fail() { + deferred.reject(); + } + ); + } + + function getAlarmsByQuery(alarmsQuery) { + var deferred = $q.defer(); + var time = Date.now(); + var pageLink; + if (alarmsQuery.limit) { + pageLink = { + limit: alarmsQuery.limit + }; + } else { + pageLink = { + limit: 100, + startTime: time - alarmsQuery.interval + }; + } + fetchAlarms(alarmsQuery, pageLink, deferred); + return deferred.promise; + } + + function onPollAlarms(alarmsQuery) { + getAlarmsByQuery(alarmsQuery).then( + function success(alarms) { + alarmsQuery.onAlarms(alarms); + }, + function fail() {} + ); + } + + function pollAlarms(entityType, entityId, alarmStatus, interval, limit, pollingInterval, onAlarms) { + var alarmsQuery = { + entityType: entityType, + entityId: entityId, + alarmStatus: alarmStatus, + interval: interval, + limit: limit, + onAlarms: onAlarms + }; + onPollAlarms(alarmsQuery); + return $interval(onPollAlarms, pollingInterval, 0, false, alarmsQuery); + } + + function cancelPollAlarms(pollPromise) { + if (angular.isDefined(pollPromise)) { + $interval.cancel(pollPromise); + } + } + +} diff --git a/ui/src/app/app.js b/ui/src/app/app.js index f67be331a9..9ba34b4c29 100644 --- a/ui/src/app/app.js +++ b/ui/src/app/app.js @@ -67,6 +67,7 @@ import thingsboardApiEntityRelation from './api/entity-relation.service'; import thingsboardApiAsset from './api/asset.service'; import thingsboardApiAttribute from './api/attribute.service'; import thingsboardApiEntity from './api/entity.service'; +import thingsboardApiAlarm from './api/alarm.service'; import 'typeface-roboto'; import 'font-awesome/css/font-awesome.min.css'; @@ -124,6 +125,7 @@ angular.module('thingsboard', [ thingsboardApiAsset, thingsboardApiAttribute, thingsboardApiEntity, + thingsboardApiAlarm, uiRouter]) .config(AppConfig) .factory('globalInterceptor', GlobalInterceptor) diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 47ac7a01ed..44e59a260d 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -59,6 +59,12 @@ export default angular.module('thingsboard.types', []) name: "aggregation.none" } }, + alarmStatus: { + activeUnack: "ACTIVE_UNACK", + activeAck: "ACTIVE_ACK", + clearedUnack: "CLEARED_UNACK", + clearedAck: "CLEARED_ACK" + }, position: { top: { value: "top",