Commit a0e74d72054393cc28bb34cd6ecca0b896798715

Authored by Artem Babak
1 parent 83c2758c

Edge Downlinks new tab implementation 2

  1 +/*
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +import $ from 'jquery';
  17 +import 'brace/ext/language_tools';
  18 +import 'brace/ext/searchbox';
  19 +import 'brace/mode/java';
  20 +import 'brace/theme/github';
  21 +import beautify from 'js-beautify';
  22 +
  23 +/* eslint-disable angular/angularelement */
  24 +
  25 +const js_beautify = beautify.js;
  26 +
  27 +/*@ngInject*/
  28 +export default function EdgeDownlinksContentDialogController($mdDialog, types, content, contentType, title, showingCallback) {
  29 +
  30 + var vm = this;
  31 +
  32 + showingCallback.onShowing = function(scope, element) {
  33 + updateEditorSize(element);
  34 + }
  35 +
  36 + vm.content = content;
  37 + vm.title = title;
  38 +
  39 + var mode;
  40 + if (contentType) {
  41 + mode = types.contentType[contentType].code;
  42 + if (contentType == types.contentType.JSON.value && vm.content) {
  43 + vm.content = js_beautify(vm.content, {indent_size: 4});
  44 + }
  45 + } else {
  46 + mode = 'java';
  47 + }
  48 +
  49 + vm.contentOptions = {
  50 + useWrapMode: false,
  51 + mode: mode,
  52 + showGutter: false,
  53 + showPrintMargin: false,
  54 + theme: 'github',
  55 + advanced: {
  56 + enableSnippets: false,
  57 + enableBasicAutocompletion: false,
  58 + enableLiveAutocompletion: false
  59 + },
  60 + onLoad: function (_ace) {
  61 + vm.editor = _ace;
  62 + }
  63 + };
  64 +
  65 + function updateEditorSize(element) {
  66 + var newHeight = 400;
  67 + var newWidth = 600;
  68 + if (vm.content && vm.content.length > 0) {
  69 + var lines = vm.content.split('\n');
  70 + newHeight = 16 * lines.length + 16;
  71 + var maxLineLength = 0;
  72 + for (var i = 0; i < lines.length; i++) {
  73 + var line = lines[i].replace(/\t/g, ' ').replace(/\n/g, '');
  74 + var lineLength = line.length;
  75 + maxLineLength = Math.max(maxLineLength, lineLength);
  76 + }
  77 + newWidth = 8 * maxLineLength + 16;
  78 + }
  79 + $('#tb-event-content', element).height(newHeight.toString() + "px")
  80 + .width(newWidth.toString() + "px");
  81 + vm.editor.resize();
  82 + }
  83 +
  84 + vm.close = close;
  85 +
  86 + function close () {
  87 + $mdDialog.hide();
  88 + }
  89 +
  90 +}
  91 +
  92 +/* eslint-enable angular/angularelement */
... ...
  1 +/*
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +/* eslint-disable import/no-unresolved, import/default */
  17 +
  18 +import edgeDownlinksHeaderTemplate from './event-header-edge-event.tpl.html'
  19 +
  20 +/* eslint-enable import/no-unresolved, import/default */
  21 +
  22 +/*@ngInject*/
  23 +export default function EventHeaderDirective2($compile, $templateCache, types) {
  24 +
  25 + var linker = function (scope, element, attrs) {
  26 +
  27 + var getTemplate = function(eventType) {
  28 + var template = '';
  29 + switch(eventType) {
  30 + case types.edgeDownlinks.value:
  31 + template = edgeDownlinksHeaderTemplate;
  32 + break;
  33 + }
  34 + return $templateCache.get(template);
  35 + }
  36 +
  37 + scope.loadTemplate = function() {
  38 + element.html(getTemplate(attrs.eventType));
  39 + $compile(element.contents())(scope);
  40 + }
  41 +
  42 + attrs.$observe('eventType', function() {
  43 + scope.loadTemplate();
  44 + });
  45 +
  46 + }
  47 +
  48 + return {
  49 + restrict: "A",
  50 + replace: false,
  51 + link: linker,
  52 + scope: false
  53 + };
  54 +}
