Browse Source

Merge pull request #73 from deaflynx/develop/2.6-edge

Develop/2.6 edge
pull/3957/head
VoBa 6 years ago
committed by GitHub
parent
commit
f9ebbe1481
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 128
      ui/src/app/common/types.constant.js
  2. 93
      ui/src/app/edge/downlinks/downlink.scss
  3. 92
      ui/src/app/edge/downlinks/edge-downlinks-content-dialog.controller.js
  4. 42
      ui/src/app/edge/downlinks/edge-downlinks-content-dialog.tpl.html
  5. 39
      ui/src/app/edge/downlinks/edge-downlinks-header.directive.js
  6. 6
      ui/src/app/edge/downlinks/edge-downlinks-header.tpl.html
  7. 124
      ui/src/app/edge/downlinks/edge-downlinks-row.directive.js
  8. 12
      ui/src/app/edge/downlinks/edge-downlinks-row.tpl.html
  9. 230
      ui/src/app/edge/downlinks/edge-downlinks-table.directive.js
  10. 46
      ui/src/app/edge/downlinks/edge-downlinks-table.tpl.html
  11. 6
      ui/src/app/edge/edges.tpl.html
  12. 8
      ui/src/app/edge/index.js
  13. 4
      ui/src/app/event/event-header.directive.js
  14. 84
      ui/src/app/event/event-row.directive.js
  15. 84
      ui/src/app/event/event-table.directive.js
  16. 1
      ui/src/app/locale/locale.constant-de_DE.json
  17. 49
      ui/src/app/locale/locale.constant-en_US.json
  18. 1
      ui/src/app/locale/locale.constant-es_ES.json

128
ui/src/app/common/types.constant.js

@ -661,10 +661,6 @@ export default angular.module('thingsboard.types', [])
stats: { stats: {
value: "STATS", value: "STATS",
name: "event.type-stats" name: "event.type-stats"
},
edgeEvent: {
value: "EDGE_EVENT",
name: "event.type-edge-event"
} }
}, },
debugEventType: { debugEventType: {
@ -1077,126 +1073,126 @@ export default angular.module('thingsboard.types', [])
translate: { translate: {
customTranslationsPrefix: "custom." customTranslationsPrefix: "custom."
}, },
edgeEventActionType: { edgeEventActionTypeTranslations: {
"ADDED": { "ADDED": {
name: "audit-log.type-added" name: "edge-event.action-type-added"
}, },
"DELETED": { "DELETED": {
name: "audit-log.type-deleted" name: "edge-event.action-type-deleted"
}, },
"UPDATED": { "UPDATED": {
name: "audit-log.type-updated" name: "edge-event.action-type-updated"
},
"POST_ATTRIBUTES": {
name: "edge-event.action-type-post-attributes"
},
"TIMESERIES_UPDATED": {
name: "edge-event.action-type-timeseries-updated"
}, },
"ATTRIBUTES_UPDATED": { "ATTRIBUTES_UPDATED": {
name: "audit-log.type-attributes-updated" name: "edge-event.action-type-attributes-updated"
}, },
"ATTRIBUTES_DELETED": { "ATTRIBUTES_DELETED": {
name: "audit-log.type-attributes-deleted" name: "edge-event.action-type-attributes-deleted"
},
"RPC_CALL": {
name: "audit-log.type-rpc-call"
}, },
"CREDENTIALS_UPDATED": { "CREDENTIALS_UPDATED": {
name: "audit-log.type-credentials-updated" name: "edge-event.action-type-credentials-updated"
},
"ASSIGNED_TO_CUSTOMER": {
name: "edge-event.action-type-assigned-to-customer"
},
"UNASSIGNED_FROM_CUSTOMER": {
name: "edge-event.action-type-unassigned-from-customer"
}, },
"RELATION_ADD_OR_UPDATE": { "RELATION_ADD_OR_UPDATE": {
name: "audit-log.type-relation-add-or-update" name: "edge-event.action-type-relation-add-or-update"
}, },
"RELATION_DELETED": { "RELATION_DELETED": {
name: "audit-log.type-relation-delete" name: "edge-event.action-type-relation-deleted"
},
"RPC_CALL": {
name: "edge-event.action-type-rpc-call"
}, },
"ALARM_ACK": { "ALARM_ACK": {
name: "audit-log.type-alarm-ack" name: "edge-event.action-type-alarm-ack"
}, },
"ALARM_CLEAR": { "ALARM_CLEAR": {
name: "audit-log.type-alarm-clear" name: "edge-event.action-type-alarm-clear"
}, },
"CREDENTIALS_REQUEST": { "CREDENTIALS_REQUEST": {
name: "edge.credentials-request" name: "edge-event.action-type-credentials-request"
},
"ATTRIBUTES_REQUEST": {
name: "edge.attributes-request"
},
"TIMESERIES_UPDATED": {
name: "edge.timeseries-updated"
},
"RELATION_REQUEST": {
name: "edge.relation-request"
},
"RULE_CHAIN_METADATA_REQUEST": {
name: "edge.rule-chain-metadata-request"
},
"GROUP_ENTITIES_REQUEST": {
name: "edge.group_entities_request"
},
"GROUP_PERMISSIONS_REQUEST": {
name: "edge.group-permissions-request"
}, },
"ASSIGNED_TO_EDGE": { "ASSIGNED_TO_EDGE": {
name: "audit-log.type-assigned-to-edge" name: "edge-event.action-type-assigned-to-edge"
}, },
"UNASSIGNED_FROM_EDGE": { "UNASSIGNED_FROM_EDGE": {
name: "audit-log.type-unassigned-from-edge" name: "edge-event.action-type-unassigned-from-edge"
},
"ENTITY_MERGE_REQUEST": {
name: "edge-event.action-type-entity-merge-request"
} }
}, },
edgeEventTypeTranslations:{ edgeEventTypeTranslations:{
"DASHBOARD": { "DASHBOARD": {
name: "entity.type-dashboard" name: "edge-event.type-dashboard"
}, },
"ASSET": { "ASSET": {
name: "entity.type-asset" name: "edge-event.type-asset"
}, },
"DEVICE": { "DEVICE": {
name: "entity.type-device" name: "edge-event.type-device"
}, },
"ENTITY_VIEW": { "ENTITY_VIEW": {
name: "entity.type-entity_view" name: "edge-event.type-entity-view"
}, },
"ALARM": { "ALARM": {
name: "entity.type-alarm" name: "edge-event.type-alarm"
}, },
"RULE_CHAIN": { "RULE_CHAIN": {
name: "entity.type-rulechain" name: "edge-event.type-rule-chain"
}, },
"RULE_CHAIN_META_DATA": { "RULE_CHAIN_METADATA": {
name: "entity.type-rule-chain-metadata" name: "edge-event.type-rule-chain-metadata"
}, },
"EDGE": { "EDGE": {
name: "entity.type-edge" name: "edge-event.type-edge"
}, },
"USER": { "USER": {
name: "entity.type-user" name: "edge-event.type-user"
},
"TENANT": {
name: "edge-event.type-tenant"
}, },
"CUSTOMER": { "CUSTOMER": {
name: "entity.type-customer" name: "edge-event.type-customer"
}, },
"RELATION": { "RELATION": {
name: "entity.type-relation" name: "edge-event.type-relation"
},
"WIDGETS_BUNDLE": {
name: "edge-event.type-widgets-bundle"
},
"WIDGET_TYPE": {
name: "edge-event.type-widgets-type"
},
"ADMIN_SETTINGS": {
name: "edge-event.type-admin-settings"
}, },
"ENTITY_GROUP": { "ENTITY_GROUP": {
name: "entity.type-entity-group" name: "edge-event.type-entity-group"
}, },
"SCHEDULER_EVENT": { "SCHEDULER_EVENT": {
name: "entity.type-scheduler-event" name: "edge-event.type-scheduler-event"
}, },
"WHITE_LABELING": { "WHITE_LABELING": {
name: "white-labeling.white-labeling" name: "edge-event.type-white-labeling"
}, },
"LOGIN_WHITE_LABELING": { "LOGIN_WHITE_LABELING": {
name: "white-labeling.login-white-labeling" name: "edge-event.type-login-white-labeling"
}, },
"CUSTOM_TRANSLATION": { "CUSTOM_TRANSLATION": {
name: "custom-translation.custom-translation", name: "edge-event.custom-translation",
},
"WIDGETS_BUNDLE": {
name: "widget.widget-bundle"
},
"WIDGET_TYPE": {
name: "widget.type"
},
"ADMIN_SETTINGS": {
name: "permission.resource.display-type.ADMIN_SETTINGS"
} }
}, }
} }
).name; ).name;

