Commit 3e0ef116780e6845745adf5e2f95e9cb7f01a892
1 parent
351684a6
TB-63: Add new 'Alarms' tab in entity details.
Showing
41 changed files
with
937 additions
and
48 deletions
... | ... | @@ -58,6 +58,19 @@ public class AlarmController extends BaseController { |
58 | 58 | } |
59 | 59 | |
60 | 60 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
61 | + @RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET) | |
62 | + @ResponseBody | |
63 | + public AlarmInfo getAlarmInfoById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException { | |
64 | + checkParameter("alarmId", strAlarmId); | |
65 | + try { | |
66 | + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); | |
67 | + return checkAlarmInfoId(alarmId); | |
68 | + } catch (Exception e) { | |
69 | + throw handleException(e); | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
61 | 74 | @RequestMapping(value = "/alarm", method = RequestMethod.POST) |
62 | 75 | @ResponseBody |
63 | 76 | public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { | ... | ... |
... | ... | @@ -27,6 +27,7 @@ import org.thingsboard.server.actors.service.ActorService; |
27 | 27 | import org.thingsboard.server.common.data.*; |
28 | 28 | import org.thingsboard.server.common.data.alarm.Alarm; |
29 | 29 | import org.thingsboard.server.common.data.alarm.AlarmId; |
30 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | |
30 | 31 | import org.thingsboard.server.common.data.asset.Asset; |
31 | 32 | import org.thingsboard.server.common.data.id.*; |
32 | 33 | import org.thingsboard.server.common.data.page.TextPageLink; |
... | ... | @@ -351,6 +352,17 @@ public abstract class BaseController { |
351 | 352 | } |
352 | 353 | } |
353 | 354 | |
355 | + AlarmInfo checkAlarmInfoId(AlarmId alarmId) throws ThingsboardException { | |
356 | + try { | |
357 | + validateId(alarmId, "Incorrect alarmId " + alarmId); | |
358 | + AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(alarmId).get(); | |
359 | + checkAlarm(alarmInfo); | |
360 | + return alarmInfo; | |
361 | + } catch (Exception e) { | |
362 | + throw handleException(e, false); | |
363 | + } | |
364 | + } | |
365 | + | |
354 | 366 | protected void checkAlarm(Alarm alarm) throws ThingsboardException { |
355 | 367 | checkNotNull(alarm); |
356 | 368 | checkTenantId(alarm.getTenantId()); | ... | ... |
... | ... | @@ -55,6 +55,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName { |
55 | 55 | |
56 | 56 | public Alarm(Alarm alarm) { |
57 | 57 | super(alarm.getId()); |
58 | + this.createdTime = alarm.getCreatedTime(); | |
58 | 59 | this.tenantId = alarm.getTenantId(); |
59 | 60 | this.type = alarm.getType(); |
60 | 61 | this.originator = alarm.getOriginator(); | ... | ... |
... | ... | @@ -35,6 +35,8 @@ public interface AlarmService { |
35 | 35 | |
36 | 36 | ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId); |
37 | 37 | |
38 | + ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId); | |
39 | + | |
38 | 40 | ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query); |
39 | 41 | |
40 | 42 | } | ... | ... |
... | ... | @@ -199,6 +199,23 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
199 | 199 | } |
200 | 200 | |
201 | 201 | @Override |
202 | + public ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId) { | |
203 | + log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId); | |
204 | + validateId(alarmId, "Incorrect alarmId " + alarmId); | |
205 | + return Futures.transform(alarmDao.findAlarmByIdAsync(alarmId.getId()), | |
206 | + (AsyncFunction<Alarm, AlarmInfo>) alarm1 -> { | |
207 | + AlarmInfo alarmInfo = new AlarmInfo(alarm1); | |
208 | + return Futures.transform( | |
209 | + entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), (Function<String, AlarmInfo>) | |
210 | + originatorName -> { | |
211 | + alarmInfo.setOriginatorName(originatorName); | |
212 | + return alarmInfo; | |
213 | + } | |
214 | + ); | |
215 | + }); | |
216 | + } | |
217 | + | |
218 | + @Override | |
202 | 219 | public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query) { |
203 | 220 | ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(query); |
204 | 221 | if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import 'brace/ext/language_tools'; | |
17 | +import 'brace/mode/json'; | |
18 | +import 'brace/theme/github'; | |
19 | +import beautify from 'js-beautify'; | |
20 | + | |
21 | +import './alarm-details-dialog.scss'; | |
22 | + | |
23 | +const js_beautify = beautify.js; | |
24 | + | |
25 | +/*@ngInject*/ | |
26 | +export default function AlarmDetailsDialogController($mdDialog, $filter, $translate, types, alarmService, alarmId, showingCallback) { | |
27 | + | |
28 | + var vm = this; | |
29 | + | |
30 | + vm.alarmId = alarmId; | |
31 | + vm.types = types; | |
32 | + vm.alarm = null; | |
33 | + | |
34 | + vm.alarmUpdated = false; | |
35 | + | |
36 | + showingCallback.onShowing = function(scope, element) { | |
37 | + updateEditorSize(element); | |
38 | + } | |
39 | + | |
40 | + vm.alarmDetailsOptions = { | |
41 | + useWrapMode: false, | |
42 | + mode: 'json', | |
43 | + showGutter: false, | |
44 | + showPrintMargin: false, | |
45 | + theme: 'github', | |
46 | + advanced: { | |
47 | + enableSnippets: false, | |
48 | + enableBasicAutocompletion: false, | |
49 | + enableLiveAutocompletion: false | |
50 | + }, | |
51 | + onLoad: function (_ace) { | |
52 | + vm.editor = _ace; | |
53 | + } | |
54 | + }; | |
55 | + | |
56 | + vm.close = close; | |
57 | + vm.acknowledge = acknowledge; | |
58 | + vm.clear = clear; | |
59 | + | |
60 | + loadAlarm(); | |
61 | + | |
62 | + function updateEditorSize(element) { | |
63 | + var newWidth = 600; | |
64 | + var newHeight = 200; | |
65 | + angular.element('#tb-alarm-details', element).height(newHeight.toString() + "px") | |
66 | + .width(newWidth.toString() + "px"); | |
67 | + vm.editor.resize(); | |
68 | + } | |
69 | + | |
70 | + function loadAlarm() { | |
71 | + alarmService.getAlarmInfo(vm.alarmId).then( | |
72 | + function success(alarm) { | |
73 | + vm.alarm = alarm; | |
74 | + loadAlarmFields(); | |
75 | + }, | |
76 | + function fail() { | |
77 | + vm.alarm = null; | |
78 | + } | |
79 | + ); | |
80 | + } | |
81 | + | |
82 | + function loadAlarmFields() { | |
83 | + vm.createdTime = $filter('date')(vm.alarm.createdTime, 'yyyy-MM-dd HH:mm:ss'); | |
84 | + vm.startTime = null; | |
85 | + if (vm.alarm.startTs) { | |
86 | + vm.startTime = $filter('date')(vm.alarm.startTs, 'yyyy-MM-dd HH:mm:ss'); | |
87 | + } | |
88 | + vm.endTime = null; | |
89 | + if (vm.alarm.endTs) { | |
90 | + vm.endTime = $filter('date')(vm.alarm.endTs, 'yyyy-MM-dd HH:mm:ss'); | |
91 | + } | |
92 | + vm.ackTime = null; | |
93 | + if (vm.alarm.ackTs) { | |
94 | + vm.ackTime = $filter('date')(vm.alarm.ackTs, 'yyyy-MM-dd HH:mm:ss') | |
95 | + } | |
96 | + vm.clearTime = null; | |
97 | + if (vm.alarm.clearTs) { | |
98 | + vm.clearTime = $filter('date')(vm.alarm.clearTs, 'yyyy-MM-dd HH:mm:ss'); | |
99 | + } | |
100 | + | |
101 | + vm.alarmSeverity = $translate.instant(types.alarmSeverity[vm.alarm.severity].name); | |
102 | + | |
103 | + vm.alarmStatus = $translate.instant('alarm.display-status.' + vm.alarm.status); | |
104 | + | |
105 | + vm.alarmDetails = null; | |
106 | + if (vm.alarm.details) { | |
107 | + vm.alarmDetails = angular.toJson(vm.alarm.details); | |
108 | + vm.alarmDetails = js_beautify(vm.alarmDetails, {indent_size: 4}); | |
109 | + } | |
110 | + } | |
111 | + | |
112 | + function acknowledge () { | |
113 | + alarmService.ackAlarm(vm.alarmId).then( | |
114 | + function success() { | |
115 | + vm.alarmUpdated = true; | |
116 | + loadAlarm(); | |
117 | + } | |
118 | + ); | |
119 | + } | |
120 | + | |
121 | + function clear () { | |
122 | + alarmService.clearAlarm(vm.alarmId).then( | |
123 | + function success() { | |
124 | + vm.alarmUpdated = true; | |
125 | + loadAlarm(); | |
126 | + } | |
127 | + ); | |
128 | + } | |
129 | + | |
130 | + function close () { | |
131 | + $mdDialog.hide(vm.alarmUpdated ? vm.alarm : null); | |
132 | + } | |
133 | + | |
134 | +} | ... | ... |
ui/src/app/alarm/alarm-details-dialog.scss
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +.tb-alarm-details-panel { | |
18 | + margin-left: 15px; | |
19 | + border: 1px solid #C0C0C0; | |
20 | + height: 100%; | |
21 | + #tb-alarm-details { | |
22 | + min-width: 600px; | |
23 | + min-height: 200px; | |
24 | + width: 100%; | |
25 | + height: 100%; | |
26 | + } | |
27 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-dialog aria-label="{{ 'alarm.alarm-details' | translate }}"> | |
19 | + <md-toolbar> | |
20 | + <div class="md-toolbar-tools"> | |
21 | + <h2 translate>alarm.alarm-details</h2> | |
22 | + <span flex></span> | |
23 | + <md-button class="md-icon-button" ng-click="vm.close()"> | |
24 | + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> | |
25 | + </md-button> | |
26 | + </div> | |
27 | + </md-toolbar> | |
28 | + <md-dialog-content> | |
29 | + <div class="md-dialog-content" layout="column"> | |
30 | + <div layout="row"> | |
31 | + <md-input-container class="md-block"> | |
32 | + <label translate>alarm.created-time</label> | |
33 | + <input ng-model="vm.createdTime" readonly> | |
34 | + </md-input-container> | |
35 | + <md-input-container flex class="md-block"> | |
36 | + <label translate>alarm.originator</label> | |
37 | + <input ng-model="vm.alarm.originatorName" readonly> | |
38 | + </md-input-container> | |
39 | + </div> | |
40 | + <div layout="row" ng-if="vm.startTime || vm.endTime"> | |
41 | + <md-input-container ng-if="vm.startTime" flex class="md-block"> | |
42 | + <label translate>alarm.start-time</label> | |
43 | + <input ng-model="vm.startTime" readonly> | |
44 | + </md-input-container> | |
45 | + <md-input-container ng-if="vm.endTime" flex class="md-block"> | |
46 | + <label translate>alarm.end-time</label> | |
47 | + <input ng-model="vm.endTime" readonly> | |
48 | + </md-input-container> | |
49 | + <span flex ng-if="!vm.startTime || !vm.endTime"></span> | |
50 | + </div> | |
51 | + <div layout="row" ng-if="vm.ackTime || vm.clearTime"> | |
52 | + <md-input-container ng-if="vm.ackTime" flex class="md-block"> | |
53 | + <label translate>alarm.ack-time</label> | |
54 | + <input ng-model="vm.ackTime" readonly> | |
55 | + </md-input-container> | |
56 | + <md-input-container ng-if="vm.clearTime" flex class="md-block"> | |
57 | + <label translate>alarm.clear-time</label> | |
58 | + <input ng-model="vm.clearTime" readonly> | |
59 | + </md-input-container> | |
60 | + <span flex ng-if="!vm.ackTime || !vm.clearTime"></span> | |
61 | + </div> | |
62 | + <div layout="row"> | |
63 | + <md-input-container flex class="md-block"> | |
64 | + <label translate>alarm.type</label> | |
65 | + <input ng-model="vm.alarm.type" readonly> | |
66 | + </md-input-container> | |
67 | + <md-input-container flex class="md-block"> | |
68 | + <label translate>alarm.severity</label> | |
69 | + <input class="tb-severity" ng-class="vm.types.alarmSeverity[vm.alarm.severity].class" | |
70 | + ng-model="vm.alarmSeverity" readonly> | |
71 | + </md-input-container> | |
72 | + <md-input-container flex class="md-block"> | |
73 | + <label translate>alarm.status</label> | |
74 | + <input ng-model="vm.alarmStatus" readonly> | |
75 | + </md-input-container> | |
76 | + </div> | |
77 | + <div class="md-caption" style="padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>alarm.details</div> | |
78 | + <div flex class="tb-alarm-details-panel" layout="column"> | |
79 | + <div flex id="tb-alarm-details" readonly | |
80 | + ui-ace="vm.alarmDetailsOptions" | |
81 | + ng-model="vm.alarmDetails"> | |
82 | + </div> | |
83 | + </div> | |
84 | + </div> | |
85 | + </md-dialog-content> | |
86 | + <md-dialog-actions layout="row"> | |
87 | + <md-button ng-if="vm.alarm.status==vm.types.alarmStatus.activeUnack || | |
88 | + vm.alarm.status==vm.types.alarmStatus.clearedUnack" | |
89 | + class="md-raised md-primary" | |
90 | + ng-disabled="loading" | |
91 | + ng-click="vm.acknowledge()" | |
92 | + style="margin-right:20px;">{{ 'alarm.acknowledge' | | |
93 | + translate }} | |
94 | + </md-button> | |
95 | + <md-button ng-if="vm.alarm.status==vm.types.alarmStatus.activeAck || | |
96 | + vm.alarm.status==vm.types.alarmStatus.activeUnack" | |
97 | + class="md-raised md-primary" | |
98 | + ng-disabled="loading" | |
99 | + ng-click="vm.clear()">{{ 'alarm.clear' | | |
100 | + translate }} | |
101 | + </md-button> | |
102 | + <span flex></span> | |
103 | + <md-button ng-disabled="loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' | | |
104 | + translate }} | |
105 | + </md-button> | |
106 | + </md-dialog-actions> | |
107 | +</md-dialog> | ... | ... |
ui/src/app/alarm/alarm-header.directive.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +/* eslint-disable import/no-unresolved, import/default */ | |
17 | + | |
18 | +import alarmHeaderTemplate from './alarm-header.tpl.html'; | |
19 | + | |
20 | +/* eslint-enable import/no-unresolved, import/default */ | |
21 | + | |
22 | +/*@ngInject*/ | |
23 | +export default function AlarmHeaderDirective($compile, $templateCache) { | |
24 | + | |
25 | + var linker = function (scope, element) { | |
26 | + | |
27 | + var template = $templateCache.get(alarmHeaderTemplate); | |
28 | + element.html(template); | |
29 | + $compile(element.contents())(scope); | |
30 | + | |
31 | + } | |
32 | + | |
33 | + return { | |
34 | + restrict: "A", | |
35 | + replace: false, | |
36 | + link: linker, | |
37 | + scope: false | |
38 | + }; | |
39 | +} | ... | ... |
ui/src/app/alarm/alarm-header.tpl.html
renamed from
ui/src/app/event/event-header-alarm.tpl.html
... | ... | @@ -15,6 +15,9 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<div translate class="tb-cell" flex="30">event.event-time</div> | |
19 | -<div translate class="tb-cell" flex="20">event.server</div> | |
20 | -<div translate class="tb-cell" flex="20">event.alarm</div> | |
18 | +<div translate class="tb-cell" flex="30">alarm.created-time</div> | |
19 | +<div translate class="tb-cell" flex="15">alarm.originator</div> | |
20 | +<div translate class="tb-cell" flex="20">alarm.type</div> | |
21 | +<div translate class="tb-cell" flex="15">alarm.severity</div> | |
22 | +<div translate class="tb-cell" flex="20">alarm.status</div> | |
23 | +<div translate class="tb-cell" flex="15">alarm.details</div> | ... | ... |
ui/src/app/alarm/alarm-row.directive.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +/* eslint-disable import/no-unresolved, import/default */ | |
17 | + | |
18 | +import alarmDetailsDialogTemplate from './alarm-details-dialog.tpl.html'; | |
19 | + | |
20 | +import alarmRowTemplate from './alarm-row.tpl.html'; | |
21 | + | |
22 | +/* eslint-enable import/no-unresolved, import/default */ | |
23 | + | |
24 | +/*@ngInject*/ | |
25 | +export default function AlarmRowDirective($compile, $templateCache, types, $mdDialog, $document) { | |
26 | + | |
27 | + var linker = function (scope, element, attrs) { | |
28 | + | |
29 | + var template = $templateCache.get(alarmRowTemplate); | |
30 | + element.html(template); | |
31 | + | |
32 | + scope.alarm = attrs.alarm; | |
33 | + scope.types = types; | |
34 | + | |
35 | + scope.showAlarmDetails = function($event) { | |
36 | + var onShowingCallback = { | |
37 | + onShowing: function(){} | |
38 | + } | |
39 | + $mdDialog.show({ | |
40 | + controller: 'AlarmDetailsDialogController', | |
41 | + controllerAs: 'vm', | |
42 | + templateUrl: alarmDetailsDialogTemplate, | |
43 | + locals: {alarmId: scope.alarm.id.id, showingCallback: onShowingCallback}, | |
44 | + parent: angular.element($document[0].body), | |
45 | + targetEvent: $event, | |
46 | + fullscreen: true, | |
47 | + skipHide: true, | |
48 | + onShowing: function(scope, element) { | |
49 | + onShowingCallback.onShowing(scope, element); | |
50 | + } | |
51 | + }).then(function (alarm) { | |
52 | + if (alarm) { | |
53 | + scope.alarm = alarm; | |
54 | + } | |
55 | + }); | |
56 | + } | |
57 | + | |
58 | + $compile(element.contents())(scope); | |
59 | + } | |
60 | + | |
61 | + return { | |
62 | + restrict: "A", | |
63 | + replace: false, | |
64 | + link: linker, | |
65 | + scope: false | |
66 | + }; | |
67 | +} | ... | ... |
ui/src/app/alarm/alarm-row.tpl.html
renamed from
ui/src/app/event/event-row-alarm.tpl.html
... | ... | @@ -15,14 +15,19 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<div class="tb-cell" flex="30">{{event.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div> | |
19 | -<div class="tb-cell" flex="20">{{event.body.server}}</div> | |
20 | -<div class="tb-cell" flex="20"> | |
21 | - <md-button ng-if="event.body.body" class="md-icon-button md-primary" | |
22 | - ng-click="showContent($event, event.body.body, 'event.alarm')" | |
18 | +<div class="tb-cell" flex="30">{{alarm.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div> | |
19 | +<div class="tb-cell" flex="15">{{alarm.originatorName}}</div> | |
20 | +<div class="tb-cell" flex="20">{{alarm.type}}</div> | |
21 | +<div class="tb-cell tb-severity" flex="15" ng-class="types.alarmSeverity[alarm.severity].class"> | |
22 | + {{ alarm ? (types.alarmSeverity[alarm.severity].name | translate) : '' }} | |
23 | +</div> | |
24 | +<div class="tb-cell" flex="20">{{ alarm ? (('alarm.display-status.' + alarm.status) | translate) : '' }}</div> | |
25 | +<div class="tb-cell" flex="15"> | |
26 | + <md-button class="md-icon-button md-primary" | |
27 | + ng-click="showAlarmDetails($event)" | |
23 | 28 | aria-label="{{ 'action.view' | translate }}"> |
24 | 29 | <md-tooltip md-direction="top"> |
25 | - {{ 'action.view' | translate }} | |
30 | + {{ 'alarm.details' | translate }} | |
26 | 31 | </md-tooltip> |
27 | 32 | <md-icon aria-label="{{ 'action.view' | translate }}" |
28 | 33 | class="material-icons"> | ... | ... |
ui/src/app/alarm/alarm-table.directive.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import './alarm.scss'; | |
17 | + | |
18 | +/* eslint-disable import/no-unresolved, import/default */ | |
19 | + | |
20 | +import alarmTableTemplate from './alarm-table.tpl.html'; | |
21 | + | |
22 | +/* eslint-enable import/no-unresolved, import/default */ | |
23 | + | |
24 | +/*@ngInject*/ | |
25 | +export default function AlarmTableDirective($compile, $templateCache, $rootScope, types, alarmService) { | |
26 | + | |
27 | + var linker = function (scope, element) { | |
28 | + | |
29 | + var template = $templateCache.get(alarmTableTemplate); | |
30 | + | |
31 | + element.html(template); | |
32 | + | |
33 | + scope.types = types; | |
34 | + | |
35 | + scope.alarmSearchStatus = types.alarmSearchStatus.any; | |
36 | + | |
37 | + var pageSize = 20; | |
38 | + var startTime = 0; | |
39 | + var endTime = 0; | |
40 | + | |
41 | + scope.timewindow = { | |
42 | + history: { | |
43 | + timewindowMs: 24 * 60 * 60 * 1000 // 1 day | |
44 | + } | |
45 | + } | |
46 | + | |
47 | + scope.topIndex = 0; | |
48 | + | |
49 | + scope.theAlarms = { | |
50 | + getItemAtIndex: function (index) { | |
51 | + if (index > scope.alarms.data.length) { | |
52 | + scope.theAlarms.fetchMoreItems_(index); | |
53 | + return null; | |
54 | + } | |
55 | + var item = scope.alarms.data[index]; | |
56 | + if (item) { | |
57 | + item.indexNumber = index + 1; | |
58 | + } | |
59 | + return item; | |
60 | + }, | |
61 | + | |
62 | + getLength: function () { | |
63 | + if (scope.alarms.hasNext) { | |
64 | + return scope.alarms.data.length + scope.alarms.nextPageLink.limit; | |
65 | + } else { | |
66 | + return scope.alarms.data.length; | |
67 | + } | |
68 | + }, | |
69 | + | |
70 | + fetchMoreItems_: function () { | |
71 | + if (scope.alarms.hasNext && !scope.alarms.pending) { | |
72 | + if (scope.entityType && scope.entityId && scope.alarmSearchStatus) { | |
73 | + var promise = alarmService.getAlarms(scope.entityType, scope.entityId, | |
74 | + scope.alarms.nextPageLink, scope.alarmSearchStatus, null, true, false); | |
75 | + if (promise) { | |
76 | + scope.alarms.pending = true; | |
77 | + promise.then( | |
78 | + function success(alarms) { | |
79 | + scope.alarms.data = scope.alarms.data.concat(alarms.data); | |
80 | + scope.alarms.nextPageLink = alarms.nextPageLink; | |
81 | + scope.alarms.hasNext = alarms.hasNext; | |
82 | + if (scope.alarms.hasNext) { | |
83 | + scope.alarms.nextPageLink.limit = pageSize; | |
84 | + } | |
85 | + scope.alarms.pending = false; | |
86 | + }, | |
87 | + function fail() { | |
88 | + scope.alarms.hasNext = false; | |
89 | + scope.alarms.pending = false; | |
90 | + }); | |
91 | + } else { | |
92 | + scope.alarms.hasNext = false; | |
93 | + } | |
94 | + } else { | |
95 | + scope.alarms.hasNext = false; | |
96 | + } | |
97 | + } | |
98 | + } | |
99 | + }; | |
100 | + | |
101 | + scope.$watch("entityId", function(newVal, prevVal) { | |
102 | + if (newVal && !angular.equals(newVal, prevVal)) { | |
103 | + resetFilter(); | |
104 | + reload(); | |
105 | + } | |
106 | + }); | |
107 | + | |
108 | + | |
109 | + | |
110 | + function destroyWatchers() { | |
111 | + if (scope.alarmSearchStatusWatchHandle) { | |
112 | + scope.alarmSearchStatusWatchHandle(); | |
113 | + scope.alarmSearchStatusWatchHandle = null; | |
114 | + } | |
115 | + if (scope.timewindowWatchHandle) { | |
116 | + scope.timewindowWatchHandle(); | |
117 | + scope.timewindowWatchHandle = null; | |
118 | + } | |
119 | + } | |
120 | + | |
121 | + function initWatchers() { | |
122 | + scope.alarmSearchStatusWatchHandle = scope.$watch("alarmSearchStatus", function(newVal, prevVal) { | |
123 | + if (newVal && !angular.equals(newVal, prevVal)) { | |
124 | + reload(); | |
125 | + } | |
126 | + }); | |
127 | + scope.timewindowWatchHandle = scope.$watch("timewindow", function(newVal, prevVal) { | |
128 | + if (newVal && !angular.equals(newVal, prevVal)) { | |
129 | + reload(); | |
130 | + } | |
131 | + }, true); | |
132 | + } | |
133 | + | |
134 | + function resetFilter() { | |
135 | + destroyWatchers(); | |
136 | + scope.timewindow = { | |
137 | + history: { | |
138 | + timewindowMs: 24 * 60 * 60 * 1000 // 1 day | |
139 | + } | |
140 | + }; | |
141 | + scope.alarmSearchStatus = types.alarmSearchStatus.any; | |
142 | + initWatchers(); | |
143 | + } | |
144 | + | |
145 | + function updateTimeWindowRange () { | |
146 | + if (scope.timewindow.history.timewindowMs) { | |
147 | + var currentTime = (new Date).getTime(); | |
148 | + startTime = currentTime - scope.timewindow.history.timewindowMs; | |
149 | + endTime = currentTime; | |
150 | + } else { | |
151 | + startTime = scope.timewindow.history.fixedTimewindow.startTimeMs; | |
152 | + endTime = scope.timewindow.history.fixedTimewindow.endTimeMs; | |
153 | + } | |
154 | + } | |
155 | + | |
156 | + function reload () { | |
157 | + scope.topIndex = 0; | |
158 | + scope.selected = []; | |
159 | + updateTimeWindowRange(); | |
160 | + scope.alarms = { | |
161 | + data: [], | |
162 | + nextPageLink: { | |
163 | + limit: pageSize, | |
164 | + startTime: startTime, | |
165 | + endTime: endTime | |
166 | + }, | |
167 | + hasNext: true, | |
168 | + pending: false | |
169 | + }; | |
170 | + scope.theAlarms.getItemAtIndex(pageSize); | |
171 | + } | |
172 | + | |
173 | + scope.noData = function() { | |
174 | + return scope.alarms.data.length == 0 && !scope.alarms.hasNext; | |
175 | + } | |
176 | + | |
177 | + scope.hasData = function() { | |
178 | + return scope.alarms.data.length > 0; | |
179 | + } | |
180 | + | |
181 | + scope.loading = function() { | |
182 | + return $rootScope.loading; | |
183 | + } | |
184 | + | |
185 | + scope.hasScroll = function() { | |
186 | + var repeatContainer = scope.repeatContainer[0]; | |
187 | + if (repeatContainer) { | |
188 | + var scrollElement = repeatContainer.children[0]; | |
189 | + if (scrollElement) { | |
190 | + return scrollElement.scrollHeight > scrollElement.clientHeight; | |
191 | + } | |
192 | + } | |
193 | + return false; | |
194 | + } | |
195 | + | |
196 | + reload(); | |
197 | + | |
198 | + initWatchers(); | |
199 | + | |
200 | + $compile(element.contents())(scope); | |
201 | + } | |
202 | + | |
203 | + return { | |
204 | + restrict: "E", | |
205 | + link: linker, | |
206 | + scope: { | |
207 | + entityType: '=', | |
208 | + entityId: '=' | |
209 | + } | |
210 | + }; | |
211 | +} | ... | ... |
ui/src/app/alarm/alarm-table.tpl.html
0 → 100644
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-content flex class="md-padding tb-absolute-fill" layout="column"> | |
19 | + <section layout="row"> | |
20 | + <md-input-container class="md-block" style="width: 200px;"> | |
21 | + <label translate>alarm.alarm-status</label> | |
22 | + <md-select ng-model="alarmSearchStatus" ng-disabled="loading()"> | |
23 | + <md-option ng-repeat="searchStatus in types.alarmSearchStatus" ng-value="searchStatus"> | |
24 | + {{ ('alarm.search-status.' + searchStatus) | translate }} | |
25 | + </md-option> | |
26 | + </md-select> | |
27 | + </md-input-container> | |
28 | + <tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow> | |
29 | + </section> | |
30 | + <div flex layout="column" class="tb-alarm-container md-whiteframe-z1"> | |
31 | + <md-list flex layout="column" class="tb-alarm-table"> | |
32 | + <md-list class="tb-row tb-header" layout="row" tb-alarm-header> | |
33 | + </md-list> | |
34 | + <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()" | |
35 | + ng-show="loading()"></md-progress-linear> | |
36 | + <md-divider></md-divider> | |
37 | + <span translate layout-align="center center" | |
38 | + style="margin-top: 25px;" | |
39 | + class="tb-prompt" ng-show="noData()">alarm.no-alarms-prompt</span> | |
40 | + <md-virtual-repeat-container ng-show="hasData()" flex md-top-index="topIndex" tb-scope-element="repeatContainer"> | |
41 | + <md-list-item md-virtual-repeat="alarm in theAlarms" md-on-demand flex ng-style="hasScroll() ? {'margin-right':'-15px'} : {}"> | |
42 | + <md-list class="tb-row" flex layout="row" tb-alarm-row alarm="{{alarm}}"> | |
43 | + </md-list> | |
44 | + <md-divider flex></md-divider> | |
45 | + </md-list-item> | |
46 | + </md-virtual-repeat-container> | |
47 | + </md-list> | |
48 | + </div> | |
49 | +</md-content> | ... | ... |
ui/src/app/alarm/alarm.scss
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +.tb-alarm-container { | |
18 | + overflow-x: auto; | |
19 | +} | |
20 | + | |
21 | +md-list.tb-alarm-table { | |
22 | + padding: 0px; | |
23 | + min-width: 700px; | |
24 | + | |
25 | + md-list-item { | |
26 | + padding: 0px; | |
27 | + } | |
28 | + | |
29 | + .tb-row { | |
30 | + height: 48px; | |
31 | + padding: 0px; | |
32 | + overflow: hidden; | |
33 | + } | |
34 | + | |
35 | + .tb-row:hover { | |
36 | + background-color: #EEEEEE; | |
37 | + } | |
38 | + | |
39 | + .tb-header:hover { | |
40 | + background: none; | |
41 | + } | |
42 | + | |
43 | + .tb-header { | |
44 | + .tb-cell { | |
45 | + color: rgba(0,0,0,.54); | |
46 | + font-size: 12px; | |
47 | + font-weight: 700; | |
48 | + white-space: nowrap; | |
49 | + background: none; | |
50 | + } | |
51 | + } | |
52 | + | |
53 | + .tb-cell { | |
54 | + padding: 0 24px; | |
55 | + margin: auto 0; | |
56 | + color: rgba(0,0,0,.87); | |
57 | + font-size: 13px; | |
58 | + vertical-align: middle; | |
59 | + text-align: left; | |
60 | + overflow: hidden; | |
61 | + .md-button { | |
62 | + padding: 0; | |
63 | + margin: 0; | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + .tb-cell.tb-number { | |
68 | + text-align: right; | |
69 | + } | |
70 | + | |
71 | +} | |
72 | + | |
73 | +#tb-alarm-content { | |
74 | + min-width: 400px; | |
75 | + min-height: 50px; | |
76 | + width: 100%; | |
77 | + height: 100%; | |
78 | +} | ... | ... |
ui/src/app/alarm/index.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +import AlarmDetailsDialogController from './alarm-details-dialog.controller'; | |
18 | +import AlarmHeaderDirective from './alarm-header.directive'; | |
19 | +import AlarmRowDirective from './alarm-row.directive'; | |
20 | +import AlarmTableDirective from './alarm-table.directive'; | |
21 | + | |
22 | +export default angular.module('thingsboard.alarm', []) | |
23 | + .controller('AlarmDetailsDialogController', AlarmDetailsDialogController) | |
24 | + .directive('tbAlarmHeader', AlarmHeaderDirective) | |
25 | + .directive('tbAlarmRow', AlarmRowDirective) | |
26 | + .directive('tbAlarmTable', AlarmTableDirective) | |
27 | + .name; | ... | ... |
... | ... | @@ -21,6 +21,7 @@ export default angular.module('thingsboard.api.alarm', []) |
21 | 21 | function AlarmService($http, $q, $interval, $filter) { |
22 | 22 | var service = { |
23 | 23 | getAlarm: getAlarm, |
24 | + getAlarmInfo: getAlarmInfo, | |
24 | 25 | saveAlarm: saveAlarm, |
25 | 26 | ackAlarm: ackAlarm, |
26 | 27 | clearAlarm: clearAlarm, |
... | ... | @@ -46,6 +47,21 @@ function AlarmService($http, $q, $interval, $filter) { |
46 | 47 | return deferred.promise; |
47 | 48 | } |
48 | 49 | |
50 | + function getAlarmInfo(alarmId, ignoreErrors, config) { | |
51 | + var deferred = $q.defer(); | |
52 | + var url = '/api/alarm/info/' + alarmId; | |
53 | + if (!config) { | |
54 | + config = {}; | |
55 | + } | |
56 | + config = Object.assign(config, { ignoreErrors: ignoreErrors }); | |
57 | + $http.get(url, config).then(function success(response) { | |
58 | + deferred.resolve(response.data); | |
59 | + }, function fail() { | |
60 | + deferred.reject(); | |
61 | + }); | |
62 | + return deferred.promise; | |
63 | + } | |
64 | + | |
49 | 65 | function saveAlarm(alarm, ignoreErrors, config) { |
50 | 66 | var deferred = $q.defer(); |
51 | 67 | var url = '/api/alarm'; | ... | ... |
... | ... | @@ -48,11 +48,16 @@ |
48 | 48 | disable-attribute-scope-selection="true"> |
49 | 49 | </tb-attribute-table> |
50 | 50 | </md-tab> |
51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}"> | |
52 | + <tb-alarm-table flex entity-type="vm.types.entityType.asset" | |
53 | + entity-id="vm.grid.operatingItem().id.id"> | |
54 | + </tb-alarm-table> | |
55 | + </md-tab> | |
51 | 56 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'asset.events' | translate }}"> |
52 | 57 | <tb-event-table flex entity-type="vm.types.entityType.asset" |
53 | 58 | entity-id="vm.grid.operatingItem().id.id" |
54 | 59 | tenant-id="vm.grid.operatingItem().tenantId.id" |
55 | - default-event-type="{{vm.types.eventType.alarm.value}}"> | |
60 | + default-event-type="{{vm.types.eventType.error.value}}"> | |
56 | 61 | </tb-event-table> |
57 | 62 | </md-tab> |
58 | 63 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | import uiRouter from 'angular-ui-router'; |
17 | 17 | import thingsboardGrid from '../components/grid.directive'; |
18 | -import thingsboardEvent from '../event'; | |
19 | 18 | import thingsboardApiUser from '../api/user.service'; |
20 | 19 | import thingsboardApiAsset from '../api/asset.service'; |
21 | 20 | import thingsboardApiCustomer from '../api/customer.service'; |
... | ... | @@ -29,7 +28,6 @@ import AssetDirective from './asset.directive'; |
29 | 28 | export default angular.module('thingsboard.asset', [ |
30 | 29 | uiRouter, |
31 | 30 | thingsboardGrid, |
32 | - thingsboardEvent, | |
33 | 31 | thingsboardApiUser, |
34 | 32 | thingsboardApiAsset, |
35 | 33 | thingsboardApiCustomer | ... | ... |
... | ... | @@ -72,6 +72,28 @@ export default angular.module('thingsboard.types', []) |
72 | 72 | ack: "ACK", |
73 | 73 | unack: "UNACK" |
74 | 74 | }, |
75 | + alarmSeverity: { | |
76 | + "CRITICAL": { | |
77 | + name: "alarm.severity-critical", | |
78 | + class: "tb-critical" | |
79 | + }, | |
80 | + "MAJOR": { | |
81 | + name: "alarm.severity-major", | |
82 | + class: "tb-major" | |
83 | + }, | |
84 | + "MINOR": { | |
85 | + name: "alarm.severity-minor", | |
86 | + class: "tb-minor" | |
87 | + }, | |
88 | + "WARNING": { | |
89 | + name: "alarm.severity-warning", | |
90 | + class: "tb-warning" | |
91 | + }, | |
92 | + "INDETERMINATE": { | |
93 | + name: "alarm.severity-indeterminate", | |
94 | + class: "tb-indeterminate" | |
95 | + } | |
96 | + }, | |
75 | 97 | aliasFilterType: { |
76 | 98 | entityList: { |
77 | 99 | value: 'entityList', |
... | ... | @@ -215,10 +237,6 @@ export default angular.module('thingsboard.types', []) |
215 | 237 | manages: "Manages" |
216 | 238 | }, |
217 | 239 | eventType: { |
218 | - alarm: { | |
219 | - value: "ALARM", | |
220 | - name: "event.type-alarm" | |
221 | - }, | |
222 | 240 | error: { |
223 | 241 | value: "ERROR", |
224 | 242 | name: "event.type-error" | ... | ... |
... | ... | @@ -48,11 +48,16 @@ |
48 | 48 | disable-attribute-scope-selection="true"> |
49 | 49 | </tb-attribute-table> |
50 | 50 | </md-tab> |
51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}"> | |
52 | + <tb-alarm-table flex entity-type="vm.types.entityType.customer" | |
53 | + entity-id="vm.grid.operatingItem().id.id"> | |
54 | + </tb-alarm-table> | |
55 | + </md-tab> | |
51 | 56 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'customer.events' | translate }}"> |
52 | 57 | <tb-event-table flex entity-type="vm.types.entityType.customer" |
53 | 58 | entity-id="vm.grid.operatingItem().id.id" |
54 | 59 | tenant-id="vm.grid.operatingItem().tenantId.id" |
55 | - default-event-type="{{vm.types.eventType.alarm.value}}"> | |
60 | + default-event-type="{{vm.types.eventType.error.value}}"> | |
56 | 61 | </tb-event-table> |
57 | 62 | </md-tab> |
58 | 63 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -49,11 +49,16 @@ |
49 | 49 | disable-attribute-scope-selection="true"> |
50 | 50 | </tb-attribute-table> |
51 | 51 | </md-tab> |
52 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}"> | |
53 | + <tb-alarm-table flex entity-type="vm.types.entityType.device" | |
54 | + entity-id="vm.grid.operatingItem().id.id"> | |
55 | + </tb-alarm-table> | |
56 | + </md-tab> | |
52 | 57 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'device.events' | translate }}"> |
53 | 58 | <tb-event-table flex entity-type="vm.types.entityType.device" |
54 | 59 | entity-id="vm.grid.operatingItem().id.id" |
55 | 60 | tenant-id="vm.grid.operatingItem().tenantId.id" |
56 | - default-event-type="{{vm.types.eventType.alarm.value}}"> | |
61 | + default-event-type="{{vm.types.eventType.error.value}}"> | |
57 | 62 | </tb-event-table> |
58 | 63 | </md-tab> |
59 | 64 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | import uiRouter from 'angular-ui-router'; |
17 | 17 | import thingsboardGrid from '../components/grid.directive'; |
18 | -import thingsboardEvent from '../event'; | |
19 | 18 | import thingsboardApiUser from '../api/user.service'; |
20 | 19 | import thingsboardApiDevice from '../api/device.service'; |
21 | 20 | import thingsboardApiCustomer from '../api/customer.service'; |
... | ... | @@ -30,7 +29,6 @@ import DeviceDirective from './device.directive'; |
30 | 29 | export default angular.module('thingsboard.device', [ |
31 | 30 | uiRouter, |
32 | 31 | thingsboardGrid, |
33 | - thingsboardEvent, | |
34 | 32 | thingsboardApiUser, |
35 | 33 | thingsboardApiDevice, |
36 | 34 | thingsboardApiCustomer | ... | ... |
... | ... | @@ -62,7 +62,7 @@ export default function EventContentDialogController($mdDialog, content, title, |
62 | 62 | } |
63 | 63 | newWidth = 8 * maxLineLength + 16; |
64 | 64 | } |
65 | - $('#tb-content', element).height(newHeight.toString() + "px") | |
65 | + $('#tb-event-content', element).height(newHeight.toString() + "px") | |
66 | 66 | .width(newWidth.toString() + "px"); |
67 | 67 | vm.editor.resize(); |
68 | 68 | } | ... | ... |
... | ... | @@ -18,7 +18,6 @@ |
18 | 18 | import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html'; |
19 | 19 | import eventHeaderStatsTemplate from './event-header-stats.tpl.html'; |
20 | 20 | import eventHeaderErrorTemplate from './event-header-error.tpl.html'; |
21 | -import eventHeaderAlarmTemplate from './event-header-alarm.tpl.html'; | |
22 | 21 | |
23 | 22 | /* eslint-enable import/no-unresolved, import/default */ |
24 | 23 | |
... | ... | @@ -39,9 +38,6 @@ export default function EventHeaderDirective($compile, $templateCache, types) { |
39 | 38 | case types.eventType.error.value: |
40 | 39 | template = eventHeaderErrorTemplate; |
41 | 40 | break; |
42 | - case types.eventType.alarm.value: | |
43 | - template = eventHeaderAlarmTemplate; | |
44 | - break; | |
45 | 41 | } |
46 | 42 | return $templateCache.get(template); |
47 | 43 | } | ... | ... |
... | ... | @@ -20,7 +20,6 @@ import eventErrorDialogTemplate from './event-content-dialog.tpl.html'; |
20 | 20 | import eventRowLcEventTemplate from './event-row-lc-event.tpl.html'; |
21 | 21 | import eventRowStatsTemplate from './event-row-stats.tpl.html'; |
22 | 22 | import eventRowErrorTemplate from './event-row-error.tpl.html'; |
23 | -import eventRowAlarmTemplate from './event-row-alarm.tpl.html'; | |
24 | 23 | |
25 | 24 | /* eslint-enable import/no-unresolved, import/default */ |
26 | 25 | |
... | ... | @@ -41,9 +40,6 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ |
41 | 40 | case types.eventType.error.value: |
42 | 41 | template = eventRowErrorTemplate; |
43 | 42 | break; |
44 | - case types.eventType.alarm.value: | |
45 | - template = eventRowAlarmTemplate; | |
46 | - break; | |
47 | 43 | } |
48 | 44 | return $templateCache.get(template); |
49 | 45 | } | ... | ... |
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | </md-input-container> |
28 | 28 | <tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow> |
29 | 29 | </section> |
30 | - <md-list flex layout="column" class="md-whiteframe-z1 tb-table"> | |
30 | + <md-list flex layout="column" class="md-whiteframe-z1 tb-event-table"> | |
31 | 31 | <md-list class="tb-row tb-header" layout="row" tb-event-header event-type="{{eventType}}"> |
32 | 32 | </md-list> |
33 | 33 | <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()" | ... | ... |
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -md-list.tb-table { | |
16 | +md-list.tb-event-table { | |
17 | 17 | padding: 0px; |
18 | 18 | |
19 | 19 | md-list-item { |
... | ... | @@ -64,7 +64,7 @@ md-list.tb-table { |
64 | 64 | |
65 | 65 | } |
66 | 66 | |
67 | -#tb-content { | |
67 | +#tb-event-content { | |
68 | 68 | min-width: 400px; |
69 | 69 | min-height: 50px; |
70 | 70 | width: 100%; | ... | ... |
... | ... | @@ -32,6 +32,8 @@ import thingsboardDashboardAutocomplete from '../components/dashboard-autocomple |
32 | 32 | import thingsboardUserMenu from './user-menu.directive'; |
33 | 33 | |
34 | 34 | import thingsboardEntity from '../entity'; |
35 | +import thingsboardEvent from '../event'; | |
36 | +import thingsboardAlarm from '../alarm'; | |
35 | 37 | import thingsboardTenant from '../tenant'; |
36 | 38 | import thingsboardCustomer from '../customer'; |
37 | 39 | import thingsboardUser from '../user'; |
... | ... | @@ -61,6 +63,8 @@ export default angular.module('thingsboard.home', [ |
61 | 63 | thingsboardHomeLinks, |
62 | 64 | thingsboardUserMenu, |
63 | 65 | thingsboardEntity, |
66 | + thingsboardEvent, | |
67 | + thingsboardAlarm, | |
64 | 68 | thingsboardTenant, |
65 | 69 | thingsboardCustomer, |
66 | 70 | thingsboardUser, | ... | ... |
... | ... | @@ -411,7 +411,6 @@ export default function addLocaleRussian(locales) { |
411 | 411 | }, |
412 | 412 | "event": { |
413 | 413 | "event-type": "Тип события", |
414 | - "type-alarm": "Аварийное оповещение", | |
415 | 414 | "type-error": "Ошибка", |
416 | 415 | "type-lc-event": "Событие жизненного цикла", |
417 | 416 | "type-stats": "Статистика", | ... | ... |
... | ... | @@ -108,9 +108,43 @@ export default angular.module('thingsboard.locale', []) |
108 | 108 | }, |
109 | 109 | "alarm": { |
110 | 110 | "alarm": "Alarm", |
111 | + "alarms": "Alarms", | |
111 | 112 | "select-alarm": "Select alarm", |
112 | 113 | "no-alarms-matching": "No alarms matching '{{entity}}' were found.", |
113 | - "alarm-required": "Alarm is required" | |
114 | + "alarm-required": "Alarm is required", | |
115 | + "alarm-status": "Alarm status", | |
116 | + "search-status": { | |
117 | + "ANY": "Any", | |
118 | + "ACTIVE": "Active", | |
119 | + "CLEARED": "Cleared", | |
120 | + "ACK": "Acknowledged", | |
121 | + "UNACK": "Unacknowledged" | |
122 | + }, | |
123 | + "display-status": { | |
124 | + "ACTIVE_UNACK": "Active Unacknowledged", | |
125 | + "ACTIVE_ACK": "Active Acknowledged", | |
126 | + "CLEARED_UNACK": "Cleared Unacknowledged", | |
127 | + "CLEARED_ACK": "Cleared Acknowledged" | |
128 | + }, | |
129 | + "no-alarms-prompt": "No alarms found", | |
130 | + "created-time": "Created time", | |
131 | + "type": "Type", | |
132 | + "severity": "Severity", | |
133 | + "originator": "Originator", | |
134 | + "details": "Details", | |
135 | + "status": "Status", | |
136 | + "alarm-details": "Alarm details", | |
137 | + "start-time": "Start time", | |
138 | + "end-time": "End time", | |
139 | + "ack-time": "Acknowledged time", | |
140 | + "clear-time": "Cleared time", | |
141 | + "severity-critical": "Critical", | |
142 | + "severity-major": "Major", | |
143 | + "severity-minor": "Minor", | |
144 | + "severity-warning": "Warning", | |
145 | + "severity-indeterminate": "Indeterminate", | |
146 | + "acknowledge": "Acknowledge", | |
147 | + "clear": "Clear" | |
114 | 148 | }, |
115 | 149 | "alias": { |
116 | 150 | "add": "Add alias", |
... | ... | @@ -647,7 +681,6 @@ export default angular.module('thingsboard.locale', []) |
647 | 681 | }, |
648 | 682 | "event": { |
649 | 683 | "event-type": "Event type", |
650 | - "type-alarm": "Alarm", | |
651 | 684 | "type-error": "Error", |
652 | 685 | "type-lc-event": "Lifecycle event", |
653 | 686 | "type-stats": "Statistics", | ... | ... |
... | ... | @@ -16,7 +16,6 @@ |
16 | 16 | import uiRouter from 'angular-ui-router'; |
17 | 17 | import thingsboardGrid from '../components/grid.directive'; |
18 | 18 | import thingsboardJsonForm from '../components/json-form.directive'; |
19 | -import thingsboardEvent from '../event'; | |
20 | 19 | import thingsboardApiPlugin from '../api/plugin.service'; |
21 | 20 | import thingsboardApiComponentDescriptor from '../api/component-descriptor.service'; |
22 | 21 | |
... | ... | @@ -28,7 +27,6 @@ export default angular.module('thingsboard.plugin', [ |
28 | 27 | uiRouter, |
29 | 28 | thingsboardGrid, |
30 | 29 | thingsboardJsonForm, |
31 | - thingsboardEvent, | |
32 | 30 | thingsboardApiPlugin, |
33 | 31 | thingsboardApiComponentDescriptor |
34 | 32 | ]) | ... | ... |
... | ... | @@ -48,12 +48,16 @@ |
48 | 48 | disable-attribute-scope-selection="true"> |
49 | 49 | </tb-attribute-table> |
50 | 50 | </md-tab> |
51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}"> | |
52 | + <tb-alarm-table flex entity-type="vm.types.entityType.plugin" | |
53 | + entity-id="vm.grid.operatingItem().id.id"> | |
54 | + </tb-alarm-table> | |
55 | + </md-tab> | |
51 | 56 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'plugin.events' | translate }}"> |
52 | 57 | <tb-event-table flex entity-type="vm.types.entityType.plugin" |
53 | 58 | entity-id="vm.grid.operatingItem().id.id" |
54 | 59 | tenant-id="vm.grid.operatingItem().tenantId.id" |
55 | - default-event-type="{{vm.types.eventType.lcEvent.value}}" | |
56 | - disabled-event-types="{{vm.types.eventType.alarm.value}}"> | |
60 | + default-event-type="{{vm.types.eventType.lcEvent.value}}"> | |
57 | 61 | </tb-event-table> |
58 | 62 | </md-tab> |
59 | 63 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -17,7 +17,6 @@ import uiRouter from 'angular-ui-router'; |
17 | 17 | import thingsboardGrid from '../components/grid.directive'; |
18 | 18 | import thingsboardPluginSelect from '../components/plugin-select.directive'; |
19 | 19 | import thingsboardComponent from '../component'; |
20 | -import thingsboardEvent from '../event'; | |
21 | 20 | import thingsboardApiRule from '../api/rule.service'; |
22 | 21 | import thingsboardApiPlugin from '../api/plugin.service'; |
23 | 22 | import thingsboardApiComponentDescriptor from '../api/component-descriptor.service'; |
... | ... | @@ -31,7 +30,6 @@ export default angular.module('thingsboard.rule', [ |
31 | 30 | thingsboardGrid, |
32 | 31 | thingsboardPluginSelect, |
33 | 32 | thingsboardComponent, |
34 | - thingsboardEvent, | |
35 | 33 | thingsboardApiRule, |
36 | 34 | thingsboardApiPlugin, |
37 | 35 | thingsboardApiComponentDescriptor | ... | ... |
... | ... | @@ -48,12 +48,16 @@ |
48 | 48 | disable-attribute-scope-selection="true"> |
49 | 49 | </tb-attribute-table> |
50 | 50 | </md-tab> |
51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}"> | |
52 | + <tb-alarm-table flex entity-type="vm.types.entityType.rule" | |
53 | + entity-id="vm.grid.operatingItem().id.id"> | |
54 | + </tb-alarm-table> | |
55 | + </md-tab> | |
51 | 56 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'rule.events' | translate }}"> |
52 | 57 | <tb-event-table flex entity-type="vm.types.entityType.rule" |
53 | 58 | entity-id="vm.grid.operatingItem().id.id" |
54 | 59 | tenant-id="vm.grid.operatingItem().tenantId.id" |
55 | - default-event-type="{{vm.types.eventType.lcEvent.value}}" | |
56 | - disabled-event-types="{{vm.types.eventType.alarm.value}}"> | |
60 | + default-event-type="{{vm.types.eventType.lcEvent.value}}"> | |
57 | 61 | </tb-event-table> |
58 | 62 | </md-tab> |
59 | 63 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -46,11 +46,16 @@ |
46 | 46 | disable-attribute-scope-selection="true"> |
47 | 47 | </tb-attribute-table> |
48 | 48 | </md-tab> |
49 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}"> | |
50 | + <tb-alarm-table flex entity-type="vm.types.entityType.tenant" | |
51 | + entity-id="vm.grid.operatingItem().id.id"> | |
52 | + </tb-alarm-table> | |
53 | + </md-tab> | |
49 | 54 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'tenant.events' | translate }}"> |
50 | 55 | <tb-event-table flex entity-type="vm.types.entityType.tenant" |
51 | 56 | entity-id="vm.grid.operatingItem().id.id" |
52 | 57 | tenant-id="vm.types.id.nullUid" |
53 | - default-event-type="{{vm.types.eventType.alarm.value}}"> | |
58 | + default-event-type="{{vm.types.eventType.error.value}}"> | |
54 | 59 | </tb-event-table> |
55 | 60 | </md-tab> |
56 | 61 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | ... | ... |
... | ... | @@ -309,6 +309,24 @@ pre.tb-highlight { |
309 | 309 | } |
310 | 310 | } |
311 | 311 | |
312 | +.tb-severity { | |
313 | + font-weight: bold; | |
314 | + &.tb-critical { | |
315 | + color: red !important; | |
316 | + } | |
317 | + &.tb-major { | |
318 | + color: orange !important; | |
319 | + } | |
320 | + &.tb-minor { | |
321 | + color: #ffca3d !important; | |
322 | + } | |
323 | + &.tb-warning { | |
324 | + color: #abab00 !important; | |
325 | + } | |
326 | + &.tb-indeterminate { | |
327 | + color: green !important; | |
328 | + } | |
329 | +} | |
312 | 330 | |
313 | 331 | /*********************** |
314 | 332 | * Flow | ... | ... |