... ...
  1 +/*
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +/* eslint-disable import/no-unresolved, import/default */
  17 +
  18 +import eventErrorDialogTemplate from './event-content-dialog.tpl.html';
  19 +
  20 +import edgeDownlinlsRowTemplate from './event-row-edge-event.tpl.html';
  21 +
  22 +/* eslint-enable import/no-unresolved, import/default */
  23 +
  24 +/*@ngInject*/
  25 +export default function EventRowDirective2($compile, $templateCache, $mdDialog, $document, $translate,
  26 + types, utils, toast, entityService, ruleChainService) {
  27 +
  28 + var linker = function (scope, element, attrs) {
  29 +
  30 + var getTemplate = function(eventType) {
  31 + var template = '';
  32 + switch(eventType) {
  33 + case types.edgeDownlinks.value:
  34 + template = edgeDownlinlsRowTemplate;
  35 + break;
  36 + }
  37 + return $templateCache.get(template);
  38 + }
  39 +
  40 + scope.loadTemplate = function() {
  41 + element.html(getTemplate(attrs.eventType));
  42 + $compile(element.contents())(scope);
  43 + }
  44 +
  45 + attrs.$observe('eventType', function() {
  46 + scope.loadTemplate();
  47 + });
  48 +
  49 + scope.types = types;
  50 +
  51 + scope.event = attrs.event;
  52 +
  53 + scope.showEdgeEntityContent = function($event, title, contentType) {
  54 + var onShowingCallback = {
  55 + onShowing: function(){}
  56 + }
  57 + if (!contentType) {
  58 + contentType = null;
  59 + }
  60 + var content = '';
  61 + switch(scope.event.type) {
  62 + case types.edgeEventType.relation:
  63 + content = angular.toJson(scope.event.body);
  64 + showDialog();
  65 + break;
  66 + case types.edgeEventType.ruleChainMetaData:
  67 + content = ruleChainService.getRuleChainMetaData(scope.event.entityId, {ignoreErrors: true}).then(
  68 + function success(info) {
  69 + showDialog();
  70 + return angular.toJson(info);
  71 + }, function fail() {
  72 + showError();
  73 + });
  74 + break;
  75 + default:
  76 + content = entityService.getEntity(scope.event.type, scope.event.entityId, {ignoreErrors: true}).then(
  77 + function success(info) {
  78 + showDialog();
  79 + return angular.toJson(info);
  80 + }, function fail() {
  81 + showError();
  82 + });
  83 + break;
  84 + }
  85 + function showDialog() {
  86 + $mdDialog.show({
  87 + controller: 'EventContentDialogController2',
  88 + controllerAs: 'vm',
  89 + templateUrl: eventErrorDialogTemplate,
  90 + locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},
  91 + parent: angular.element($document[0].body),
  92 + fullscreen: true,
  93 + targetEvent: $event,
  94 + multiple: true,
  95 + onShowing: function(scope, element) {
  96 + onShowingCallback.onShowing(scope, element);
  97 + }
  98 + });
  99 + }
  100 + function showError() {
  101 + toast.showError($translate.instant('edge.load-entity-error'));
  102 + }
  103 + }
  104 +
  105 + scope.checkEdgeEventType = function (type) {
  106 + return !(type === types.edgeEventType.widgetType ||
  107 + type === types.edgeEventType.adminSettings ||
  108 + type === types.edgeEventType.widgetsBundle );
  109 + }
  110 +
  111 + scope.checkTooltip = function($event) {
  112 + var el = $event.target;
  113 + var $el = angular.element(el);
  114 + if(el.offsetWidth < el.scrollWidth && !$el.attr('title')){
  115 + $el.attr('title', $el.text());
  116 + }
  117 + }
  118 +
  119 + $compile(element.contents())(scope);
  120 +
  121 + scope.updateStatus = function(eventCreatedTime) {
  122 + var status;
  123 + if (eventCreatedTime < scope.queueStartTs) {
  124 + status = $translate.instant(types.edgeEventStatus.DEPLOYED.name);
  125 + scope.statusColor = types.edgeEventStatus.DEPLOYED.color;
  126 + } else {
  127 + status = $translate.instant(types.edgeEventStatus.PENDING.name);
  128 + scope.statusColor = types.edgeEventStatus.PENDING.color;
  129 + }
  130 + return status;
  131 + }
  132 + }
  133 +
  134 + return {
  135 + restrict: "A",
  136 + replace: false,
  137 + link: linker,
  138 + scope: false
  139 + };
  140 +}