93
ui/src/app/edge/downlinks/downlink.scss

@ -0,0 +1,93 @@
/**
* Copyright © 2016-2020 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-list.tb-edge-downlinks-table {
padding: 0;
md-list-item {
padding: 0;
}
.tb-row {
height: 48px;
padding: 0;
overflow: hidden;
.tb-cell {
text-overflow: ellipsis;
&.tb-scroll {
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
}
&.tb-nowrap {
white-space: nowrap;
}
}
}
.tb-row:hover {
background-color: #eee;
}
.tb-header:hover {
background: none;
}
.tb-header {
.tb-cell {
font-size: 12px;
font-weight: 700;
color: rgba(0, 0, 0, .54);
white-space: nowrap;
background: none;
}
}
.tb-cell {
&:first-child {
padding-left: 14px;
}
&:last-child {
padding-right: 14px;
}
padding: 0 6px;
margin: auto 0;
overflow: hidden;
font-size: 13px;
color: rgba(0, 0, 0, .87);
text-align: left;
vertical-align: middle;
.md-button {
padding: 0;
margin: 0;
}
}
.tb-cell.tb-number {
text-align: right;
}
}
#tb-edge-downlinks-content {
width: 100%;
min-width: 400px;
height: 100%;
min-height: 50px;
}

92
ui/src/app/edge/downlinks/edge-downlinks-content-dialog.controller.js

@ -0,0 +1,92 @@
/*
* Copyright © 2016-2020 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 $ from 'jquery';
import 'brace/ext/language_tools';
import 'brace/ext/searchbox';
import 'brace/mode/java';
import 'brace/theme/github';
import beautify from 'js-beautify';
/* eslint-disable angular/angularelement */
const js_beautify = beautify.js;
/*@ngInject*/
export default function EdgeDownlinksContentDialogController($mdDialog, types, content, contentType, title, showingCallback) {
var vm = this;
showingCallback.onShowing = function(scope, element) {
updateEditorSize(element);
}
vm.content = content;
vm.title = title;
var mode;
if (contentType) {
mode = types.contentType[contentType].code;
if (contentType == types.contentType.JSON.value && vm.content) {
vm.content = js_beautify(vm.content, {indent_size: 4});
}
} else {
mode = 'java';
}
vm.contentOptions = {
useWrapMode: false,
mode: mode,
showGutter: false,
showPrintMargin: false,
theme: 'github',
advanced: {
enableSnippets: false,
enableBasicAutocompletion: false,
enableLiveAutocompletion: false
},
onLoad: function (_ace) {
vm.editor = _ace;
}
};
function updateEditorSize(element) {
var newHeight = 400;
var newWidth = 600;
if (vm.content && vm.content.length > 0) {
var lines = vm.content.split('\n');
newHeight = 16 * lines.length + 16;
var maxLineLength = 0;
for (var i = 0; i < lines.length; i++) {
var line = lines[i].replace(/\t/g, ' ').replace(/\n/g, '');
var lineLength = line.length;
maxLineLength = Math.max(maxLineLength, lineLength);
}
newWidth = 8 * maxLineLength + 16;
}
$('#tb-edge-downlinks-content', element).height(newHeight.toString() + "px")
.width(newWidth.toString() + "px");
vm.editor.resize();
}
vm.close = close;
function close () {
$mdDialog.hide();
}
}
/* eslint-enable angular/angularelement */

