Commit 849f53ca4c973c0a39e6de6d3db35c4e0e56d217
1 parent
25af06f2
Fix: don't fetch name of deleted alarm originator. Add ability to create dynamic…
… subscriptions for alarms.
Showing
8 changed files
with
83 additions
and
20 deletions
... | ... | @@ -44,7 +44,7 @@ import java.util.stream.Collectors; |
44 | 44 | @RequestMapping("/api") |
45 | 45 | public class AlarmController extends BaseController { |
46 | 46 | |
47 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
47 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
48 | 48 | @RequestMapping(value = "/alarm/{alarmId}", method = RequestMethod.GET) |
49 | 49 | @ResponseBody |
50 | 50 | public Alarm getAlarmById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { |
... | ... | @@ -57,7 +57,7 @@ public class AlarmController extends BaseController { |
57 | 57 | } |
58 | 58 | } |
59 | 59 | |
60 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
60 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
61 | 61 | @RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET) |
62 | 62 | @ResponseBody |
63 | 63 | public AlarmInfo getAlarmInfoById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { |
... | ... | @@ -70,7 +70,7 @@ public class AlarmController extends BaseController { |
70 | 70 | } |
71 | 71 | } |
72 | 72 | |
73 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
73 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
74 | 74 | @RequestMapping(value = "/alarm", method = RequestMethod.POST) |
75 | 75 | @ResponseBody |
76 | 76 | public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { |
... | ... | @@ -82,7 +82,7 @@ public class AlarmController extends BaseController { |
82 | 82 | } |
83 | 83 | } |
84 | 84 | |
85 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
85 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
86 | 86 | @RequestMapping(value = "/alarm/{alarmId}/ack", method = RequestMethod.POST) |
87 | 87 | @ResponseStatus(value = HttpStatus.OK) |
88 | 88 | public void ackAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { |
... | ... | @@ -96,7 +96,7 @@ public class AlarmController extends BaseController { |
96 | 96 | } |
97 | 97 | } |
98 | 98 | |
99 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
99 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
100 | 100 | @RequestMapping(value = "/alarm/{alarmId}/clear", method = RequestMethod.POST) |
101 | 101 | @ResponseStatus(value = HttpStatus.OK) |
102 | 102 | public void clearAlarm(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { |
... | ... | @@ -110,7 +110,7 @@ public class AlarmController extends BaseController { |
110 | 110 | } |
111 | 111 | } |
112 | 112 | |
113 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
113 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
114 | 114 | @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) |
115 | 115 | @ResponseBody |
116 | 116 | public TimePageData<AlarmInfo> getAlarms( |
... | ... | @@ -143,7 +143,7 @@ public class AlarmController extends BaseController { |
143 | 143 | } |
144 | 144 | } |
145 | 145 | |
146 | - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
146 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
147 | 147 | @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) |
148 | 148 | @ResponseBody |
149 | 149 | public AlarmSeverity getHighestAlarmSeverity( | ... | ... |
... | ... | @@ -227,6 +227,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
227 | 227 | alarmFutures.add(Futures.transform( |
228 | 228 | entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), (Function<String, AlarmInfo>) |
229 | 229 | originatorName -> { |
230 | + if (originatorName == null) { | |
231 | + originatorName = "Deleted"; | |
232 | + } | |
230 | 233 | alarmInfo.setOriginatorName(originatorName); |
231 | 234 | return alarmInfo; |
232 | 235 | } | ... | ... |
... | ... | @@ -109,7 +109,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe |
109 | 109 | default: |
110 | 110 | throw new IllegalStateException("Not Implemented!"); |
111 | 111 | } |
112 | - entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1.getName() ); | |
112 | + entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1 != null ? hasName1.getName() : null ); | |
113 | 113 | return entityName; |
114 | 114 | } |
115 | 115 | ... | ... |
... | ... | @@ -84,7 +84,6 @@ public class BaseRelationService implements RelationService { |
84 | 84 | for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) { |
85 | 85 | inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup)); |
86 | 86 | } |
87 | - Futures.allAsList(inboundRelationsList); | |
88 | 87 | ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList); |
89 | 88 | ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, new AsyncFunction<List<List<EntityRelation>>, List<Boolean>>() { |
90 | 89 | @Override | ... | ... |
... | ... | @@ -35,6 +35,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
35 | 35 | prepareAllowedEntityTypesList: prepareAllowedEntityTypesList, |
36 | 36 | getEntityKeys: getEntityKeys, |
37 | 37 | createDatasourcesFromSubscriptionsInfo: createDatasourcesFromSubscriptionsInfo, |
38 | + createAlarmSourceFromSubscriptionInfo: createAlarmSourceFromSubscriptionInfo, | |
38 | 39 | getRelatedEntities: getRelatedEntities, |
39 | 40 | saveRelatedEntity: saveRelatedEntity, |
40 | 41 | getRelatedEntity: getRelatedEntity, |
... | ... | @@ -757,6 +758,26 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
757 | 758 | return deferred.promise; |
758 | 759 | } |
759 | 760 | |
761 | + function createAlarmSourceFromSubscriptionInfo(subscriptionInfo) { | |
762 | + var deferred = $q.defer(); | |
763 | + var datasources = []; | |
764 | + if (subscriptionInfo.entityId && subscriptionInfo.entityType) { | |
765 | + getEntity(subscriptionInfo.entityType, subscriptionInfo.entityId, {ignoreLoading: true}).then( | |
766 | + function success(entity) { | |
767 | + createDatasourceFromSubscription(subscriptionInfo, datasources, entity); | |
768 | + var alarmSource = datasources[0]; | |
769 | + deferred.resolve(alarmSource); | |
770 | + }, | |
771 | + function fail() { | |
772 | + deferred.reject(); | |
773 | + } | |
774 | + ); | |
775 | + } else { | |
776 | + deferred.reject(); | |
777 | + } | |
778 | + return deferred.promise; | |
779 | + } | |
780 | + | |
760 | 781 | function processSubscriptionsInfo(index, subscriptionsInfo, datasources, deferred) { |
761 | 782 | if (index < subscriptionsInfo.length) { |
762 | 783 | var subscriptionInfo = validateSubscriptionInfo(subscriptionsInfo[index]); |
... | ... | @@ -858,6 +879,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
858 | 879 | if (subscriptionInfo.functions) { |
859 | 880 | createDatasourceKeys(subscriptionInfo.functions, types.dataKeyType.function, datasource, datasources); |
860 | 881 | } |
882 | + if (subscriptionInfo.alarmFields) { | |
883 | + createDatasourceKeys(subscriptionInfo.alarmFields, types.dataKeyType.alarm, datasource, datasources); | |
884 | + } | |
861 | 885 | } |
862 | 886 | |
863 | 887 | function createDatasourceKeys(keyInfos, type, datasource, datasources) { | ... | ... |
... | ... | @@ -61,47 +61,57 @@ export default angular.module('thingsboard.types', []) |
61 | 61 | }, |
62 | 62 | alarmFields: { |
63 | 63 | createdTime: { |
64 | + keyName: 'createdTime', | |
64 | 65 | value: "createdTime", |
65 | 66 | name: "alarm.created-time", |
66 | 67 | time: true |
67 | 68 | }, |
68 | 69 | startTime: { |
70 | + keyName: 'startTime', | |
69 | 71 | value: "startTs", |
70 | 72 | name: "alarm.start-time", |
71 | 73 | time: true |
72 | 74 | }, |
73 | 75 | endTime: { |
76 | + keyName: 'endTime', | |
74 | 77 | value: "endTs", |
75 | 78 | name: "alarm.end-time", |
76 | 79 | time: true |
77 | 80 | }, |
78 | 81 | ackTime: { |
82 | + keyName: 'ackTime', | |
79 | 83 | value: "ackTs", |
80 | 84 | name: "alarm.ack-time", |
81 | 85 | time: true |
82 | 86 | }, |
83 | 87 | clearTime: { |
88 | + keyName: 'clearTime', | |
84 | 89 | value: "clearTs", |
85 | 90 | name: "alarm.clear-time", |
86 | 91 | time: true |
87 | 92 | }, |
88 | 93 | originator: { |
94 | + keyName: 'originator', | |
89 | 95 | value: "originatorName", |
90 | 96 | name: "alarm.originator" |
91 | 97 | }, |
92 | 98 | originatorType: { |
99 | + keyName: 'originatorType', | |
93 | 100 | value: "originator.entityType", |
94 | 101 | name: "alarm.originator-type" |
95 | 102 | }, |
96 | 103 | type: { |
104 | + keyName: 'type', | |
97 | 105 | value: "type", |
98 | 106 | name: "alarm.type" |
99 | 107 | }, |
100 | 108 | severity: { |
109 | + keyName: 'severity', | |
101 | 110 | value: "severity", |
102 | 111 | name: "alarm.severity" |
103 | 112 | }, |
104 | 113 | status: { |
114 | + keyName: 'status', | |
105 | 115 | value: "status", |
106 | 116 | name: "alarm.status" |
107 | 117 | } | ... | ... |
... | ... | @@ -96,11 +96,11 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, types) { |
96 | 96 | }; |
97 | 97 | |
98 | 98 | var defaultAlarmFields = [ |
99 | - 'createdTime', | |
100 | - 'originator', | |
101 | - 'type', | |
102 | - 'severity', | |
103 | - 'status' | |
99 | + types.alarmFields.createdTime.keyName, | |
100 | + types.alarmFields.originator.keyName, | |
101 | + types.alarmFields.type.keyName, | |
102 | + types.alarmFields.severity.keyName, | |
103 | + types.alarmFields.status.keyName | |
104 | 104 | ]; |
105 | 105 | |
106 | 106 | var defaultAlarmDataKeys = []; |
... | ... | @@ -376,10 +376,20 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, types) { |
376 | 376 | } |
377 | 377 | |
378 | 378 | function createKey(keyInfo, type, datasources) { |
379 | + var label; | |
380 | + if (type === types.dataKeyType.alarm && !keyInfo.label) { | |
381 | + var alarmField = types.alarmFields[keyInfo.name]; | |
382 | + if (alarmField) { | |
383 | + label = $translate.instant(alarmField.name)+''; | |
384 | + } | |
385 | + } | |
386 | + if (!label) { | |
387 | + label = keyInfo.label || keyInfo.name; | |
388 | + } | |
379 | 389 | var dataKey = { |
380 | 390 | name: keyInfo.name, |
381 | 391 | type: type, |
382 | - label: keyInfo.label || keyInfo.name, | |
392 | + label: label, | |
383 | 393 | color: genNextColor(datasources), |
384 | 394 | funcBody: keyInfo.funcBody, |
385 | 395 | settings: {}, | ... | ... |
... | ... | @@ -36,6 +36,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
36 | 36 | $scope.rpcEnabled = false; |
37 | 37 | $scope.executingRpcRequest = false; |
38 | 38 | |
39 | + vm.dashboardTimewindow = dashboardTimewindow; | |
40 | + | |
39 | 41 | var gridsterItemInited = false; |
40 | 42 | var subscriptionInited = false; |
41 | 43 | var widgetSizeDetected = false; |
... | ... | @@ -192,9 +194,20 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
192 | 194 | } |
193 | 195 | } |
194 | 196 | |
195 | - entityService.createDatasourcesFromSubscriptionsInfo(subscriptionsInfo).then( | |
196 | - function (datasources) { | |
197 | - options.datasources = datasources; | |
197 | + var createDatasourcesPromise; | |
198 | + if (options.type == types.widgetType.alarm.value) { | |
199 | + createDatasourcesPromise = entityService.createAlarmSourceFromSubscriptionInfo(subscriptionsInfo); | |
200 | + } else { | |
201 | + createDatasourcesPromise = entityService.createDatasourcesFromSubscriptionsInfo(subscriptionsInfo); | |
202 | + } | |
203 | + | |
204 | + createDatasourcesPromise.then( | |
205 | + function (result) { | |
206 | + if (options.type == types.widgetType.alarm.value) { | |
207 | + options.alarmSource = result; | |
208 | + } else { | |
209 | + options.datasources = result; | |
210 | + } | |
198 | 211 | createSubscription(options, subscribe).then( |
199 | 212 | function success(subscription) { |
200 | 213 | if (useDefaultComponents) { |
... | ... | @@ -213,7 +226,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
213 | 226 | |
214 | 227 | function createSubscription(options, subscribe) { |
215 | 228 | var deferred = $q.defer(); |
216 | - options.dashboardTimewindow = dashboardTimewindow; | |
229 | + options.dashboardTimewindow = vm.dashboardTimewindow; | |
217 | 230 | new Subscription(subscriptionContext, options).then( |
218 | 231 | function success(subscription) { |
219 | 232 | widgetContext.subscriptions[subscription.id] = subscription; |
... | ... | @@ -234,7 +247,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
234 | 247 | options.useDashboardTimewindow = angular.isDefined(widget.config.useDashboardTimewindow) |
235 | 248 | ? widget.config.useDashboardTimewindow : true; |
236 | 249 | |
237 | - options.timeWindowConfig = options.useDashboardTimewindow ? dashboardTimewindow : widget.config.timewindow; | |
250 | + options.timeWindowConfig = options.useDashboardTimewindow ? vm.dashboardTimewindow : widget.config.timewindow; | |
238 | 251 | options.legendConfig = null; |
239 | 252 | |
240 | 253 | if ($scope.displayLegend) { |
... | ... | @@ -504,6 +517,10 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
504 | 517 | } |
505 | 518 | }); |
506 | 519 | |
520 | + $scope.$on('dashboardTimewindowChanged', function (event, newDashboardTimewindow) { | |
521 | + vm.dashboardTimewindow = newDashboardTimewindow; | |
522 | + }); | |
523 | + | |
507 | 524 | $scope.$on("$destroy", function () { |
508 | 525 | onDestroy(); |
509 | 526 | }); | ... | ... |