... ...
  1 +/*
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +import './event.scss';
  17 +
  18 +/* eslint-disable import/no-unresolved, import/default */
  19 +
  20 +import edgeDownlinksTableTemplate from './edge-downlinks-table.tpl.html';
  21 +
  22 +/* eslint-enable import/no-unresolved, import/default */
  23 +
  24 +/*@ngInject*/
  25 +export default function EdgeDownlinksDirective2($compile, $templateCache, $rootScope, $translate, types,
  26 + eventService, edgeService, attributeService) {
  27 +
  28 + var linker = function (scope, element) {
  29 +
  30 + var template = $templateCache.get(edgeDownlinksTableTemplate);
  31 +
  32 + element.html(template);
  33 +
  34 + scope.eventType = types.edgeDownlinks.value;
  35 +
  36 + var pageSize = 20;
  37 + var startTime = 0;
  38 + var endTime = 0;
  39 +
  40 + scope.timewindow = {
  41 + history: {
  42 + timewindowMs: 24 * 60 * 60 * 1000 // 1 day
  43 + }
  44 + }
  45 +
  46 + scope.topIndex = 0;
  47 +
  48 + scope.theEvents = {
  49 + getItemAtIndex: function (index) {
  50 + if (index > scope.events.data.length) {
  51 + scope.theEvents.fetchMoreItems_(index);
  52 + return null;
  53 + }
  54 + var item = scope.events.data[index];
  55 + if (item) {
  56 + item.indexNumber = index + 1;
  57 + }
  58 + return item;
  59 + },
  60 +
  61 + getLength: function () {
  62 + if (scope.events.hasNext) {
  63 + return scope.events.data.length + scope.events.nextPageLink.limit;
  64 + } else {
  65 + return scope.events.data.length;
  66 + }
  67 + },
  68 +
  69 + fetchMoreItems_: function () {
  70 + if (scope.events.hasNext && !scope.events.pending) {
  71 + if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) {
  72 + scope.loadEdgeInfo();
  73 + scope.events.pending = true;
  74 + edgeService.getEdgeDownlinks(scope.entityId, scope.events.nextPageLink).then(
  75 + function success(events) {
  76 + scope.events.data = scope.events.data.concat(prepareEdgeEventData(events.data));
  77 + scope.events.nextPageLink = events.nextPageLink;
  78 + scope.events.hasNext = events.hasNext;
  79 + if (scope.events.hasNext) {
  80 + scope.events.nextPageLink.limit = pageSize;
  81 + }
  82 + scope.events.pending = false;
  83 + },
  84 + function fail() {
  85 + scope.events.hasNext = false;
  86 + scope.events.pending = false;
  87 + });
  88 + } else {
  89 + scope.events.hasNext = false;
  90 + }
  91 + }
  92 + }
  93 + };
  94 +
  95 + scope.$watch("entityId", function(newVal, prevVal) {
  96 + if (newVal && !angular.equals(newVal, prevVal)) {
  97 + scope.resetFilter();
  98 + scope.reload();
  99 + }
  100 + });
  101 +
  102 + scope.$watch("timewindow", function(newVal, prevVal) {
  103 + if (newVal && !angular.equals(newVal, prevVal)) {
  104 + scope.reload();
  105 + }
  106 + }, true);
  107 +
  108 + scope.resetFilter = function() {
  109 + scope.timewindow = {
  110 + history: {
  111 + timewindowMs: 24 * 60 * 60 * 1000 // 1 day
  112 + }
  113 + };
  114 + }
  115 +
  116 + scope.updateTimeWindowRange = function() {
  117 + if (scope.timewindow.history.timewindowMs) {
  118 + var currentTime = (new Date).getTime();
  119 + startTime = currentTime - scope.timewindow.history.timewindowMs;
  120 + endTime = currentTime;
  121 + } else {
  122 + startTime = scope.timewindow.history.fixedTimewindow.startTimeMs;
  123 + endTime = scope.timewindow.history.fixedTimewindow.endTimeMs;
  124 + }
  125 + }
  126 +
  127 + scope.reload = function() {
  128 + scope.topIndex = 0;
  129 + scope.selected = [];
  130 + scope.updateTimeWindowRange();
  131 + scope.events = {
  132 + data: [],
  133 + nextPageLink: {
  134 + limit: pageSize,
  135 + startTime: startTime,
  136 + endTime: endTime
  137 + },
  138 + hasNext: true,
  139 + pending: false
  140 + };
  141 + scope.theEvents.getItemAtIndex(pageSize);
  142 + }
  143 +
  144 + scope.noData = function() {
  145 + return scope.events.data.length == 0 && !scope.events.hasNext;
  146 + }
  147 +
  148 + scope.hasData = function() {
  149 + return scope.events.data.length > 0;
  150 + }
  151 +
  152 + scope.loading = function() {
  153 + return $rootScope.loading;
  154 + }
  155 +
  156 + scope.hasScroll = function() {
  157 + var repeatContainer = scope.repeatContainer[0];
  158 + if (repeatContainer) {
  159 + var scrollElement = repeatContainer.children[0];
  160 + if (scrollElement) {
  161 + return scrollElement.scrollHeight > scrollElement.clientHeight;
  162 + }
  163 + }
  164 + return false;
  165 + }
  166 +
  167 + scope.subscriptionId = null;
  168 +
  169 + scope.loadEdgeInfo = function() {
  170 + attributeService.getEntityAttributesValues(
  171 + scope.entityType,
  172 + scope.entityId,
  173 + types.attributesScope.server.value,
  174 + types.edgeAttributeKeys.queueStartTs,
  175 + null).then(
  176 + function success(attributes) {
  177 + attributes.length > 0 ? scope.onEdgeAttributesUpdate(attributes) : scope.queueStartTs = 0;
  178 + });
  179 + scope.checkSubscription();
  180 + }
  181 +
  182 + scope.onEdgeAttributesUpdate = function(attributes) {
  183 + let edgeAttributes = attributes.reduce(function (map, attribute) {
  184 + map[attribute.key] = attribute;
  185 + return map;
  186 + }, {});
  187 + if (edgeAttributes.queueStartTs) {
  188 + scope.queueStartTs = edgeAttributes.queueStartTs.lastUpdateTs;
  189 + }
  190 + }
  191 +
  192 + scope.checkSubscription = function() {
  193 + var newSubscriptionId = null;
  194 + if (scope.entityId && scope.entityType && types.attributesScope.server.value) {
  195 + newSubscriptionId =
  196 + attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value);
  197 + }
  198 + if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
  199 + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
  200 + }
  201 + scope.subscriptionId = newSubscriptionId;
  202 + }
  203 +
  204 + scope.$on('$destroy', function () {
  205 + if (scope.subscriptionId) {
  206 + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
  207 + }
  208 + });
  209 +
  210 + scope.reload();
  211 +
  212 + $compile(element.contents())(scope);
  213 + }
  214 + function prepareEdgeEventData(data) {
  215 +
  216 + data.forEach(
  217 + edgeEvent => {
  218 + edgeEvent.edgeEventActionText = $translate.instant(types.edgeEventActionType[edgeEvent.action].name);
  219 + edgeEvent.edgeEventTypeText = $translate.instant(types.edgeEventTypeTranslations[edgeEvent.edgeId.entityType].name);
  220 + }
  221 + );
  222 + return data;
  223 + }
  224 +
  225 + return {
  226 + restrict: "E",
  227 + link: linker,
  228 + scope: {
  229 + entityType: '=',
  230 + entityId: '=',
  231 + tenantId: '='
  232 + }
  233 + };
  234 +}
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<md-content flex class="md-padding tb-absolute-fill" layout="column">
  19 + <section layout="row">
  20 + <tb-timewindow flex ng-model="timewindow" history-only as-button="true"></tb-timewindow>
  21 + <md-button ng-disabled="$root.loading"
  22 + class="md-icon-button" ng-click="reload()">
  23 + <md-icon>refresh</md-icon>
  24 + <md-tooltip md-direction="top">
  25 + {{ 'action.refresh' | translate }}
  26 + </md-tooltip>
  27 + </md-button>
  28 + </section>
  29 + <md-list flex layout="column" class="md-whiteframe-z1 tb-edge-downlinks-table">
  30 + <md-list class="tb-row tb-header" layout="row" layout-align="start center" tb-edge-downlinks-header event-type="{{eventType}}">
  31 + </md-list>
  32 + <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!$root.loading"
  33 + ng-show="$root.loading"></md-progress-linear>
  34 + <md-divider></md-divider>
  35 + <span translate layout-align="center center"
  36 + style="margin-top: 25px;"
  37 + class="tb-prompt" ng-show="noData()">edge.no-downlinks-prompt</span>
  38 + <md-virtual-repeat-container ng-show="hasData()" flex md-top-index="topIndex" tb-scope-element="repeatContainer">
  39 + <md-list-item md-virtual-repeat="event in theEvents" md-on-demand flex ng-style="hasScroll() ? {'margin-right':'-15px'} : {}">
  40 + <md-list class="tb-row" flex layout="row" layout-align="start center" tb-edge-downlinks-row event-type="{{eventType}}" event="{{event}}">
  41 + </md-list>
  42 + <md-divider flex></md-divider>
  43 + </md-list-item>
  44 + </md-virtual-repeat-container>
  45 + </md-list>
  46 +</md-content>
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<md-dialog aria-label="{{ vm.title | translate }}">
  19 + <md-toolbar>
  20 + <div class="md-toolbar-tools">
  21 + <h2 translate>{{ vm.title }}</h2>
  22 + <span flex></span>
  23 + <md-button class="md-icon-button" ng-click="vm.close()">
  24 + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>
  25 + </md-button>
  26 + </div>
  27 + </md-toolbar>
  28 + <md-dialog-content>
  29 + <div class="md-dialog-content">
  30 + <div flex id="tb-event-content" readonly
  31 + ui-ace="vm.contentOptions"
  32 + ng-model="vm.content">
  33 + </div>
  34 + </div>
  35 + </md-dialog-content>
  36 + <md-dialog-actions layout="row">
  37 + <span flex></span>
  38 + <md-button ng-disabled="$root.loading" ng-click="vm.close()" style="margin-right:20px;">{{ 'action.close' |
  39 + translate }}
  40 + </md-button>
  41 + </md-dialog-actions>
  42 +</md-dialog>
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div translate class="tb-cell" flex="20">event.event-time</div>
  19 +<div translate class="tb-cell" flex="10">event.event-type</div>
  20 +<div translate class="tb-cell" flex="15">edge.event-action</div>
  21 +<div translate class="tb-cell" flex="30">edge.entity-id</div>
  22 +<div translate class="tb-cell" flex="15">edge.status</div>
  23 +<div translate class="tb-cell" flex="10">edge.entity-info</div>
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="tb-cell" flex="20">{{ event.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}</div>
  19 +<div class="tb-cell" flex="10">{{ event.edgeEventTypeText }}</div>
  20 +<div class="tb-cell" flex="15">{{ event.edgeEventActionText }}</div>
  21 +<div class="tb-cell" flex="30">{{ event.entityId }}</div>
  22 +<div class="tb-cell" flex="15" ng-style="{'color': statusColor}">{{ updateStatus(event.createdTime) }}</div>
  23 +<div class="tb-cell" flex="10">
  24 + <md-button ng-if="checkEdgeEventType(event.type)" class="md-icon-button md-primary"
  25 + ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')"
  26 + aria-label="{{ 'action.view' | translate }}">
  27 + <md-tooltip md-direction="top">
  28 + {{ 'action.view' | translate }}
  29 + </md-tooltip>
  30 + <md-icon aria-label="{{ 'action.view' | translate }}"
  31 + class="material-icons">
  32 + more_horiz
  33 + </md-icon>
  34 + </md-button>
  35 +</div>
  36 +
  37 +
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +md-list.tb-event-table {
  17 + padding: 0;
  18 +
  19 + md-list-item {
  20 + padding: 0;
  21 + }
  22 +
  23 + .tb-row {
  24 + height: 48px;
  25 + padding: 0;
  26 + overflow: hidden;
  27 +
  28 + .tb-cell {
  29 + text-overflow: ellipsis;
  30 +
  31 + &.tb-scroll {
  32 + overflow-x: auto;
  33 + overflow-y: hidden;
  34 + white-space: nowrap;
  35 + }
  36 +
  37 + &.tb-nowrap {
  38 + white-space: nowrap;
  39 + }
  40 + }
  41 + }
  42 +
  43 + .tb-row:hover {
  44 + background-color: #eee;
  45 + }
  46 +
  47 + .tb-header:hover {
  48 + background: none;
  49 + }
  50 +
  51 + .tb-header {
  52 + .tb-cell {
  53 + font-size: 12px;
  54 + font-weight: 700;
  55 + color: rgba(0, 0, 0, .54);
  56 + white-space: nowrap;
  57 + background: none;
  58 + }
  59 + }
  60 +
  61 + .tb-cell {
  62 + &:first-child {
  63 + padding-left: 14px;
  64 + }
  65 +
  66 + &:last-child {
  67 + padding-right: 14px;
  68 + }
  69 + padding: 0 6px;
  70 + margin: auto 0;
  71 + overflow: hidden;
  72 + font-size: 13px;
  73 + color: rgba(0, 0, 0, .87);
  74 + text-align: left;
  75 + vertical-align: middle;
  76 +
  77 + .md-button {
  78 + padding: 0;
  79 + margin: 0;
  80 + }
  81 + }
  82 +
  83 + .tb-cell.tb-number {
  84 + text-align: right;
  85 + }
  86 +}
  87 +
  88 +.tb-edge-downlinks-table-2 {
  89 + @extend .tb-event-table;
  90 +}
  91 +
  92 +#tb-event-content {
  93 + width: 100%;
  94 + min-width: 400px;
  95 + height: 100%;
  96 + min-height: 50px;
  97 +}