42
ui/src/app/edge/downlinks/edge-downlinks-content-dialog.tpl.html

@ -0,0 +1,42 @@
<!--
Copyright © 2016-2020 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="{{ vm.title | translate }}">
<md-toolbar>
<div class="md-toolbar-tools">
<h2 translate>{{ vm.title }}</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">
<div flex id="tb-edge-downlinks-content" readonly
ui-ace="vm.contentOptions"
ng-model="vm.content">
</div>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
<span flex></span>
<md-button ng-disabled="$root.loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' |
translate }}
</md-button>
</md-dialog-actions>
</md-dialog>

39
ui/src/app/edge/downlinks/edge-downlinks-header.directive.js

@ -0,0 +1,39 @@
/*
* Copyright © 2016-2020 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 edgeDownlinksHeaderTemplate from './edge-downlinks-header.tpl.html'
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function EdgeDownlinksHeaderDirective($compile, $templateCache) {
var linker = function (scope, element) {
var template = edgeDownlinksHeaderTemplate;
element.html($templateCache.get(template));
$compile(element.contents())(scope);
}
return {
restrict: "A",
replace: false,
link: linker,
scope: false
};
}

6
ui/src/app/event/event-header-edge-event.tpl.html → ui/src/app/edge/downlinks/edge-downlinks-header.tpl.html

@ -16,8 +16,8 @@
--> -->
<div translate class="tb-cell" flex="20">event.event-time</div> <div translate class="tb-cell" flex="20">event.event-time</div>
<div translate class="tb-cell" flex="10">event.event-type</div> <div translate class="tb-cell" flex="15">event.type</div>
<div translate class="tb-cell" flex="15">edge.event-action</div> <div translate class="tb-cell" flex="15">edge.event-action</div>
<div translate class="tb-cell" flex="30">edge.entity-id</div> <div translate class="tb-cell" flex="30">edge.entity-id</div>
<div translate class="tb-cell" flex="15">edge.status</div> <div translate class="tb-cell" flex="10">event.status</div>
<div translate class="tb-cell" flex="10">edge.entity-info</div> <div translate class="tb-cell" flex="10">event.data</div>

124
ui/src/app/edge/downlinks/edge-downlinks-row.directive.js

@ -0,0 +1,124 @@
/*
* Copyright © 2016-2020 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 edgeDownlinksContentTemplate from './edge-downlinks-content-dialog.tpl.html';
import edgeDownlinlsRowTemplate from './edge-downlinks-row.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function EdgeDownlinksRowDirective($compile, $templateCache, $mdDialog, $document, $translate,
types, utils, toast, entityService, ruleChainService) {
var linker = function (scope, element, attrs) {
var template = edgeDownlinlsRowTemplate;
element.html($templateCache.get(template));
$compile(element.contents())(scope);
scope.types = types;
scope.downlink = attrs.downlink;
scope.showEdgeEntityContent = function($event, title, contentType) {
var onShowingCallback = {
onShowing: function(){}
}
if (!contentType) {
contentType = null;
}
var content = '';
switch(scope.downlink.type) {
case types.edgeEventType.relation:
content = angular.toJson(scope.downlink.body);
showDialog();
break;
case types.edgeEventType.ruleChainMetaData:
content = ruleChainService.getRuleChainMetaData(scope.downlink.entityId, {ignoreErrors: true}).then(
function success(info) {
showDialog();
return angular.toJson(info);
}, function fail() {
showError();
});
break;
default:
content = entityService.getEntity(scope.downlink.type, scope.downlink.entityId, {ignoreErrors: true}).then(
function success(info) {
showDialog();
return angular.toJson(info);
}, function fail() {
showError();
});
break;
}
function showDialog() {
$mdDialog.show({
controller: 'EdgeDownlinksContentDialogController',
controllerAs: 'vm',
templateUrl: edgeDownlinksContentTemplate,
locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},
parent: angular.element($document[0].body),
fullscreen: true,
targetEvent: $event,
multiple: true,
onShowing: function(scope, element) {
onShowingCallback.onShowing(scope, element);
}
});
}
function showError() {
toast.showError($translate.instant('edge.load-entity-error'));
}
}
scope.checkEdgeDownlinksType = function (type) {
return !(type === types.edgeEventType.widgetType ||
type === types.edgeEventType.adminSettings ||
type === types.edgeEventType.widgetsBundle );
}
scope.checkTooltip = function($event) {
var el = $event.target;
var $el = angular.element(el);
if(el.offsetWidth < el.scrollWidth && !$el.attr('title')){
$el.attr('title', $el.text());
}
}
$compile(element.contents())(scope);
scope.updateStatus = function(downlinkCreatedTime) {
var status;
if (downlinkCreatedTime < scope.queueStartTs) {
status = $translate.instant(types.edgeEventStatus.DEPLOYED.name);
scope.statusColor = types.edgeEventStatus.DEPLOYED.color;
} else {
status = $translate.instant(types.edgeEventStatus.PENDING.name);
scope.statusColor = types.edgeEventStatus.PENDING.color;
}
return status;
}
}
return {
restrict: "A",
replace: false,
link: linker,
scope: false
};
}

12
ui/src/app/event/event-row-edge-event.tpl.html → ui/src/app/edge/downlinks/edge-downlinks-row.tpl.html

@ -15,13 +15,13 @@
limitations under the License. limitations under the License.
--> -->
<div class="tb-cell" flex="20">{{ event.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}</div> <div class="tb-cell" flex="20">{{ downlink.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}</div>
<div class="tb-cell" flex="10">{{ event.edgeEventTypeText }}</div> <div class="tb-cell" flex="15">{{ downlink.edgeEventTypeText }}</div>
<div class="tb-cell" flex="15">{{ event.edgeEventActionText }}</div> <div class="tb-cell" flex="15">{{ downlink.edgeEventActionText }}</div>
<div class="tb-cell" flex="30">{{ event.entityId }}</div> <div class="tb-cell" flex="30">{{ downlink.entityId }}</div>
<div class="tb-cell" flex="15" ng-style="{'color': statusColor}">{{ updateStatus(event.createdTime) }}</div> <div class="tb-cell" flex="10" ng-style="{'color': statusColor}">{{ updateStatus(downlink.createdTime) }}</div>
<div class="tb-cell" flex="10"> <div class="tb-cell" flex="10">
<md-button ng-if="checkEdgeEventType(event.type)" class="md-icon-button md-primary" <md-button ng-if="checkEdgeDownlinksType(downlink.type)" class="md-icon-button md-primary"
ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')" ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')"
aria-label="{{ 'action.view' | translate }}"> aria-label="{{ 'action.view' | translate }}">
<md-tooltip md-direction="top"> <md-tooltip md-direction="top">

230
ui/src/app/edge/downlinks/edge-downlinks-table.directive.js

@ -0,0 +1,230 @@
/*
* Copyright © 2016-2020 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 './downlink.scss';
/* eslint-disable import/no-unresolved, import/default */
import edgeDownlinksTableTemplate from './edge-downlinks-table.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function EdgeDownlinksDirective($compile, $templateCache, $rootScope, $translate, types, edgeService, attributeService) {
var linker = function (scope, element) {
var template = $templateCache.get(edgeDownlinksTableTemplate);
element.html(template);
var pageSize = 20;
var startTime = 0;
var endTime = 0;
scope.timewindow = {
history: {
timewindowMs: 24 * 60 * 60 * 1000 // 1 day
}
}
scope.topIndex = 0;
scope.theDownlinks = {
getItemAtIndex: function (index) {
if (index > scope.downlinks.data.length) {
scope.theDownlinks.fetchMoreItems_(index);
return null;
}
var item = scope.downlinks.data[index];
if (item) {
item.indexNumber = index + 1;
}
return item;
},
getLength: function () {
if (scope.downlinks.hasNext) {
return scope.downlinks.data.length + scope.downlinks.nextPageLink.limit;
} else {
return scope.downlinks.data.length;
}
},
fetchMoreItems_: function () {
if (scope.downlinks.hasNext && !scope.downlinks.pending) {
if (scope.entityType && scope.entityId && scope.tenantId) {
scope.loadEdgeInfo();
scope.downlinks.pending = true;
edgeService.getEdgeEvents(scope.entityId, scope.downlinks.nextPageLink).then(
function success(downlinks) {
scope.downlinks.data = scope.downlinks.data.concat(prepareEdgeDownlinksData(downlinks.data));
scope.downlinks.nextPageLink = downlinks.nextPageLink;
scope.downlinks.hasNext = downlinks.hasNext;
if (scope.downlinks.hasNext) {
scope.downlinks.nextPageLink.limit = pageSize;
}
scope.downlinks.pending = false;
},
function fail() {
scope.downlinks.hasNext = false;
scope.downlinks.pending = false;
});
} else {
scope.downlinks.hasNext = false;
}
}
}
};
scope.$watch("entityId", function(newVal, prevVal) {
if (newVal && !angular.equals(newVal, prevVal)) {
scope.resetFilter();
scope.reload();
}
});
scope.$watch("timewindow", function(newVal, prevVal) {
if (newVal && !angular.equals(newVal, prevVal)) {
scope.reload();
}
}, true);
scope.resetFilter = function() {
scope.timewindow = {
history: {
timewindowMs: 24 * 60 * 60 * 1000 // 1 day
}
};
}
scope.updateTimeWindowRange = function() {
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;
}
}
scope.reload = function() {
scope.topIndex = 0;
scope.selected = [];
scope.updateTimeWindowRange();
scope.downlinks = {
data: [],
nextPageLink: {
limit: pageSize,
startTime: startTime,
endTime: endTime
},
hasNext: true,
pending: false
};
scope.theDownlinks.getItemAtIndex(pageSize);
}
scope.noData = function() {
return scope.downlinks.data.length == 0 && !scope.downlinks.hasNext;
}
scope.hasData = function() {
return scope.downlinks.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;
}
scope.subscriptionId = null;
scope.loadEdgeInfo = function() {
attributeService.getEntityAttributesValues(
scope.entityType,
scope.entityId,
types.attributesScope.server.value,
types.edgeAttributeKeys.queueStartTs,
null).then(
function success(attributes) {
attributes.length > 0 ? scope.onEdgeAttributesUpdate(attributes) : scope.queueStartTs = 0;
});
scope.checkSubscription();
}
scope.onEdgeAttributesUpdate = function(attributes) {
let edgeAttributes = attributes.reduce(function (map, attribute) {
map[attribute.key] = attribute;
return map;
}, {});
if (edgeAttributes.queueStartTs) {
scope.queueStartTs = edgeAttributes.queueStartTs.lastUpdateTs;
}
}
scope.checkSubscription = function() {
var newSubscriptionId = null;
if (scope.entityId && scope.entityType && types.attributesScope.server.value) {
newSubscriptionId =
attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value);
}
if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
scope.subscriptionId = newSubscriptionId;
}
scope.$on('$destroy', function () {
if (scope.subscriptionId) {
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
});
scope.reload();
$compile(element.contents())(scope);
}
function prepareEdgeDownlinksData(data) {
data.forEach(
edgeDownlink => {
edgeDownlink.edgeEventActionText = $translate.instant(types.edgeEventActionTypeTranslations[edgeDownlink.action].name);
edgeDownlink.edgeEventTypeText = $translate.instant(types.edgeEventTypeTranslations[edgeDownlink.type].name);
}
);
return data;
}
return {
restrict: "E",
link: linker,
scope: {
entityType: '=',
entityId: '=',
tenantId: '='
}
};
}

