thingsboard-memoizeit
Changes
ui/src/app/alarm/alarm.scss 78(+78 -0)
ui/src/app/alarm/alarm-details-dialog.controller.js 134(+134 -0)
ui/src/app/alarm/alarm-details-dialog.scss 27(+27 -0)
ui/src/app/alarm/alarm-details-dialog.tpl.html 107(+107 -0)
ui/src/app/alarm/alarm-header.directive.js 39(+39 -0)
ui/src/app/alarm/alarm-row.directive.js 67(+67 -0)
ui/src/app/alarm/alarm-row.tpl.html 17(+11 -6)
ui/src/app/alarm/alarm-table.directive.js 211(+211 -0)
ui/src/app/alarm/alarm-table.tpl.html 49(+49 -0)
ui/src/app/alarm/index.js 27(+27 -0)
ui/src/app/api/alarm.service.js 16(+16 -0)
ui/src/app/asset/assets.tpl.html 7(+6 -1)
ui/src/app/asset/index.js 2(+0 -2)
ui/src/app/common/types.constant.js 26(+22 -4)
ui/src/app/device/devices.tpl.html 7(+6 -1)
ui/src/app/device/index.js 2(+0 -2)
ui/src/app/event/event.scss 4(+2 -2)
ui/src/app/layout/index.js 4(+4 -0)
ui/src/app/locale/locale.constant.js 37(+35 -2)
ui/src/app/plugin/index.js 2(+0 -2)
ui/src/app/plugin/plugins.tpl.html 8(+6 -2)
ui/src/app/rule/index.js 2(+0 -2)
ui/src/app/rule/rules.tpl.html 8(+6 -2)
ui/src/app/tenant/tenants.tpl.html 7(+6 -1)
ui/src/scss/main.scss 18(+18 -0)
Details
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index 19774bb..19c75e7 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -58,6 +58,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
public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException {
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index aba4b6e..c63dda7 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -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());
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
index 9c6f998..e48cf5b 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java
@@ -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();
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
index fb8a80d..3556d51 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
@@ -35,6 +35,8 @@ public interface AlarmService {
ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
+ ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(AlarmId alarmId);
+
ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query);
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
index d152d96..58f7316 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
@@ -199,6 +199,23 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@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);
if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) {
ui/src/app/alarm/alarm.scss 78(+78 -0)
diff --git a/ui/src/app/alarm/alarm.scss b/ui/src/app/alarm/alarm.scss
new file mode 100644
index 0000000..aea5225
--- /dev/null
+++ b/ui/src/app/alarm/alarm.scss
@@ -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%;
+}
ui/src/app/alarm/alarm-details-dialog.controller.js 134(+134 -0)
diff --git a/ui/src/app/alarm/alarm-details-dialog.controller.js b/ui/src/app/alarm/alarm-details-dialog.controller.js
new file mode 100644
index 0000000..0cc05ef
--- /dev/null
+++ b/ui/src/app/alarm/alarm-details-dialog.controller.js
@@ -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);
+ }
+
+}
ui/src/app/alarm/alarm-details-dialog.scss 27(+27 -0)
diff --git a/ui/src/app/alarm/alarm-details-dialog.scss b/ui/src/app/alarm/alarm-details-dialog.scss
new file mode 100644
index 0000000..9b923d0
--- /dev/null
+++ b/ui/src/app/alarm/alarm-details-dialog.scss
@@ -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%;
+ }
+}
ui/src/app/alarm/alarm-details-dialog.tpl.html 107(+107 -0)
diff --git a/ui/src/app/alarm/alarm-details-dialog.tpl.html b/ui/src/app/alarm/alarm-details-dialog.tpl.html
new file mode 100644
index 0000000..c958201
--- /dev/null
+++ b/ui/src/app/alarm/alarm-details-dialog.tpl.html
@@ -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>
ui/src/app/alarm/alarm-header.directive.js 39(+39 -0)
diff --git a/ui/src/app/alarm/alarm-header.directive.js b/ui/src/app/alarm/alarm-header.directive.js
new file mode 100644
index 0000000..b66a972
--- /dev/null
+++ b/ui/src/app/alarm/alarm-header.directive.js
@@ -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
+ };
+}
ui/src/app/alarm/alarm-row.directive.js 67(+67 -0)
diff --git a/ui/src/app/alarm/alarm-row.directive.js b/ui/src/app/alarm/alarm-row.directive.js
new file mode 100644
index 0000000..9cb9bed
--- /dev/null
+++ b/ui/src/app/alarm/alarm-row.directive.js
@@ -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
+ };
+}
ui/src/app/alarm/alarm-table.directive.js 211(+211 -0)
diff --git a/ui/src/app/alarm/alarm-table.directive.js b/ui/src/app/alarm/alarm-table.directive.js
new file mode 100644
index 0000000..c93ea03
--- /dev/null
+++ b/ui/src/app/alarm/alarm-table.directive.js
@@ -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: '='
+ }
+ };
+}
ui/src/app/alarm/alarm-table.tpl.html 49(+49 -0)
diff --git a/ui/src/app/alarm/alarm-table.tpl.html b/ui/src/app/alarm/alarm-table.tpl.html
new file mode 100644
index 0000000..c32e39a
--- /dev/null
+++ b/ui/src/app/alarm/alarm-table.tpl.html
@@ -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>
ui/src/app/alarm/index.js 27(+27 -0)
diff --git a/ui/src/app/alarm/index.js b/ui/src/app/alarm/index.js
new file mode 100644
index 0000000..0ea4610
--- /dev/null
+++ b/ui/src/app/alarm/index.js
@@ -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;
ui/src/app/api/alarm.service.js 16(+16 -0)
diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js
index ca892f2..34e6b59 100644
--- a/ui/src/app/api/alarm.service.js
+++ b/ui/src/app/api/alarm.service.js
@@ -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';
ui/src/app/asset/assets.tpl.html 7(+6 -1)
diff --git a/ui/src/app/asset/assets.tpl.html b/ui/src/app/asset/assets.tpl.html
index 11a118f..8370d3d 100644
--- a/ui/src/app/asset/assets.tpl.html
+++ b/ui/src/app/asset/assets.tpl.html
@@ -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 }}">
ui/src/app/asset/index.js 2(+0 -2)
diff --git a/ui/src/app/asset/index.js b/ui/src/app/asset/index.js
index 62ab201..2426e85 100644
--- a/ui/src/app/asset/index.js
+++ b/ui/src/app/asset/index.js
@@ -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
ui/src/app/common/types.constant.js 26(+22 -4)
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 2076093..b281ad1 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -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"
diff --git a/ui/src/app/customer/customers.tpl.html b/ui/src/app/customer/customers.tpl.html
index 6c70a70..a6521f0 100644
--- a/ui/src/app/customer/customers.tpl.html
+++ b/ui/src/app/customer/customers.tpl.html
@@ -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 }}">
ui/src/app/device/devices.tpl.html 7(+6 -1)
diff --git a/ui/src/app/device/devices.tpl.html b/ui/src/app/device/devices.tpl.html
index 3ff6c1c..1e467be 100644
--- a/ui/src/app/device/devices.tpl.html
+++ b/ui/src/app/device/devices.tpl.html
@@ -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 }}">
ui/src/app/device/index.js 2(+0 -2)
diff --git a/ui/src/app/device/index.js b/ui/src/app/device/index.js
index ea42ee8..5a8adaf 100644
--- a/ui/src/app/device/index.js
+++ b/ui/src/app/device/index.js
@@ -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
ui/src/app/event/event.scss 4(+2 -2)
diff --git a/ui/src/app/event/event.scss b/ui/src/app/event/event.scss
index 6fa3e67..8622b0d 100644
--- a/ui/src/app/event/event.scss
+++ b/ui/src/app/event/event.scss
@@ -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%;
diff --git a/ui/src/app/event/event-content-dialog.controller.js b/ui/src/app/event/event-content-dialog.controller.js
index 19ddb8c..235cfcf 100644
--- a/ui/src/app/event/event-content-dialog.controller.js
+++ b/ui/src/app/event/event-content-dialog.controller.js
@@ -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();
}
diff --git a/ui/src/app/event/event-content-dialog.tpl.html b/ui/src/app/event/event-content-dialog.tpl.html
index 4cf046b..7b4184c 100644
--- a/ui/src/app/event/event-content-dialog.tpl.html
+++ b/ui/src/app/event/event-content-dialog.tpl.html
@@ -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>
diff --git a/ui/src/app/event/event-header.directive.js b/ui/src/app/event/event-header.directive.js
index 5e8cc7c..c43894e 100644
--- a/ui/src/app/event/event-header.directive.js
+++ b/ui/src/app/event/event-header.directive.js
@@ -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);
}
diff --git a/ui/src/app/event/event-row.directive.js b/ui/src/app/event/event-row.directive.js
index 9bff192..d1feb60 100644
--- a/ui/src/app/event/event-row.directive.js
+++ b/ui/src/app/event/event-row.directive.js
@@ -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);
}
diff --git a/ui/src/app/event/event-table.tpl.html b/ui/src/app/event/event-table.tpl.html
index f44aeb3..82a921f 100644
--- a/ui/src/app/event/event-table.tpl.html
+++ b/ui/src/app/event/event-table.tpl.html
@@ -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()"
ui/src/app/layout/index.js 4(+4 -0)
diff --git a/ui/src/app/layout/index.js b/ui/src/app/layout/index.js
index be63558..2a27c93 100644
--- a/ui/src/app/layout/index.js
+++ b/ui/src/app/layout/index.js
@@ -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,
ui/src/app/locale/locale.constant.js 37(+35 -2)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index cd21747..a54eba4 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -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",
diff --git a/ui/src/app/locale/locale.constant-es.js b/ui/src/app/locale/locale.constant-es.js
index e4d4b49..b9076ba 100644
--- a/ui/src/app/locale/locale.constant-es.js
+++ b/ui/src/app/locale/locale.constant-es.js
@@ -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",
diff --git a/ui/src/app/locale/locale.constant-ko.js b/ui/src/app/locale/locale.constant-ko.js
index 32dbf49..0caeab8 100644
--- a/ui/src/app/locale/locale.constant-ko.js
+++ b/ui/src/app/locale/locale.constant-ko.js
@@ -378,7 +378,6 @@ export default function addLocaleKorean(locales) {
},
"event": {
"event-type": "이벤트 타입",
- "type-alarm": "알람",
"type-error": "에러",
"type-lc-event": "주기적 이벤트",
"type-stats": "통계",
diff --git a/ui/src/app/locale/locale.constant-ru.js b/ui/src/app/locale/locale.constant-ru.js
index d7734b4..cded7a6 100644
--- a/ui/src/app/locale/locale.constant-ru.js
+++ b/ui/src/app/locale/locale.constant-ru.js
@@ -411,7 +411,6 @@ export default function addLocaleRussian(locales) {
},
"event": {
"event-type": "Тип события",
- "type-alarm": "Аварийное оповещение",
"type-error": "Ошибка",
"type-lc-event": "Событие жизненного цикла",
"type-stats": "Статистика",
diff --git a/ui/src/app/locale/locale.constant-zh.js b/ui/src/app/locale/locale.constant-zh.js
index 3246070..62746c7 100644
--- a/ui/src/app/locale/locale.constant-zh.js
+++ b/ui/src/app/locale/locale.constant-zh.js
@@ -411,7 +411,6 @@ export default function addLocaleChinese(locales) {
},
"event" : {
"event-type": "事件类型",
- "type-alarm": "报警",
"type-error": "错误",
"type-lc-event": "生命周期事件",
"type-stats": "类型统计",
ui/src/app/plugin/index.js 2(+0 -2)
diff --git a/ui/src/app/plugin/index.js b/ui/src/app/plugin/index.js
index 1c9e731..6173d62 100644
--- a/ui/src/app/plugin/index.js
+++ b/ui/src/app/plugin/index.js
@@ -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
])
ui/src/app/plugin/plugins.tpl.html 8(+6 -2)
diff --git a/ui/src/app/plugin/plugins.tpl.html b/ui/src/app/plugin/plugins.tpl.html
index 5b03506..73b0adc 100644
--- a/ui/src/app/plugin/plugins.tpl.html
+++ b/ui/src/app/plugin/plugins.tpl.html
@@ -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 }}">
ui/src/app/rule/index.js 2(+0 -2)
diff --git a/ui/src/app/rule/index.js b/ui/src/app/rule/index.js
index 6481920..2700ec7 100644
--- a/ui/src/app/rule/index.js
+++ b/ui/src/app/rule/index.js
@@ -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
ui/src/app/rule/rules.tpl.html 8(+6 -2)
diff --git a/ui/src/app/rule/rules.tpl.html b/ui/src/app/rule/rules.tpl.html
index 098bbee..336fe63 100644
--- a/ui/src/app/rule/rules.tpl.html
+++ b/ui/src/app/rule/rules.tpl.html
@@ -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 }}">
ui/src/app/tenant/tenants.tpl.html 7(+6 -1)
diff --git a/ui/src/app/tenant/tenants.tpl.html b/ui/src/app/tenant/tenants.tpl.html
index 00350a4..e407291 100644
--- a/ui/src/app/tenant/tenants.tpl.html
+++ b/ui/src/app/tenant/tenants.tpl.html
@@ -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 }}">
ui/src/scss/main.scss 18(+18 -0)
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss
index bf44493..ab720c5 100644
--- a/ui/src/scss/main.scss
+++ b/ui/src/scss/main.scss
@@ -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