9 changed files with 685 additions and 1 deletions
@ -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; |
||||
|
} |
||||
@ -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 */ |
||||
@ -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> |
||||
@ -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 |
||||
|
}; |
||||
|
} |
||||
@ -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 |
||||
|
}; |
||||
|
} |
||||
@ -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: '=' |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -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> |
||||
Loading…
Reference in new issue