46
ui/src/app/edge/downlinks/edge-downlinks-table.tpl.html

@ -0,0 +1,46 @@
<!--
Copyright © 2016-2020 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">
<tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow>
<md-button ng-disabled="$root.loading"
class="md-icon-button" ng-click="reload()">
<md-icon>refresh</md-icon>
<md-tooltip md-direction="top">
{{ 'action.refresh' | translate }}
</md-tooltip>
</md-button>
</section>
<md-list flex layout="column" class="md-whiteframe-z1 tb-edge-downlinks-table">
<md-list class="tb-row tb-header" layout="row" layout-align="start center" tb-edge-downlinks-header>
</md-list>
<md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!$root.loading"
ng-show="$root.loading"></md-progress-linear>
<md-divider></md-divider>
<span translate layout-align="center center"
style="margin-top: 25px;"
class="tb-prompt" ng-show="noData()">edge.no-downlinks-prompt</span>
<md-virtual-repeat-container ng-show="hasData()" flex md-top-index="topIndex" tb-scope-element="repeatContainer">
<md-list-item md-virtual-repeat="downlink in theDownlinks" md-on-demand flex ng-style="hasScroll() ? {'margin-right':'-15px'} : {}">
<md-list class="tb-row" flex layout="row" layout-align="start center" tb-edge-downlinks-row downlink="{{downlink}}">
</md-list>
<md-divider flex></md-divider>
</md-list-item>
</md-virtual-repeat-container>
</md-list>
</md-content>

