TB-63: Add new 'Alarms' tab in entity details.
This commit is contained in:
parent
351684a6cd
commit
3e0ef11678
@ -57,6 +57,19 @@ public class AlarmController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@RequestMapping(value = "/alarm/info/{alarmId}", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public AlarmInfo getAlarmInfoById(@PathVariable("alarmId") String strAlarmId) throws ThingsboardException {
|
||||
checkParameter("alarmId", strAlarmId);
|
||||
try {
|
||||
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
|
||||
return checkAlarmInfoId(alarmId);
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
|
||||
@ -27,6 +27,7 @@ import org.thingsboard.server.actors.service.ActorService;
|
||||
import org.thingsboard.server.common.data.*;
|
||||
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.asset.Asset;
|
||||
import org.thingsboard.server.common.data.id.*;
|
||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
@ -351,6 +352,17 @@ public abstract class BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
AlarmInfo checkAlarmInfoId(AlarmId alarmId) throws ThingsboardException {
|
||||
try {
|
||||
validateId(alarmId, "Incorrect alarmId " + alarmId);
|
||||
AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(alarmId).get();
|
||||
checkAlarm(alarmInfo);
|
||||
return alarmInfo;
|
||||
} catch (Exception e) {
|
||||
throw handleException(e, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkAlarm(Alarm alarm) throws ThingsboardException {
|
||||
checkNotNull(alarm);
|
||||
checkTenantId(alarm.getTenantId());
|
||||
|
||||
@ -55,6 +55,7 @@ public class Alarm extends BaseData<AlarmId> implements HasName {
|
||||
|
||||
public Alarm(Alarm alarm) {
|
||||
super(alarm.getId());
|
||||
this.createdTime = alarm.getCreatedTime();
|
||||
this.tenantId = alarm.getTenantId();
|
||||
this.type = alarm.getType();
|
||||
this.originator = alarm.getOriginator();
|
||||
|
||||
@ -35,6 +35,8 @@ public interface AlarmService {
|
||||
|
||||
ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
|
||||
|
||||
ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId);
|
||||
|
||||
ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query);
|
||||
|
||||
}
|
||||
|
||||
@ -198,6 +198,23 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
|
||||
return alarmDao.findAlarmByIdAsync(alarmId.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId) {
|
||||
log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId);
|
||||
validateId(alarmId, "Incorrect alarmId " + alarmId);
|
||||
return Futures.transform(alarmDao.findAlarmByIdAsync(alarmId.getId()),
|
||||
(AsyncFunction<Alarm, AlarmInfo>) alarm1 -> {
|
||||
AlarmInfo alarmInfo = new AlarmInfo(alarm1);
|
||||
return Futures.transform(
|
||||
entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), (Function<String, AlarmInfo>)
|
||||
originatorName -> {
|
||||
alarmInfo.setOriginatorName(originatorName);
|
||||
return alarmInfo;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query) {
|
||||
ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(query);
|
||||
|
||||
134
ui/src/app/alarm/alarm-details-dialog.controller.js
Normal file
134
ui/src/app/alarm/alarm-details-dialog.controller.js
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import 'brace/ext/language_tools';
|
||||
import 'brace/mode/json';
|
||||
import 'brace/theme/github';
|
||||
import beautify from 'js-beautify';
|
||||
|
||||
import './alarm-details-dialog.scss';
|
||||
|
||||
const js_beautify = beautify.js;
|
||||
|
||||
/*@ngInject*/
|
||||
export default function AlarmDetailsDialogController($mdDialog, $filter, $translate, types, alarmService, alarmId, showingCallback) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.alarmId = alarmId;
|
||||
vm.types = types;
|
||||
vm.alarm = null;
|
||||
|
||||
vm.alarmUpdated = false;
|
||||
|
||||
showingCallback.onShowing = function(scope, element) {
|
||||
updateEditorSize(element);
|
||||
}
|
||||
|
||||
vm.alarmDetailsOptions = {
|
||||
useWrapMode: false,
|
||||
mode: 'json',
|
||||
showGutter: false,
|
||||
showPrintMargin: false,
|
||||
theme: 'github',
|
||||
advanced: {
|
||||
enableSnippets: false,
|
||||
enableBasicAutocompletion: false,
|
||||
enableLiveAutocompletion: false
|
||||
},
|
||||
onLoad: function (_ace) {
|
||||
vm.editor = _ace;
|
||||
}
|
||||
};
|
||||
|
||||
vm.close = close;
|
||||
vm.acknowledge = acknowledge;
|
||||
vm.clear = clear;
|
||||
|
||||
loadAlarm();
|
||||
|
||||
function updateEditorSize(element) {
|
||||
var newWidth = 600;
|
||||
var newHeight = 200;
|
||||
angular.element('#tb-alarm-details', element).height(newHeight.toString() + "px")
|
||||
.width(newWidth.toString() + "px");
|
||||
vm.editor.resize();
|
||||
}
|
||||
|
||||
function loadAlarm() {
|
||||
alarmService.getAlarmInfo(vm.alarmId).then(
|
||||
function success(alarm) {
|
||||
vm.alarm = alarm;
|
||||
loadAlarmFields();
|
||||
},
|
||||
function fail() {
|
||||
vm.alarm = null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function loadAlarmFields() {
|
||||
vm.createdTime = $filter('date')(vm.alarm.createdTime, 'yyyy-MM-dd HH:mm:ss');
|
||||
vm.startTime = null;
|
||||
if (vm.alarm.startTs) {
|
||||
vm.startTime = $filter('date')(vm.alarm.startTs, 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
vm.endTime = null;
|
||||
if (vm.alarm.endTs) {
|
||||
vm.endTime = $filter('date')(vm.alarm.endTs, 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
vm.ackTime = null;
|
||||
if (vm.alarm.ackTs) {
|
||||
vm.ackTime = $filter('date')(vm.alarm.ackTs, 'yyyy-MM-dd HH:mm:ss')
|
||||
}
|
||||
vm.clearTime = null;
|
||||
if (vm.alarm.clearTs) {
|
||||
vm.clearTime = $filter('date')(vm.alarm.clearTs, 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
|
||||
vm.alarmSeverity = $translate.instant(types.alarmSeverity[vm.alarm.severity].name);
|
||||
|
||||
vm.alarmStatus = $translate.instant('alarm.display-status.' + vm.alarm.status);
|
||||
|
||||
vm.alarmDetails = null;
|
||||
if (vm.alarm.details) {
|
||||
vm.alarmDetails = angular.toJson(vm.alarm.details);
|
||||
vm.alarmDetails = js_beautify(vm.alarmDetails, {indent_size: 4});
|
||||
}
|
||||
}
|
||||
|
||||
function acknowledge () {
|
||||
alarmService.ackAlarm(vm.alarmId).then(
|
||||
function success() {
|
||||
vm.alarmUpdated = true;
|
||||
loadAlarm();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clear () {
|
||||
alarmService.clearAlarm(vm.alarmId).then(
|
||||
function success() {
|
||||
vm.alarmUpdated = true;
|
||||
loadAlarm();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function close () {
|
||||
$mdDialog.hide(vm.alarmUpdated ? vm.alarm : null);
|
||||
}
|
||||
|
||||
}
|
||||
27
ui/src/app/alarm/alarm-details-dialog.scss
Normal file
27
ui/src/app/alarm/alarm-details-dialog.scss
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.tb-alarm-details-panel {
|
||||
margin-left: 15px;
|
||||
border: 1px solid #C0C0C0;
|
||||
height: 100%;
|
||||
#tb-alarm-details {
|
||||
min-width: 600px;
|
||||
min-height: 200px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
107
ui/src/app/alarm/alarm-details-dialog.tpl.html
Normal file
107
ui/src/app/alarm/alarm-details-dialog.tpl.html
Normal file
@ -0,0 +1,107 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<md-dialog aria-label="{{ 'alarm.alarm-details' | translate }}">
|
||||
<md-toolbar>
|
||||
<div class="md-toolbar-tools">
|
||||
<h2 translate>alarm.alarm-details</h2>
|
||||
<span flex></span>
|
||||
<md-button class="md-icon-button" ng-click="vm.close()">
|
||||
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-dialog-content>
|
||||
<div class="md-dialog-content" layout="column">
|
||||
<div layout="row">
|
||||
<md-input-container class="md-block">
|
||||
<label translate>alarm.created-time</label>
|
||||
<input ng-model="vm.createdTime" readonly>
|
||||
</md-input-container>
|
||||
<md-input-container flex class="md-block">
|
||||
<label translate>alarm.originator</label>
|
||||
<input ng-model="vm.alarm.originatorName" readonly>
|
||||
</md-input-container>
|
||||
</div>
|
||||
<div layout="row" ng-if="vm.startTime || vm.endTime">
|
||||
<md-input-container ng-if="vm.startTime" flex class="md-block">
|
||||
<label translate>alarm.start-time</label>
|
||||
<input ng-model="vm.startTime" readonly>
|
||||
</md-input-container>
|
||||
<md-input-container ng-if="vm.endTime" flex class="md-block">
|
||||
<label translate>alarm.end-time</label>
|
||||
<input ng-model="vm.endTime" readonly>
|
||||
</md-input-container>
|
||||
<span flex ng-if="!vm.startTime || !vm.endTime"></span>
|
||||
</div>
|
||||
<div layout="row" ng-if="vm.ackTime || vm.clearTime">
|
||||
<md-input-container ng-if="vm.ackTime" flex class="md-block">
|
||||
<label translate>alarm.ack-time</label>
|
||||
<input ng-model="vm.ackTime" readonly>
|
||||
</md-input-container>
|
||||
<md-input-container ng-if="vm.clearTime" flex class="md-block">
|
||||
<label translate>alarm.clear-time</label>
|
||||
<input ng-model="vm.clearTime" readonly>
|
||||
</md-input-container>
|
||||
<span flex ng-if="!vm.ackTime || !vm.clearTime"></span>
|
||||
</div>
|
||||
<div layout="row">
|
||||
<md-input-container flex class="md-block">
|
||||
<label translate>alarm.type</label>
|
||||
<input ng-model="vm.alarm.type" readonly>
|
||||
</md-input-container>
|
||||
<md-input-container flex class="md-block">
|
||||
<label translate>alarm.severity</label>
|
||||
<input class="tb-severity" ng-class="vm.types.alarmSeverity[vm.alarm.severity].class"
|
||||
ng-model="vm.alarmSeverity" readonly>
|
||||
</md-input-container>
|
||||
<md-input-container flex class="md-block">
|
||||
<label translate>alarm.status</label>
|
||||
<input ng-model="vm.alarmStatus" readonly>
|
||||
</md-input-container>
|
||||
</div>
|
||||
<div class="md-caption" style="padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>alarm.details</div>
|
||||
<div flex class="tb-alarm-details-panel" layout="column">
|
||||
<div flex id="tb-alarm-details" readonly
|
||||
ui-ace="vm.alarmDetailsOptions"
|
||||
ng-model="vm.alarmDetails">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-dialog-content>
|
||||
<md-dialog-actions layout="row">
|
||||
<md-button ng-if="vm.alarm.status==vm.types.alarmStatus.activeUnack ||
|
||||
vm.alarm.status==vm.types.alarmStatus.clearedUnack"
|
||||
class="md-raised md-primary"
|
||||
ng-disabled="loading"
|
||||
ng-click="vm.acknowledge()"
|
||||
style="margin-right:20px;">{{ 'alarm.acknowledge' |
|
||||
translate }}
|
||||
</md-button>
|
||||
<md-button ng-if="vm.alarm.status==vm.types.alarmStatus.activeAck ||
|
||||
vm.alarm.status==vm.types.alarmStatus.activeUnack"
|
||||
class="md-raised md-primary"
|
||||
ng-disabled="loading"
|
||||
ng-click="vm.clear()">{{ 'alarm.clear' |
|
||||
translate }}
|
||||
</md-button>
|
||||
<span flex></span>
|
||||
<md-button ng-disabled="loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' |
|
||||
translate }}
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
</md-dialog>
|
||||
39
ui/src/app/alarm/alarm-header.directive.js
Normal file
39
ui/src/app/alarm/alarm-header.directive.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import alarmHeaderTemplate from './alarm-header.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function AlarmHeaderDirective($compile, $templateCache) {
|
||||
|
||||
var linker = function (scope, element) {
|
||||
|
||||
var template = $templateCache.get(alarmHeaderTemplate);
|
||||
element.html(template);
|
||||
$compile(element.contents())(scope);
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "A",
|
||||
replace: false,
|
||||
link: linker,
|
||||
scope: false
|
||||
};
|
||||
}
|
||||
@ -15,6 +15,9 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div translate class="tb-cell" flex="30">event.event-time</div>
|
||||
<div translate class="tb-cell" flex="20">event.server</div>
|
||||
<div translate class="tb-cell" flex="20">event.alarm</div>
|
||||
<div translate class="tb-cell" flex="30">alarm.created-time</div>
|
||||
<div translate class="tb-cell" flex="15">alarm.originator</div>
|
||||
<div translate class="tb-cell" flex="20">alarm.type</div>
|
||||
<div translate class="tb-cell" flex="15">alarm.severity</div>
|
||||
<div translate class="tb-cell" flex="20">alarm.status</div>
|
||||
<div translate class="tb-cell" flex="15">alarm.details</div>
|
||||
67
ui/src/app/alarm/alarm-row.directive.js
Normal file
67
ui/src/app/alarm/alarm-row.directive.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import alarmDetailsDialogTemplate from './alarm-details-dialog.tpl.html';
|
||||
|
||||
import alarmRowTemplate from './alarm-row.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function AlarmRowDirective($compile, $templateCache, types, $mdDialog, $document) {
|
||||
|
||||
var linker = function (scope, element, attrs) {
|
||||
|
||||
var template = $templateCache.get(alarmRowTemplate);
|
||||
element.html(template);
|
||||
|
||||
scope.alarm = attrs.alarm;
|
||||
scope.types = types;
|
||||
|
||||
scope.showAlarmDetails = function($event) {
|
||||
var onShowingCallback = {
|
||||
onShowing: function(){}
|
||||
}
|
||||
$mdDialog.show({
|
||||
controller: 'AlarmDetailsDialogController',
|
||||
controllerAs: 'vm',
|
||||
templateUrl: alarmDetailsDialogTemplate,
|
||||
locals: {alarmId: scope.alarm.id.id, showingCallback: onShowingCallback},
|
||||
parent: angular.element($document[0].body),
|
||||
targetEvent: $event,
|
||||
fullscreen: true,
|
||||
skipHide: true,
|
||||
onShowing: function(scope, element) {
|
||||
onShowingCallback.onShowing(scope, element);
|
||||
}
|
||||
}).then(function (alarm) {
|
||||
if (alarm) {
|
||||
scope.alarm = alarm;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "A",
|
||||
replace: false,
|
||||
link: linker,
|
||||
scope: false
|
||||
};
|
||||
}
|
||||
@ -15,14 +15,19 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div class="tb-cell" flex="30">{{event.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div>
|
||||
<div class="tb-cell" flex="20">{{event.body.server}}</div>
|
||||
<div class="tb-cell" flex="20">
|
||||
<md-button ng-if="event.body.body" class="md-icon-button md-primary"
|
||||
ng-click="showContent($event, event.body.body, 'event.alarm')"
|
||||
<div class="tb-cell" flex="30">{{alarm.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div>
|
||||
<div class="tb-cell" flex="15">{{alarm.originatorName}}</div>
|
||||
<div class="tb-cell" flex="20">{{alarm.type}}</div>
|
||||
<div class="tb-cell tb-severity" flex="15" ng-class="types.alarmSeverity[alarm.severity].class">
|
||||
{{ alarm ? (types.alarmSeverity[alarm.severity].name | translate) : '' }}
|
||||
</div>
|
||||
<div class="tb-cell" flex="20">{{ alarm ? (('alarm.display-status.' + alarm.status) | translate) : '' }}</div>
|
||||
<div class="tb-cell" flex="15">
|
||||
<md-button class="md-icon-button md-primary"
|
||||
ng-click="showAlarmDetails($event)"
|
||||
aria-label="{{ 'action.view' | translate }}">
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.view' | translate }}
|
||||
{{ 'alarm.details' | translate }}
|
||||
</md-tooltip>
|
||||
<md-icon aria-label="{{ 'action.view' | translate }}"
|
||||
class="material-icons">
|
||||
211
ui/src/app/alarm/alarm-table.directive.js
Normal file
211
ui/src/app/alarm/alarm-table.directive.js
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import './alarm.scss';
|
||||
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import alarmTableTemplate from './alarm-table.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function AlarmTableDirective($compile, $templateCache, $rootScope, types, alarmService) {
|
||||
|
||||
var linker = function (scope, element) {
|
||||
|
||||
var template = $templateCache.get(alarmTableTemplate);
|
||||
|
||||
element.html(template);
|
||||
|
||||
scope.types = types;
|
||||
|
||||
scope.alarmSearchStatus = types.alarmSearchStatus.any;
|
||||
|
||||
var pageSize = 20;
|
||||
var startTime = 0;
|
||||
var endTime = 0;
|
||||
|
||||
scope.timewindow = {
|
||||
history: {
|
||||
timewindowMs: 24 * 60 * 60 * 1000 // 1 day
|
||||
}
|
||||
}
|
||||
|
||||
scope.topIndex = 0;
|
||||
|
||||
scope.theAlarms = {
|
||||
getItemAtIndex: function (index) {
|
||||
if (index > scope.alarms.data.length) {
|
||||
scope.theAlarms.fetchMoreItems_(index);
|
||||
return null;
|
||||
}
|
||||
var item = scope.alarms.data[index];
|
||||
if (item) {
|
||||
item.indexNumber = index + 1;
|
||||
}
|
||||
return item;
|
||||
},
|
||||
|
||||
getLength: function () {
|
||||
if (scope.alarms.hasNext) {
|
||||
return scope.alarms.data.length + scope.alarms.nextPageLink.limit;
|
||||
} else {
|
||||
return scope.alarms.data.length;
|
||||
}
|
||||
},
|
||||
|
||||
fetchMoreItems_: function () {
|
||||
if (scope.alarms.hasNext && !scope.alarms.pending) {
|
||||
if (scope.entityType && scope.entityId && scope.alarmSearchStatus) {
|
||||
var promise = alarmService.getAlarms(scope.entityType, scope.entityId,
|
||||
scope.alarms.nextPageLink, scope.alarmSearchStatus, null, true, false);
|
||||
if (promise) {
|
||||
scope.alarms.pending = true;
|
||||
promise.then(
|
||||
function success(alarms) {
|
||||
scope.alarms.data = scope.alarms.data.concat(alarms.data);
|
||||
scope.alarms.nextPageLink = alarms.nextPageLink;
|
||||
scope.alarms.hasNext = alarms.hasNext;
|
||||
if (scope.alarms.hasNext) {
|
||||
scope.alarms.nextPageLink.limit = pageSize;
|
||||
}
|
||||
scope.alarms.pending = false;
|
||||
},
|
||||
function fail() {
|
||||
scope.alarms.hasNext = false;
|
||||
scope.alarms.pending = false;
|
||||
});
|
||||
} else {
|
||||
scope.alarms.hasNext = false;
|
||||
}
|
||||
} else {
|
||||
scope.alarms.hasNext = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch("entityId", function(newVal, prevVal) {
|
||||
if (newVal && !angular.equals(newVal, prevVal)) {
|
||||
resetFilter();
|
||||
reload();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
function destroyWatchers() {
|
||||
if (scope.alarmSearchStatusWatchHandle) {
|
||||
scope.alarmSearchStatusWatchHandle();
|
||||
scope.alarmSearchStatusWatchHandle = null;
|
||||
}
|
||||
if (scope.timewindowWatchHandle) {
|
||||
scope.timewindowWatchHandle();
|
||||
scope.timewindowWatchHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
function initWatchers() {
|
||||
scope.alarmSearchStatusWatchHandle = scope.$watch("alarmSearchStatus", function(newVal, prevVal) {
|
||||
if (newVal && !angular.equals(newVal, prevVal)) {
|
||||
reload();
|
||||
}
|
||||
});
|
||||
scope.timewindowWatchHandle = scope.$watch("timewindow", function(newVal, prevVal) {
|
||||
if (newVal && !angular.equals(newVal, prevVal)) {
|
||||
reload();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function resetFilter() {
|
||||
destroyWatchers();
|
||||
scope.timewindow = {
|
||||
history: {
|
||||
timewindowMs: 24 * 60 * 60 * 1000 // 1 day
|
||||
}
|
||||
};
|
||||
scope.alarmSearchStatus = types.alarmSearchStatus.any;
|
||||
initWatchers();
|
||||
}
|
||||
|
||||
function updateTimeWindowRange () {
|
||||
if (scope.timewindow.history.timewindowMs) {
|
||||
var currentTime = (new Date).getTime();
|
||||
startTime = currentTime - scope.timewindow.history.timewindowMs;
|
||||
endTime = currentTime;
|
||||
} else {
|
||||
startTime = scope.timewindow.history.fixedTimewindow.startTimeMs;
|
||||
endTime = scope.timewindow.history.fixedTimewindow.endTimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
function reload () {
|
||||
scope.topIndex = 0;
|
||||
scope.selected = [];
|
||||
updateTimeWindowRange();
|
||||
scope.alarms = {
|
||||
data: [],
|
||||
nextPageLink: {
|
||||
limit: pageSize,
|
||||
startTime: startTime,
|
||||
endTime: endTime
|
||||
},
|
||||
hasNext: true,
|
||||
pending: false
|
||||
};
|
||||
scope.theAlarms.getItemAtIndex(pageSize);
|
||||
}
|
||||
|
||||
scope.noData = function() {
|
||||
return scope.alarms.data.length == 0 && !scope.alarms.hasNext;
|
||||
}
|
||||
|
||||
scope.hasData = function() {
|
||||
return scope.alarms.data.length > 0;
|
||||
}
|
||||
|
||||
scope.loading = function() {
|
||||
return $rootScope.loading;
|
||||
}
|
||||
|
||||
scope.hasScroll = function() {
|
||||
var repeatContainer = scope.repeatContainer[0];
|
||||
if (repeatContainer) {
|
||||
var scrollElement = repeatContainer.children[0];
|
||||
if (scrollElement) {
|
||||
return scrollElement.scrollHeight > scrollElement.clientHeight;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
reload();
|
||||
|
||||
initWatchers();
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "E",
|
||||
link: linker,
|
||||
scope: {
|
||||
entityType: '=',
|
||||
entityId: '='
|
||||
}
|
||||
};
|
||||
}
|
||||
49
ui/src/app/alarm/alarm-table.tpl.html
Normal file
49
ui/src/app/alarm/alarm-table.tpl.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<md-content flex class="md-padding tb-absolute-fill" layout="column">
|
||||
<section layout="row">
|
||||
<md-input-container class="md-block" style="width: 200px;">
|
||||
<label translate>alarm.alarm-status</label>
|
||||
<md-select ng-model="alarmSearchStatus" ng-disabled="loading()">
|
||||
<md-option ng-repeat="searchStatus in types.alarmSearchStatus" ng-value="searchStatus">
|
||||
{{ ('alarm.search-status.' + searchStatus) | translate }}
|
||||
</md-option>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
<tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow>
|
||||
</section>
|
||||
<div flex layout="column" class="tb-alarm-container md-whiteframe-z1">
|
||||
<md-list flex layout="column" class="tb-alarm-table">
|
||||
<md-list class="tb-row tb-header" layout="row" tb-alarm-header>
|
||||
</md-list>
|
||||
<md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()"
|
||||
ng-show="loading()"></md-progress-linear>
|
||||
<md-divider></md-divider>
|
||||
<span translate layout-align="center center"
|
||||
style="margin-top: 25px;"
|
||||
class="tb-prompt" ng-show="noData()">alarm.no-alarms-prompt</span>
|
||||
<md-virtual-repeat-container ng-show="hasData()" flex md-top-index="topIndex" tb-scope-element="repeatContainer">
|
||||
<md-list-item md-virtual-repeat="alarm in theAlarms" md-on-demand flex ng-style="hasScroll() ? {'margin-right':'-15px'} : {}">
|
||||
<md-list class="tb-row" flex layout="row" tb-alarm-row alarm="{{alarm}}">
|
||||
</md-list>
|
||||
<md-divider flex></md-divider>
|
||||
</md-list-item>
|
||||
</md-virtual-repeat-container>
|
||||
</md-list>
|
||||
</div>
|
||||
</md-content>
|
||||
78
ui/src/app/alarm/alarm.scss
Normal file
78
ui/src/app/alarm/alarm.scss
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.tb-alarm-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
md-list.tb-alarm-table {
|
||||
padding: 0px;
|
||||
min-width: 700px;
|
||||
|
||||
md-list-item {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.tb-row {
|
||||
height: 48px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tb-row:hover {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
|
||||
.tb-header:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.tb-header {
|
||||
.tb-cell {
|
||||
color: rgba(0,0,0,.54);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tb-cell {
|
||||
padding: 0 24px;
|
||||
margin: auto 0;
|
||||
color: rgba(0,0,0,.87);
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
.md-button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tb-cell.tb-number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#tb-alarm-content {
|
||||
min-width: 400px;
|
||||
min-height: 50px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
27
ui/src/app/alarm/index.js
Normal file
27
ui/src/app/alarm/index.js
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import AlarmDetailsDialogController from './alarm-details-dialog.controller';
|
||||
import AlarmHeaderDirective from './alarm-header.directive';
|
||||
import AlarmRowDirective from './alarm-row.directive';
|
||||
import AlarmTableDirective from './alarm-table.directive';
|
||||
|
||||
export default angular.module('thingsboard.alarm', [])
|
||||
.controller('AlarmDetailsDialogController', AlarmDetailsDialogController)
|
||||
.directive('tbAlarmHeader', AlarmHeaderDirective)
|
||||
.directive('tbAlarmRow', AlarmRowDirective)
|
||||
.directive('tbAlarmTable', AlarmTableDirective)
|
||||
.name;
|
||||
@ -21,6 +21,7 @@ export default angular.module('thingsboard.api.alarm', [])
|
||||
function AlarmService($http, $q, $interval, $filter) {
|
||||
var service = {
|
||||
getAlarm: getAlarm,
|
||||
getAlarmInfo: getAlarmInfo,
|
||||
saveAlarm: saveAlarm,
|
||||
ackAlarm: ackAlarm,
|
||||
clearAlarm: clearAlarm,
|
||||
@ -46,6 +47,21 @@ function AlarmService($http, $q, $interval, $filter) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getAlarmInfo(alarmId, ignoreErrors, config) {
|
||||
var deferred = $q.defer();
|
||||
var url = '/api/alarm/info/' + 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';
|
||||
|
||||
@ -48,11 +48,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.asset"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'asset.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.asset"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.grid.operatingItem().tenantId.id"
|
||||
default-event-type="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.error.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
import uiRouter from 'angular-ui-router';
|
||||
import thingsboardGrid from '../components/grid.directive';
|
||||
import thingsboardEvent from '../event';
|
||||
import thingsboardApiUser from '../api/user.service';
|
||||
import thingsboardApiAsset from '../api/asset.service';
|
||||
import thingsboardApiCustomer from '../api/customer.service';
|
||||
@ -29,7 +28,6 @@ import AssetDirective from './asset.directive';
|
||||
export default angular.module('thingsboard.asset', [
|
||||
uiRouter,
|
||||
thingsboardGrid,
|
||||
thingsboardEvent,
|
||||
thingsboardApiUser,
|
||||
thingsboardApiAsset,
|
||||
thingsboardApiCustomer
|
||||
|
||||
@ -72,6 +72,28 @@ export default angular.module('thingsboard.types', [])
|
||||
ack: "ACK",
|
||||
unack: "UNACK"
|
||||
},
|
||||
alarmSeverity: {
|
||||
"CRITICAL": {
|
||||
name: "alarm.severity-critical",
|
||||
class: "tb-critical"
|
||||
},
|
||||
"MAJOR": {
|
||||
name: "alarm.severity-major",
|
||||
class: "tb-major"
|
||||
},
|
||||
"MINOR": {
|
||||
name: "alarm.severity-minor",
|
||||
class: "tb-minor"
|
||||
},
|
||||
"WARNING": {
|
||||
name: "alarm.severity-warning",
|
||||
class: "tb-warning"
|
||||
},
|
||||
"INDETERMINATE": {
|
||||
name: "alarm.severity-indeterminate",
|
||||
class: "tb-indeterminate"
|
||||
}
|
||||
},
|
||||
aliasFilterType: {
|
||||
entityList: {
|
||||
value: 'entityList',
|
||||
@ -215,10 +237,6 @@ export default angular.module('thingsboard.types', [])
|
||||
manages: "Manages"
|
||||
},
|
||||
eventType: {
|
||||
alarm: {
|
||||
value: "ALARM",
|
||||
name: "event.type-alarm"
|
||||
},
|
||||
error: {
|
||||
value: "ERROR",
|
||||
name: "event.type-error"
|
||||
|
||||
@ -48,11 +48,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.customer"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'customer.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.customer"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.grid.operatingItem().tenantId.id"
|
||||
default-event-type="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.error.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
|
||||
|
||||
@ -49,11 +49,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.device"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'device.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.device"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.grid.operatingItem().tenantId.id"
|
||||
default-event-type="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.error.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
import uiRouter from 'angular-ui-router';
|
||||
import thingsboardGrid from '../components/grid.directive';
|
||||
import thingsboardEvent from '../event';
|
||||
import thingsboardApiUser from '../api/user.service';
|
||||
import thingsboardApiDevice from '../api/device.service';
|
||||
import thingsboardApiCustomer from '../api/customer.service';
|
||||
@ -30,7 +29,6 @@ import DeviceDirective from './device.directive';
|
||||
export default angular.module('thingsboard.device', [
|
||||
uiRouter,
|
||||
thingsboardGrid,
|
||||
thingsboardEvent,
|
||||
thingsboardApiUser,
|
||||
thingsboardApiDevice,
|
||||
thingsboardApiCustomer
|
||||
|
||||
@ -62,7 +62,7 @@ export default function EventContentDialogController($mdDialog, content, title,
|
||||
}
|
||||
newWidth = 8 * maxLineLength + 16;
|
||||
}
|
||||
$('#tb-content', element).height(newHeight.toString() + "px")
|
||||
$('#tb-event-content', element).height(newHeight.toString() + "px")
|
||||
.width(newWidth.toString() + "px");
|
||||
vm.editor.resize();
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
</md-toolbar>
|
||||
<md-dialog-content>
|
||||
<div class="md-dialog-content">
|
||||
<div flex id="tb-content" readonly
|
||||
<div flex id="tb-event-content" readonly
|
||||
ui-ace="vm.contentOptions"
|
||||
ng-model="vm.content">
|
||||
</div>
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html';
|
||||
import eventHeaderStatsTemplate from './event-header-stats.tpl.html';
|
||||
import eventHeaderErrorTemplate from './event-header-error.tpl.html';
|
||||
import eventHeaderAlarmTemplate from './event-header-alarm.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
@ -39,9 +38,6 @@ export default function EventHeaderDirective($compile, $templateCache, types) {
|
||||
case types.eventType.error.value:
|
||||
template = eventHeaderErrorTemplate;
|
||||
break;
|
||||
case types.eventType.alarm.value:
|
||||
template = eventHeaderAlarmTemplate;
|
||||
break;
|
||||
}
|
||||
return $templateCache.get(template);
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ import eventErrorDialogTemplate from './event-content-dialog.tpl.html';
|
||||
import eventRowLcEventTemplate from './event-row-lc-event.tpl.html';
|
||||
import eventRowStatsTemplate from './event-row-stats.tpl.html';
|
||||
import eventRowErrorTemplate from './event-row-error.tpl.html';
|
||||
import eventRowAlarmTemplate from './event-row-alarm.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
@ -41,9 +40,6 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
|
||||
case types.eventType.error.value:
|
||||
template = eventRowErrorTemplate;
|
||||
break;
|
||||
case types.eventType.alarm.value:
|
||||
template = eventRowAlarmTemplate;
|
||||
break;
|
||||
}
|
||||
return $templateCache.get(template);
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
</md-input-container>
|
||||
<tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow>
|
||||
</section>
|
||||
<md-list flex layout="column" class="md-whiteframe-z1 tb-table">
|
||||
<md-list flex layout="column" class="md-whiteframe-z1 tb-event-table">
|
||||
<md-list class="tb-row tb-header" layout="row" tb-event-header event-type="{{eventType}}">
|
||||
</md-list>
|
||||
<md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!loading()"
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
md-list.tb-table {
|
||||
md-list.tb-event-table {
|
||||
padding: 0px;
|
||||
|
||||
md-list-item {
|
||||
@ -64,7 +64,7 @@ md-list.tb-table {
|
||||
|
||||
}
|
||||
|
||||
#tb-content {
|
||||
#tb-event-content {
|
||||
min-width: 400px;
|
||||
min-height: 50px;
|
||||
width: 100%;
|
||||
|
||||
@ -32,6 +32,8 @@ import thingsboardDashboardAutocomplete from '../components/dashboard-autocomple
|
||||
import thingsboardUserMenu from './user-menu.directive';
|
||||
|
||||
import thingsboardEntity from '../entity';
|
||||
import thingsboardEvent from '../event';
|
||||
import thingsboardAlarm from '../alarm';
|
||||
import thingsboardTenant from '../tenant';
|
||||
import thingsboardCustomer from '../customer';
|
||||
import thingsboardUser from '../user';
|
||||
@ -61,6 +63,8 @@ export default angular.module('thingsboard.home', [
|
||||
thingsboardHomeLinks,
|
||||
thingsboardUserMenu,
|
||||
thingsboardEntity,
|
||||
thingsboardEvent,
|
||||
thingsboardAlarm,
|
||||
thingsboardTenant,
|
||||
thingsboardCustomer,
|
||||
thingsboardUser,
|
||||
|
||||
@ -411,7 +411,6 @@
|
||||
},
|
||||
"event": {
|
||||
"event-type": "Tipo de evento",
|
||||
"type-alarm": "Alarma",
|
||||
"type-error": "Error",
|
||||
"type-lc-event": "Ciclo de vida",
|
||||
"type-stats": "Estadísticas",
|
||||
|
||||
@ -378,7 +378,6 @@ export default function addLocaleKorean(locales) {
|
||||
},
|
||||
"event": {
|
||||
"event-type": "이벤트 타입",
|
||||
"type-alarm": "알람",
|
||||
"type-error": "에러",
|
||||
"type-lc-event": "주기적 이벤트",
|
||||
"type-stats": "통계",
|
||||
|
||||
@ -411,7 +411,6 @@ export default function addLocaleRussian(locales) {
|
||||
},
|
||||
"event": {
|
||||
"event-type": "Тип события",
|
||||
"type-alarm": "Аварийное оповещение",
|
||||
"type-error": "Ошибка",
|
||||
"type-lc-event": "Событие жизненного цикла",
|
||||
"type-stats": "Статистика",
|
||||
|
||||
@ -411,7 +411,6 @@ export default function addLocaleChinese(locales) {
|
||||
},
|
||||
"event" : {
|
||||
"event-type": "事件类型",
|
||||
"type-alarm": "报警",
|
||||
"type-error": "错误",
|
||||
"type-lc-event": "生命周期事件",
|
||||
"type-stats": "类型统计",
|
||||
|
||||
@ -108,9 +108,43 @@ export default angular.module('thingsboard.locale', [])
|
||||
},
|
||||
"alarm": {
|
||||
"alarm": "Alarm",
|
||||
"alarms": "Alarms",
|
||||
"select-alarm": "Select alarm",
|
||||
"no-alarms-matching": "No alarms matching '{{entity}}' were found.",
|
||||
"alarm-required": "Alarm is required"
|
||||
"alarm-required": "Alarm is required",
|
||||
"alarm-status": "Alarm status",
|
||||
"search-status": {
|
||||
"ANY": "Any",
|
||||
"ACTIVE": "Active",
|
||||
"CLEARED": "Cleared",
|
||||
"ACK": "Acknowledged",
|
||||
"UNACK": "Unacknowledged"
|
||||
},
|
||||
"display-status": {
|
||||
"ACTIVE_UNACK": "Active Unacknowledged",
|
||||
"ACTIVE_ACK": "Active Acknowledged",
|
||||
"CLEARED_UNACK": "Cleared Unacknowledged",
|
||||
"CLEARED_ACK": "Cleared Acknowledged"
|
||||
},
|
||||
"no-alarms-prompt": "No alarms found",
|
||||
"created-time": "Created time",
|
||||
"type": "Type",
|
||||
"severity": "Severity",
|
||||
"originator": "Originator",
|
||||
"details": "Details",
|
||||
"status": "Status",
|
||||
"alarm-details": "Alarm details",
|
||||
"start-time": "Start time",
|
||||
"end-time": "End time",
|
||||
"ack-time": "Acknowledged time",
|
||||
"clear-time": "Cleared time",
|
||||
"severity-critical": "Critical",
|
||||
"severity-major": "Major",
|
||||
"severity-minor": "Minor",
|
||||
"severity-warning": "Warning",
|
||||
"severity-indeterminate": "Indeterminate",
|
||||
"acknowledge": "Acknowledge",
|
||||
"clear": "Clear"
|
||||
},
|
||||
"alias": {
|
||||
"add": "Add alias",
|
||||
@ -647,7 +681,6 @@ export default angular.module('thingsboard.locale', [])
|
||||
},
|
||||
"event": {
|
||||
"event-type": "Event type",
|
||||
"type-alarm": "Alarm",
|
||||
"type-error": "Error",
|
||||
"type-lc-event": "Lifecycle event",
|
||||
"type-stats": "Statistics",
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
import uiRouter from 'angular-ui-router';
|
||||
import thingsboardGrid from '../components/grid.directive';
|
||||
import thingsboardJsonForm from '../components/json-form.directive';
|
||||
import thingsboardEvent from '../event';
|
||||
import thingsboardApiPlugin from '../api/plugin.service';
|
||||
import thingsboardApiComponentDescriptor from '../api/component-descriptor.service';
|
||||
|
||||
@ -28,7 +27,6 @@ export default angular.module('thingsboard.plugin', [
|
||||
uiRouter,
|
||||
thingsboardGrid,
|
||||
thingsboardJsonForm,
|
||||
thingsboardEvent,
|
||||
thingsboardApiPlugin,
|
||||
thingsboardApiComponentDescriptor
|
||||
])
|
||||
|
||||
@ -48,12 +48,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.plugin"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'plugin.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.plugin"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.grid.operatingItem().tenantId.id"
|
||||
default-event-type="{{vm.types.eventType.lcEvent.value}}"
|
||||
disabled-event-types="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.lcEvent.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<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';
|
||||
import thingsboardGrid from '../components/grid.directive';
|
||||
import thingsboardPluginSelect from '../components/plugin-select.directive';
|
||||
import thingsboardComponent from '../component';
|
||||
import thingsboardEvent from '../event';
|
||||
import thingsboardApiRule from '../api/rule.service';
|
||||
import thingsboardApiPlugin from '../api/plugin.service';
|
||||
import thingsboardApiComponentDescriptor from '../api/component-descriptor.service';
|
||||
@ -31,7 +30,6 @@ export default angular.module('thingsboard.rule', [
|
||||
thingsboardGrid,
|
||||
thingsboardPluginSelect,
|
||||
thingsboardComponent,
|
||||
thingsboardEvent,
|
||||
thingsboardApiRule,
|
||||
thingsboardApiPlugin,
|
||||
thingsboardApiComponentDescriptor
|
||||
|
||||
@ -48,12 +48,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.rule"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'rule.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.rule"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.grid.operatingItem().tenantId.id"
|
||||
default-event-type="{{vm.types.eventType.lcEvent.value}}"
|
||||
disabled-event-types="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.lcEvent.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}">
|
||||
|
||||
@ -46,11 +46,16 @@
|
||||
disable-attribute-scope-selection="true">
|
||||
</tb-attribute-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
|
||||
<tb-alarm-table flex entity-type="vm.types.entityType.tenant"
|
||||
entity-id="vm.grid.operatingItem().id.id">
|
||||
</tb-alarm-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'tenant.events' | translate }}">
|
||||
<tb-event-table flex entity-type="vm.types.entityType.tenant"
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
tenant-id="vm.types.id.nullUid"
|
||||
default-event-type="{{vm.types.eventType.alarm.value}}">
|
||||
default-event-type="{{vm.types.eventType.error.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
|
||||
|
||||
@ -309,6 +309,24 @@ pre.tb-highlight {
|
||||
}
|
||||
}
|
||||
|
||||
.tb-severity {
|
||||
font-weight: bold;
|
||||
&.tb-critical {
|
||||
color: red !important;
|
||||
}
|
||||
&.tb-major {
|
||||
color: orange !important;
|
||||
}
|
||||
&.tb-minor {
|
||||
color: #ffca3d !important;
|
||||
}
|
||||
&.tb-warning {
|
||||
color: #abab00 !important;
|
||||
}
|
||||
&.tb-indeterminate {
|
||||
color: green !important;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************
|
||||
* Flow
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user