diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index e43dd9aa8a..375adad109 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -661,10 +661,6 @@ export default angular.module('thingsboard.types', []) stats: { value: "STATS", name: "event.type-stats" - }, - edgeEvent: { - value: "EDGE_EVENT", - name: "event.type-edge-event" } }, debugEventType: { @@ -1077,126 +1073,126 @@ export default angular.module('thingsboard.types', []) translate: { customTranslationsPrefix: "custom." }, - edgeEventActionType: { + edgeEventActionTypeTranslations: { "ADDED": { - name: "audit-log.type-added" + name: "edge-event.action-type-added" }, "DELETED": { - name: "audit-log.type-deleted" + name: "edge-event.action-type-deleted" }, "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": { - name: "audit-log.type-attributes-updated" + name: "edge-event.action-type-attributes-updated" }, "ATTRIBUTES_DELETED": { - name: "audit-log.type-attributes-deleted" - }, - "RPC_CALL": { - name: "audit-log.type-rpc-call" + name: "edge-event.action-type-attributes-deleted" }, "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": { - name: "audit-log.type-relation-add-or-update" + name: "edge-event.action-type-relation-add-or-update" }, "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": { - name: "audit-log.type-alarm-ack" + name: "edge-event.action-type-alarm-ack" }, "ALARM_CLEAR": { - name: "audit-log.type-alarm-clear" + name: "edge-event.action-type-alarm-clear" }, "CREDENTIALS_REQUEST": { - name: "edge.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" + name: "edge-event.action-type-credentials-request" }, "ASSIGNED_TO_EDGE": { - name: "audit-log.type-assigned-to-edge" + name: "edge-event.action-type-assigned-to-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:{ "DASHBOARD": { - name: "entity.type-dashboard" + name: "edge-event.type-dashboard" }, "ASSET": { - name: "entity.type-asset" + name: "edge-event.type-asset" }, "DEVICE": { - name: "entity.type-device" + name: "edge-event.type-device" }, "ENTITY_VIEW": { - name: "entity.type-entity_view" + name: "edge-event.type-entity-view" }, "ALARM": { - name: "entity.type-alarm" + name: "edge-event.type-alarm" }, "RULE_CHAIN": { - name: "entity.type-rulechain" + name: "edge-event.type-rule-chain" }, - "RULE_CHAIN_META_DATA": { - name: "entity.type-rule-chain-metadata" + "RULE_CHAIN_METADATA": { + name: "edge-event.type-rule-chain-metadata" }, "EDGE": { - name: "entity.type-edge" + name: "edge-event.type-edge" }, "USER": { - name: "entity.type-user" + name: "edge-event.type-user" + }, + "TENANT": { + name: "edge-event.type-tenant" }, "CUSTOMER": { - name: "entity.type-customer" + name: "edge-event.type-customer" }, "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": { - name: "entity.type-entity-group" + name: "edge-event.type-entity-group" }, "SCHEDULER_EVENT": { - name: "entity.type-scheduler-event" + name: "edge-event.type-scheduler-event" }, "WHITE_LABELING": { - name: "white-labeling.white-labeling" + name: "edge-event.type-white-labeling" }, "LOGIN_WHITE_LABELING": { - name: "white-labeling.login-white-labeling" + name: "edge-event.type-login-white-labeling" }, "CUSTOM_TRANSLATION": { - name: "custom-translation.custom-translation", - }, - "WIDGETS_BUNDLE": { - name: "widget.widget-bundle" - }, - "WIDGET_TYPE": { - name: "widget.type" - }, - "ADMIN_SETTINGS": { - name: "permission.resource.display-type.ADMIN_SETTINGS" + name: "edge-event.custom-translation", } - }, + } } ).name; diff --git a/ui/src/app/edge/downlinks/downlink.scss b/ui/src/app/edge/downlinks/downlink.scss new file mode 100644 index 0000000000..9f975fc1e1 --- /dev/null +++ b/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; +} diff --git a/ui/src/app/edge/downlinks/edge-downlinks-content-dialog.controller.js b/ui/src/app/edge/downlinks/edge-downlinks-content-dialog.controller.js new file mode 100644 index 0000000000..432bdf4d50 --- /dev/null +++ b/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 */ diff --git a/ui/src/app/edge/downlinks/edge-downlinks-content-dialog.tpl.html b/ui/src/app/edge/downlinks/edge-downlinks-content-dialog.tpl.html new file mode 100644 index 0000000000..798990ec07 --- /dev/null +++ b/ui/src/app/edge/downlinks/edge-downlinks-content-dialog.tpl.html @@ -0,0 +1,42 @@ + + + +
+

{{ vm.title }}

+ + + + +
+
+ +
+ +
+
+ + + {{ 'action.close' | + translate }} + + +
diff --git a/ui/src/app/edge/downlinks/edge-downlinks-header.directive.js b/ui/src/app/edge/downlinks/edge-downlinks-header.directive.js new file mode 100644 index 0000000000..3af243ca48 --- /dev/null +++ b/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 + }; +} diff --git a/ui/src/app/event/event-header-edge-event.tpl.html b/ui/src/app/edge/downlinks/edge-downlinks-header.tpl.html similarity index 81% rename from ui/src/app/event/event-header-edge-event.tpl.html rename to ui/src/app/edge/downlinks/edge-downlinks-header.tpl.html index 3de281ddc7..e08f688142 100644 --- a/ui/src/app/event/event-header-edge-event.tpl.html +++ b/ui/src/app/edge/downlinks/edge-downlinks-header.tpl.html @@ -16,8 +16,8 @@ -->
event.event-time
-
event.event-type
+
event.type
edge.event-action
edge.entity-id
-
edge.status
-
edge.entity-info
+
event.status
+
event.data
diff --git a/ui/src/app/edge/downlinks/edge-downlinks-row.directive.js b/ui/src/app/edge/downlinks/edge-downlinks-row.directive.js new file mode 100644 index 0000000000..16015d12db --- /dev/null +++ b/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 + }; +} diff --git a/ui/src/app/event/event-row-edge-event.tpl.html b/ui/src/app/edge/downlinks/edge-downlinks-row.tpl.html similarity index 68% rename from ui/src/app/event/event-row-edge-event.tpl.html rename to ui/src/app/edge/downlinks/edge-downlinks-row.tpl.html index a842b5d787..7fe595bc8c 100644 --- a/ui/src/app/event/event-row-edge-event.tpl.html +++ b/ui/src/app/edge/downlinks/edge-downlinks-row.tpl.html @@ -15,13 +15,13 @@ limitations under the License. --> -
{{ event.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}
-
{{ event.edgeEventTypeText }}
-
{{ event.edgeEventActionText }}
-
{{ event.entityId }}
-
{{ updateStatus(event.createdTime) }}
+
{{ downlink.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}
+
{{ downlink.edgeEventTypeText }}
+
{{ downlink.edgeEventActionText }}
+
{{ downlink.entityId }}
+
{{ updateStatus(downlink.createdTime) }}
- diff --git a/ui/src/app/edge/downlinks/edge-downlinks-table.directive.js b/ui/src/app/edge/downlinks/edge-downlinks-table.directive.js new file mode 100644 index 0000000000..98bd63abb0 --- /dev/null +++ b/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: '=' + } + }; +} diff --git a/ui/src/app/edge/downlinks/edge-downlinks-table.tpl.html b/ui/src/app/edge/downlinks/edge-downlinks-table.tpl.html new file mode 100644 index 0000000000..0e66b2b685 --- /dev/null +++ b/ui/src/app/edge/downlinks/edge-downlinks-table.tpl.html @@ -0,0 +1,46 @@ + + +
+ + + refresh + + {{ 'action.refresh' | translate }} + + +
+ + + + + + edge.no-downlinks-prompt + + + + + + + + +
diff --git a/ui/src/app/edge/edges.tpl.html b/ui/src/app/edge/edges.tpl.html index 2600413255..ea40c80b06 100644 --- a/ui/src/app/edge/edges.tpl.html +++ b/ui/src/app/edge/edges.tpl.html @@ -65,6 +65,12 @@ default-event-type="{{vm.types.eventType.error.value}}"> + + + + 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 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 { restrict: "E", link: linker, diff --git a/ui/src/app/locale/locale.constant-de_DE.json b/ui/src/app/locale/locale.constant-de_DE.json index 6c69c25910..1f495ccdf0 100644 --- a/ui/src/app/locale/locale.constant-de_DE.json +++ b/ui/src/app/locale/locale.constant-de_DE.json @@ -808,7 +808,6 @@ "deployed": "Bereitgestellt", "pending": "Steht aus", "entity-id": "Entität ID", - "entity-info": "Entitätsinfo", "event-action": "Ereignisaktion", "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.", diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 56f45586c3..c9522365b6 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -788,7 +788,6 @@ "cloud-endpoint": "Cloud Endpoint", "cloud-endpoint-required": "Cloud Endpoint is required.", "description": "Description", - "entity-info": "Entity info", "details": "Details", "events": "Events", "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-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} }", - "status": "Received by edge", "deployed": "Deployed", "pending": "Pending", "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 pricing page 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.", "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.

List of missing rule chain(s):
{{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.

List of missing rule chain(s):
{{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": { "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", @@ -1097,7 +1139,6 @@ "type-debug-rule-chain": "Debug", "no-events-prompt": "No events found", "error": "Error", - "type-edge-event": "Downlink", "alarm": "Alarm", "event-time": "Event time", "server": "Server", diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json index 301e292de2..07acd04e3a 100644 --- a/ui/src/app/locale/locale.constant-es_ES.json +++ b/ui/src/app/locale/locale.constant-es_ES.json @@ -821,7 +821,6 @@ "deployed": "Desplegada", "pending": "Pendiente", "entity-id": "ID de entidad", - "entity-info": "Entity info", "event-action": "Información de la entidad", "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.",