6
ui/src/app/edge/edges.tpl.html

@ -65,6 +65,12 @@
default-event-type="{{vm.types.eventType.error.value}}"> default-event-type="{{vm.types.eventType.error.value}}">
</tb-event-table> </tb-event-table>
</md-tab> </md-tab>
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.downlinks' | translate }}">
<tb-edge-downlinks-table flex entity-type="vm.types.entityType.edge"
entity-id="vm.grid.operatingItem().id.id"
tenant-id="vm.grid.operatingItem().tenantId.id">
</tb-edge-downlinks-table>
</md-tab>
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
<tb-relation-table flex <tb-relation-table flex
readonly="!('edge' | hasGenericPermission:'write')" readonly="!('edge' | hasGenericPermission:'write')"

8
ui/src/app/edge/index.js

@ -25,6 +25,10 @@ import AssignEdgeToCustomerController from './assign-to-customer.controller';
import AddEdgesToCustomerController from './add-edges-to-customer.controller'; import AddEdgesToCustomerController from './add-edges-to-customer.controller';
import SetRootRuleChainToEdgesController from './set-root-rule-chain-to-edges.controller'; import SetRootRuleChainToEdgesController from './set-root-rule-chain-to-edges.controller';
import EdgeDirective from './edge.directive'; import EdgeDirective from './edge.directive';
import EdgeDownlinksContentDialogController from './downlinks/edge-downlinks-content-dialog.controller';
import EdgeDownlinksHeaderDirective from './downlinks/edge-downlinks-header.directive';
import EdgeDownlinksRowDirective from './downlinks/edge-downlinks-row.directive';
import EdgeDownlinksDirective from "./downlinks/edge-downlinks-table.directive";
export default angular.module('thingsboard.edge', [ export default angular.module('thingsboard.edge', [
uiRouter, uiRouter,
@ -39,5 +43,9 @@ export default angular.module('thingsboard.edge', [
.controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController) .controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController)
.controller('AddEdgesToCustomerController', AddEdgesToCustomerController) .controller('AddEdgesToCustomerController', AddEdgesToCustomerController)
.controller('SetRootRuleChainToEdgesController', SetRootRuleChainToEdgesController) .controller('SetRootRuleChainToEdgesController', SetRootRuleChainToEdgesController)
.controller('EdgeDownlinksContentDialogController', EdgeDownlinksContentDialogController)
.directive('tbEdge', EdgeDirective) .directive('tbEdge', EdgeDirective)
.directive('tbEdgeDownlinksTable', EdgeDownlinksDirective)
.directive('tbEdgeDownlinksHeader', EdgeDownlinksHeaderDirective)
.directive('tbEdgeDownlinksRow', EdgeDownlinksRowDirective)
.name; .name;

4
ui/src/app/event/event-header.directive.js

@ -19,7 +19,6 @@ import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html';
import eventHeaderStatsTemplate from './event-header-stats.tpl.html'; import eventHeaderStatsTemplate from './event-header-stats.tpl.html';
import eventHeaderErrorTemplate from './event-header-error.tpl.html'; import eventHeaderErrorTemplate from './event-header-error.tpl.html';
import eventHeaderDebugRuleNodeTemplate from './event-header-debug-rulenode.tpl.html'; import eventHeaderDebugRuleNodeTemplate from './event-header-debug-rulenode.tpl.html';
import eventHeaderEdgeEventTemplate from './event-header-edge-event.tpl.html'
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
@ -46,9 +45,6 @@ export default function EventHeaderDirective($compile, $templateCache, types) {
case types.debugEventType.debugRuleChain.value: case types.debugEventType.debugRuleChain.value:
template = eventHeaderDebugRuleNodeTemplate; template = eventHeaderDebugRuleNodeTemplate;
break; break;
case types.eventType.edgeEvent.value:
template = eventHeaderEdgeEventTemplate;
break;
} }
return $templateCache.get(template); return $templateCache.get(template);
} }

84
ui/src/app/event/event-row.directive.js

@ -21,13 +21,12 @@ import eventRowLcEventTemplate from './event-row-lc-event.tpl.html';
import eventRowStatsTemplate from './event-row-stats.tpl.html'; import eventRowStatsTemplate from './event-row-stats.tpl.html';
import eventRowErrorTemplate from './event-row-error.tpl.html'; import eventRowErrorTemplate from './event-row-error.tpl.html';
import eventRowDebugRuleNodeTemplate from './event-row-debug-rulenode.tpl.html'; import eventRowDebugRuleNodeTemplate from './event-row-debug-rulenode.tpl.html';
import eventRowEdgeEventTemplate from './event-row-edge-event.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/ /*@ngInject*/
export default function EventRowDirective($compile, $templateCache, $mdDialog, $document, $translate, export default function EventRowDirective($compile, $templateCache, $mdDialog, $document, $translate,
types, utils, toast, entityService, ruleChainService) { types, utils) {
var linker = function (scope, element, attrs) { var linker = function (scope, element, attrs) {
@ -49,9 +48,6 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
case types.debugEventType.debugRuleChain.value: case types.debugEventType.debugRuleChain.value:
template = eventRowDebugRuleNodeTemplate; template = eventRowDebugRuleNodeTemplate;
break; break;
case types.eventType.edgeEvent.value:
template = eventRowEdgeEventTemplate;
break;
} }
return $templateCache.get(template); return $templateCache.get(template);
} }
@ -98,85 +94,7 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
}); });
} }
scope.showEdgeEntityContent = function($event, title, contentType) {
var onShowingCallback = {
onShowing: function(){}
}
if (!contentType) {
contentType = null;
}
var content = '';
switch(scope.event.type) {
case types.edgeEventType.relation:
content = angular.toJson(scope.event.body);
showDialog();
break;
case types.edgeEventType.ruleChainMetaData:
content = ruleChainService.getRuleChainMetaData(scope.event.entityId, {ignoreErrors: true}).then(
function success(info) {
showDialog();
return angular.toJson(info);
}, function fail() {
showError();
});
break;
default:
content = entityService.getEntity(scope.event.type, scope.event.entityId, {ignoreErrors: true}).then(
function success(info) {
showDialog();
return angular.toJson(info);
}, function fail() {
showError();
});
break;
}
function showDialog() {
$mdDialog.show({
controller: 'EventContentDialogController',
controllerAs: 'vm',
templateUrl: eventErrorDialogTemplate,
locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},
parent: angular.element($document[0].body),
fullscreen: true,
targetEvent: $event,
multiple: true,
onShowing: function(scope, element) {
onShowingCallback.onShowing(scope, element);
}
});
}
function showError() {
toast.showError($translate.instant('edge.load-entity-error'));
}
}
scope.checkEdgeEventType = function (type) {
return !(type === types.edgeEventType.widgetType ||
type === types.edgeEventType.adminSettings ||
type === types.edgeEventType.widgetsBundle );
}
scope.checkTooltip = function($event) {
var el = $event.target;
var $el = angular.element(el);
if(el.offsetWidth < el.scrollWidth && !$el.attr('title')){
$el.attr('title', $el.text());
}
}
$compile(element.contents())(scope); $compile(element.contents())(scope);
scope.updateStatus = function(eventCreatedTime) {
var status;
if (eventCreatedTime < scope.queueStartTs) {
status = $translate.instant(types.edgeEventStatus.DEPLOYED.name);
scope.statusColor = types.edgeEventStatus.DEPLOYED.color;
} else {
status = $translate.instant(types.edgeEventStatus.PENDING.name);
scope.statusColor = types.edgeEventStatus.PENDING.color;
}
return status;
}
} }
return { return {

84
ui/src/app/event/event-table.directive.js

@ -22,8 +22,7 @@ import eventTableTemplate from './event-table.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/ /*@ngInject*/
export default function EventTableDirective($compile, $templateCache, $rootScope, $translate, types, export default function EventTableDirective($compile, $templateCache, $rootScope, types, eventService) {
eventService, edgeService, attributeService) {
var linker = function (scope, element, attrs) { var linker = function (scope, element, attrs) {
@ -31,16 +30,11 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
element.html(template); element.html(template);
scope.eventTypeScope = angular.copy(types.eventType);
if (scope.entityType !== types.entityType.edge) {
delete scope.eventTypeScope.edgeEvent;
}
if (attrs.disabledEventTypes) { if (attrs.disabledEventTypes) {
var disabledEventTypes = attrs.disabledEventTypes.split(','); var disabledEventTypes = attrs.disabledEventTypes.split(',');
scope.eventTypes = {}; scope.eventTypes = {};
for (var type in scope.eventTypeScope) { for (var type in types.eventType) {
var eventType = scope.eventTypeScope[type]; var eventType = types.eventType[type];
var enabled = true; var enabled = true;
for (var i=0;i<disabledEventTypes.length;i++) { for (var i=0;i<disabledEventTypes.length;i++) {
if (eventType.value === disabledEventTypes[i]) { if (eventType.value === disabledEventTypes[i]) {
@ -53,7 +47,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
} }
} }
} else { } else {
scope.eventTypes = angular.copy(scope.eventTypeScope); scope.eventTypes = angular.copy(types.eventType);
} }
if (attrs.debugEventTypes) { if (attrs.debugEventTypes) {
@ -106,23 +100,13 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
fetchMoreItems_: function () { fetchMoreItems_: function () {
if (scope.events.hasNext && !scope.events.pending) { if (scope.events.hasNext && !scope.events.pending) {
if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) { if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) {
var promise = ''; var promise = eventService.getEvents(scope.entityType, scope.entityId,
if (scope.eventType !== types.eventType.edgeEvent.value) { scope.eventType, scope.tenantId, scope.events.nextPageLink);
promise = eventService.getEvents(scope.entityType, scope.entityId,
scope.eventType, scope.tenantId, scope.events.nextPageLink);
} else {
promise = edgeService.getEdgeEvents(scope.entityId, scope.events.nextPageLink);
scope.loadEdgeInfo();
}
if (promise) { if (promise) {
scope.events.pending = true; scope.events.pending = true;
promise.then( promise.then(
function success(events) { function success(events) {
if (scope.eventType === types.eventType.edgeEvent.value) { scope.events.data = scope.events.data.concat(events.data);
scope.events.data = scope.events.data.concat(prepareEdgeEventData(events.data));
} else {
scope.events.data = scope.events.data.concat(events.data);
}
scope.events.nextPageLink = events.nextPageLink; scope.events.nextPageLink = events.nextPageLink;
scope.events.hasNext = events.hasNext; scope.events.hasNext = events.hasNext;
if (scope.events.hasNext) { if (scope.events.hasNext) {
@ -223,64 +207,10 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
return false; return false;
} }
scope.subscriptionId = null;
scope.loadEdgeInfo = function() {
attributeService.getEntityAttributesValues(
scope.entityType,
scope.entityId,
types.attributesScope.server.value,
types.edgeAttributeKeys.queueStartTs,
null).then(
function success(attributes) {
attributes.length > 0 ? scope.onEdgeAttributesUpdate(attributes) : scope.queueStartTs = 0;
});
scope.checkSubscription();
}
scope.onEdgeAttributesUpdate = function(attributes) {
let edgeAttributes = attributes.reduce(function (map, attribute) {
map[attribute.key] = attribute;
return map;
}, {});
if (edgeAttributes.queueStartTs) {
scope.queueStartTs = edgeAttributes.queueStartTs.lastUpdateTs;
}
}
scope.checkSubscription = function() {
var newSubscriptionId = null;
if (scope.entityId && scope.entityType && types.attributesScope.server.value) {
newSubscriptionId =
attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value);
}
if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
scope.subscriptionId = newSubscriptionId;
}
scope.$on('$destroy', function () {
if (scope.subscriptionId) {
attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
}
});
scope.reload(); scope.reload();
$compile(element.contents())(scope); $compile(element.contents())(scope);
} }
function prepareEdgeEventData(data) {
data.forEach(
edgeEvent => {
edgeEvent.edgeEventActionText = $translate.instant(types.edgeEventActionType[edgeEvent.action].name);
edgeEvent.edgeEventTypeText = $translate.instant(types.edgeEventTypeTranslations[edgeEvent.edgeId.entityType].name);
}
);
return data;
}
return { return {
restrict: "E", restrict: "E",
link: linker, link: linker,

1
ui/src/app/locale/locale.constant-de_DE.json

@ -808,7 +808,6 @@
"deployed": "Bereitgestellt", "deployed": "Bereitgestellt",
"pending": "Steht aus", "pending": "Steht aus",
"entity-id": "Entität ID", "entity-id": "Entität ID",
"entity-info": "Entitätsinfo",
"event-action": "Ereignisaktion", "event-action": "Ereignisaktion",
"load-entity-error": "Entität nicht gefunden. Fehler beim Laden der Informationen", "load-entity-error": "Entität nicht gefunden. Fehler beim Laden der Informationen",
"unassign-edges-text": "Nach der Bestätigung werden alle ausgewählten Kanten nicht zugewiesen und sind für den Kunden nicht zugänglich.", "unassign-edges-text": "Nach der Bestätigung werden alle ausgewählten Kanten nicht zugewiesen und sind für den Kunden nicht zugänglich.",

49
ui/src/app/locale/locale.constant-en_US.json

@ -788,7 +788,6 @@
"cloud-endpoint": "Cloud Endpoint", "cloud-endpoint": "Cloud Endpoint",
"cloud-endpoint-required": "Cloud Endpoint is required.", "cloud-endpoint-required": "Cloud Endpoint is required.",
"description": "Description", "description": "Description",
"entity-info": "Entity info",
"details": "Details", "details": "Details",
"events": "Events", "events": "Events",
"copy-id": "Copy Edge Id", "copy-id": "Copy Edge Id",
@ -845,7 +844,6 @@
"set-root-rule-chain-text": "Please select root rule chain for edge(s)", "set-root-rule-chain-text": "Please select root rule chain for edge(s)",
"set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)", "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",
"set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }", "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }",
"status": "Received by edge",
"deployed": "Deployed", "deployed": "Deployed",
"pending": "Pending", "pending": "Pending",
"unassign-edges-action-title": "Unassign { count, plural, 1 {1 edge} other {# edges} } from customer", "unassign-edges-action-title": "Unassign { count, plural, 1 {1 edge} other {# edges} } from customer",
@ -856,7 +854,51 @@
"license-key-hint": "To obtain your license please navigate to the <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'>pricing page</a> and select the best license option for your case.", "license-key-hint": "To obtain your license please navigate to the <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'>pricing page</a> and select the best license option for your case.",
"cloud-endpoint-hint": "Edge requires HTTP(s) access to Cloud (ThingsBoard CE/PE) to verify the license key. Please specify Cloud URL that Edge is able to connect to.", "cloud-endpoint-hint": "Edge requires HTTP(s) access to Cloud (ThingsBoard CE/PE) to verify the license key. Please specify Cloud URL that Edge is able to connect to.",
"missing-related-rule-chains-title": "Edge has missing related rule chain(s)", "missing-related-rule-chains-title": "Edge has missing related rule chain(s)",
"missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}" "missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}",
"downlinks": "Downlinks",
"no-downlinks-prompt": "No downlinks found"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alar",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
}, },
"error": { "error": {
"unable-to-connect": "Unable to connect to the server! Please check your internet connection.", "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",
@ -1097,7 +1139,6 @@
"type-debug-rule-chain": "Debug", "type-debug-rule-chain": "Debug",
"no-events-prompt": "No events found", "no-events-prompt": "No events found",
"error": "Error", "error": "Error",
"type-edge-event": "Downlink",
"alarm": "Alarm", "alarm": "Alarm",
"event-time": "Event time", "event-time": "Event time",
"server": "Server", "server": "Server",

1
ui/src/app/locale/locale.constant-es_ES.json

@ -821,7 +821,6 @@
"deployed": "Desplegada", "deployed": "Desplegada",
"pending": "Pendiente", "pending": "Pendiente",
"entity-id": "ID de entidad", "entity-id": "ID de entidad",
"entity-info": "Entity info",
"event-action": "Información de la entidad", "event-action": "Información de la entidad",
"load-entity-error": "Entidad no encontrada. No se pudo cargar la información", "load-entity-error": "Entidad no encontrada. No se pudo cargar la información",
"unassign-edges-text": "Después de la confirmación de todos los bordes seleccionados, se anulará la asignación y el cliente no podrá acceder a ellos.", "unassign-edges-text": "Después de la confirmación de todos los bordes seleccionados, se anulará la asignación y el cliente no podrá acceder a ellos.",

Loading…
Cancel
Save