... ...
... ... @@ -65,11 +65,18 @@
65 65 default-event-type="{{vm.types.eventType.error.value}}">
66 66 </tb-event-table>
67 67 </md-tab>
68   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.downlinks' | translate }}">
69   - <tb-edge-downlinks-table flex entity-type="vm.types.entityType.edge"
  68 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.edge' | translate }}">
  69 + <tb-edge-downlinks-table-old flex entity-type="vm.types.entityType.edge"
70 70 entity-id="vm.grid.operatingItem().id.id"
71 71 tenant-id="vm.grid.operatingItem().tenantId.id"
72 72 default-event-type="{{vm.types.edgeDownlinks.value}}">
  73 + </tb-edge-downlinks-table-old>
  74 + </md-tab>
  75 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.downlinks' | translate }}">
  76 + <tb-edge-downlinks-table flex entity-type="vm.types.entityType.edge"
  77 + entity-id="vm.grid.operatingItem().id.id"
  78 + tenant-id="vm.grid.operatingItem().tenantId.id"
  79 + default-event-type="{{vm.types.edgeDownlinks.value}}">
73 80 </tb-edge-downlinks-table>
74 81 </md-tab>
75 82 <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
... ...
... ... @@ -25,6 +25,10 @@ import AssignEdgeToCustomerController from './assign-to-customer.controller';
25 25 import AddEdgesToCustomerController from './add-edges-to-customer.controller';
26 26 import SetRootRuleChainToEdgesController from './set-root-rule-chain-to-edges.controller';
27 27 import EdgeDirective from './edge.directive';
  28 +import EdgeDownlinksContentDialogController from './downlinks/edge-downlinks-content-dialog.controller';
  29 +import EdgeDownlinksHeaderDirective from './downlinks/edge-downlinks-header.directive';
  30 +import EdgeDownlinksRowDirective from './downlinks/edge-downlinks-row.directive';
  31 +import EdgeDownlinksDirective from "./downlinks/edge-downlinks-table.directive";
28 32
29 33 export default angular.module('thingsboard.edge', [
30 34 uiRouter,
... ... @@ -39,5 +43,9 @@ export default angular.module('thingsboard.edge', [
39 43 .controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController)
40 44 .controller('AddEdgesToCustomerController', AddEdgesToCustomerController)
41 45 .controller('SetRootRuleChainToEdgesController', SetRootRuleChainToEdgesController)
  46 + .controller('EdgeDownlinksContentDialogController', EdgeDownlinksContentDialogController)
42 47 .directive('tbEdge', EdgeDirective)
  48 + .directive('tbEdgeDownlinksHeader', EdgeDownlinksHeaderDirective)
  49 + .directive('tbEdgeDownlinksRow', EdgeDownlinksRowDirective)
  50 + .directive('tbEdgeDownlinksTable', EdgeDownlinksDirective)
43 51 .name;
... ...
... ... @@ -26,7 +26,7 @@
26 26 </md-tooltip>
27 27 </md-button>
28 28 </section>
29   - <md-list flex layout="column" class="md-whiteframe-z1 tb-edge-downlinks-table">
  29 + <md-list flex layout="column" class="md-whiteframe-z1 tb-edge-downlinks-table-old">
30 30 <md-list class="tb-row tb-header" layout="row" layout-align="start center" tb-event-header event-type="{{eventType}}">
31 31 </md-list>
32 32 <md-progress-linear style="max-height: 0px;" md-mode="indeterminate" ng-disabled="!$root.loading"
... ...
... ... @@ -28,5 +28,5 @@ export default angular.module('thingsboard.event', [
28 28 .directive('tbEventHeader', EventHeaderDirective)
29 29 .directive('tbEventRow', EventRowDirective)
30 30 .directive('tbEventTable', EventTableDirective)
31   - .directive('tbEdgeDownlinksTable', EdgeDownlinksDirective)
  31 + .directive('tbEdgeDownlinksTableOld', EdgeDownlinksDirective)
32 32 .name;
... ...