Showing
11 changed files
with
421 additions
and
87 deletions
@@ -35,7 +35,7 @@ function EdgeService($http, $q, customerService) { | @@ -35,7 +35,7 @@ function EdgeService($http, $q, customerService) { | ||
35 | unassignEdgeFromCustomer: unassignEdgeFromCustomer, | 35 | unassignEdgeFromCustomer: unassignEdgeFromCustomer, |
36 | makeEdgePublic: makeEdgePublic, | 36 | makeEdgePublic: makeEdgePublic, |
37 | setRootRuleChain: setRootRuleChain, | 37 | setRootRuleChain: setRootRuleChain, |
38 | - getEdgeEvents: getEdgeEvents, | 38 | + getEdgeDownlinks: getEdgeDownlinks, |
39 | syncEdge: syncEdge, | 39 | syncEdge: syncEdge, |
40 | findMissingToRelatedRuleChains: findMissingToRelatedRuleChains | 40 | findMissingToRelatedRuleChains: findMissingToRelatedRuleChains |
41 | }; | 41 | }; |
@@ -276,7 +276,7 @@ function EdgeService($http, $q, customerService) { | @@ -276,7 +276,7 @@ function EdgeService($http, $q, customerService) { | ||
276 | return deferred.promise; | 276 | return deferred.promise; |
277 | } | 277 | } |
278 | 278 | ||
279 | - function getEdgeEvents(edgeId, pageLink) { | 279 | + function getEdgeDownlinks(edgeId, pageLink) { |
280 | var deferred = $q.defer(); | 280 | var deferred = $q.defer(); |
281 | var url = '/api/edge/' + edgeId + '/events' + '?limit=' + pageLink.limit; | 281 | var url = '/api/edge/' + edgeId + '/events' + '?limit=' + pageLink.limit; |
282 | if (angular.isDefined(pageLink.startTime) && pageLink.startTime != null) { | 282 | if (angular.isDefined(pageLink.startTime) && pageLink.startTime != null) { |
@@ -661,10 +661,6 @@ export default angular.module('thingsboard.types', []) | @@ -661,10 +661,6 @@ export default angular.module('thingsboard.types', []) | ||
661 | stats: { | 661 | stats: { |
662 | value: "STATS", | 662 | value: "STATS", |
663 | name: "event.type-stats" | 663 | name: "event.type-stats" |
664 | - }, | ||
665 | - edgeEvent: { | ||
666 | - value: "EDGE_EVENT", | ||
667 | - name: "event.type-edge-event" | ||
668 | } | 664 | } |
669 | }, | 665 | }, |
670 | debugEventType: { | 666 | debugEventType: { |
@@ -1197,6 +1193,14 @@ export default angular.module('thingsboard.types', []) | @@ -1197,6 +1193,14 @@ export default angular.module('thingsboard.types', []) | ||
1197 | "ADMIN_SETTINGS": { | 1193 | "ADMIN_SETTINGS": { |
1198 | name: "permission.resource.display-type.ADMIN_SETTINGS" | 1194 | name: "permission.resource.display-type.ADMIN_SETTINGS" |
1199 | } | 1195 | } |
1196 | + }, | ||
1197 | + edgeEvent: { | ||
1198 | + value: "EDGE_EVENT", | ||
1199 | + name: "edge.downlink" | ||
1200 | + }, | ||
1201 | + edgeDownlinks: { | ||
1202 | + value: "EDGE_DOWNLINKS", | ||
1203 | + name: "edge.downlinks" | ||
1200 | } | 1204 | } |
1201 | } | 1205 | } |
1202 | ).name; | 1206 | ).name; |
@@ -65,6 +65,13 @@ | @@ -65,6 +65,13 @@ | ||
65 | default-event-type="{{vm.types.eventType.error.value}}"> | 65 | default-event-type="{{vm.types.eventType.error.value}}"> |
66 | </tb-event-table> | 66 | </tb-event-table> |
67 | </md-tab> | 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" | ||
70 | + entity-id="vm.grid.operatingItem().id.id" | ||
71 | + tenant-id="vm.grid.operatingItem().tenantId.id" | ||
72 | + default-event-type="{{vm.types.edgeDownlinks.value}}"> | ||
73 | + </tb-edge-downlinks-table> | ||
74 | + </md-tab> | ||
68 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> | 75 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> |
69 | <tb-relation-table flex | 76 | <tb-relation-table flex |
70 | readonly="!('edge' | hasGenericPermission:'write')" | 77 | readonly="!('edge' | hasGenericPermission:'write')" |
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 EdgeDownlinksDirective($compile, $templateCache, $rootScope, $translate, types, | ||
26 | + eventService, edgeService, attributeService) { | ||
27 | + | ||
28 | + var linker = function (scope, element, attrs) { | ||
29 | + | ||
30 | + var template = $templateCache.get(edgeDownlinksTableTemplate); | ||
31 | + | ||
32 | + element.html(template); | ||
33 | + | ||
34 | + if (attrs.disabledEventTypes) { | ||
35 | + var disabledEventTypes = attrs.disabledEventTypes.split(','); | ||
36 | + scope.eventTypes = {}; | ||
37 | + for (var type in types.eventType) { | ||
38 | + var eventType = types.eventType[type]; | ||
39 | + var enabled = true; | ||
40 | + for (var i=0;i<disabledEventTypes.length;i++) { | ||
41 | + if (eventType.value === disabledEventTypes[i]) { | ||
42 | + enabled = false; | ||
43 | + break; | ||
44 | + } | ||
45 | + } | ||
46 | + if (enabled) { | ||
47 | + scope.eventTypes[type] = eventType; | ||
48 | + } | ||
49 | + } | ||
50 | + } else { | ||
51 | + scope.eventTypes = angular.copy(types.eventType); | ||
52 | + } | ||
53 | + | ||
54 | + if (attrs.debugEventTypes) { | ||
55 | + var debugEventTypes = attrs.debugEventTypes.split(','); | ||
56 | + for (i=0;i<debugEventTypes.length;i++) { | ||
57 | + for (type in types.debugEventType) { | ||
58 | + eventType = types.debugEventType[type]; | ||
59 | + if (eventType.value === debugEventTypes[i]) { | ||
60 | + scope.eventTypes[type] = eventType; | ||
61 | + } | ||
62 | + } | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + scope.eventType = attrs.defaultEventType; | ||
67 | + | ||
68 | + var pageSize = 20; | ||
69 | + var startTime = 0; | ||
70 | + var endTime = 0; | ||
71 | + | ||
72 | + scope.timewindow = { | ||
73 | + history: { | ||
74 | + timewindowMs: 24 * 60 * 60 * 1000 // 1 day | ||
75 | + } | ||
76 | + } | ||
77 | + | ||
78 | + scope.topIndex = 0; | ||
79 | + | ||
80 | + scope.theEvents = { | ||
81 | + getItemAtIndex: function (index) { | ||
82 | + if (index > scope.events.data.length) { | ||
83 | + scope.theEvents.fetchMoreItems_(index); | ||
84 | + return null; | ||
85 | + } | ||
86 | + var item = scope.events.data[index]; | ||
87 | + if (item) { | ||
88 | + item.indexNumber = index + 1; | ||
89 | + } | ||
90 | + return item; | ||
91 | + }, | ||
92 | + | ||
93 | + getLength: function () { | ||
94 | + if (scope.events.hasNext) { | ||
95 | + return scope.events.data.length + scope.events.nextPageLink.limit; | ||
96 | + } else { | ||
97 | + return scope.events.data.length; | ||
98 | + } | ||
99 | + }, | ||
100 | + | ||
101 | + fetchMoreItems_: function () { | ||
102 | + if (scope.events.hasNext && !scope.events.pending) { | ||
103 | + if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) { | ||
104 | + scope.loadEdgeInfo(); | ||
105 | + scope.events.pending = true; | ||
106 | + edgeService.getEdgeDownlinks(scope.entityId, scope.events.nextPageLink).then( | ||
107 | + function success(events) { | ||
108 | + scope.events.data = scope.events.data.concat(prepareEdgeEventData(events.data)); | ||
109 | + scope.events.nextPageLink = events.nextPageLink; | ||
110 | + scope.events.hasNext = events.hasNext; | ||
111 | + if (scope.events.hasNext) { | ||
112 | + scope.events.nextPageLink.limit = pageSize; | ||
113 | + } | ||
114 | + scope.events.pending = false; | ||
115 | + }, | ||
116 | + function fail() { | ||
117 | + scope.events.hasNext = false; | ||
118 | + scope.events.pending = false; | ||
119 | + }); | ||
120 | + } else { | ||
121 | + scope.events.hasNext = false; | ||
122 | + } | ||
123 | + } | ||
124 | + } | ||
125 | + }; | ||
126 | + | ||
127 | + scope.$watch("entityId", function(newVal, prevVal) { | ||
128 | + if (newVal && !angular.equals(newVal, prevVal)) { | ||
129 | + scope.resetFilter(); | ||
130 | + scope.reload(); | ||
131 | + } | ||
132 | + }); | ||
133 | + | ||
134 | + scope.$watch("eventType", function(newVal, prevVal) { | ||
135 | + if (newVal && !angular.equals(newVal, prevVal)) { | ||
136 | + scope.reload(); | ||
137 | + } | ||
138 | + }); | ||
139 | + | ||
140 | + scope.$watch("timewindow", function(newVal, prevVal) { | ||
141 | + if (newVal && !angular.equals(newVal, prevVal)) { | ||
142 | + scope.reload(); | ||
143 | + } | ||
144 | + }, true); | ||
145 | + | ||
146 | + scope.resetFilter = function() { | ||
147 | + scope.timewindow = { | ||
148 | + history: { | ||
149 | + timewindowMs: 24 * 60 * 60 * 1000 // 1 day | ||
150 | + } | ||
151 | + }; | ||
152 | + } | ||
153 | + | ||
154 | + scope.updateTimeWindowRange = function() { | ||
155 | + if (scope.timewindow.history.timewindowMs) { | ||
156 | + var currentTime = (new Date).getTime(); | ||
157 | + startTime = currentTime - scope.timewindow.history.timewindowMs; | ||
158 | + endTime = currentTime; | ||
159 | + } else { | ||
160 | + startTime = scope.timewindow.history.fixedTimewindow.startTimeMs; | ||
161 | + endTime = scope.timewindow.history.fixedTimewindow.endTimeMs; | ||
162 | + } | ||
163 | + } | ||
164 | + | ||
165 | + scope.reload = function() { | ||
166 | + scope.topIndex = 0; | ||
167 | + scope.selected = []; | ||
168 | + scope.updateTimeWindowRange(); | ||
169 | + scope.events = { | ||
170 | + data: [], | ||
171 | + nextPageLink: { | ||
172 | + limit: pageSize, | ||
173 | + startTime: startTime, | ||
174 | + endTime: endTime | ||
175 | + }, | ||
176 | + hasNext: true, | ||
177 | + pending: false | ||
178 | + }; | ||
179 | + scope.theEvents.getItemAtIndex(pageSize); | ||
180 | + } | ||
181 | + | ||
182 | + scope.noData = function() { | ||
183 | + return scope.events.data.length == 0 && !scope.events.hasNext; | ||
184 | + } | ||
185 | + | ||
186 | + scope.hasData = function() { | ||
187 | + return scope.events.data.length > 0; | ||
188 | + } | ||
189 | + | ||
190 | + scope.loading = function() { | ||
191 | + return $rootScope.loading; | ||
192 | + } | ||
193 | + | ||
194 | + scope.hasScroll = function() { | ||
195 | + var repeatContainer = scope.repeatContainer[0]; | ||
196 | + if (repeatContainer) { | ||
197 | + var scrollElement = repeatContainer.children[0]; | ||
198 | + if (scrollElement) { | ||
199 | + return scrollElement.scrollHeight > scrollElement.clientHeight; | ||
200 | + } | ||
201 | + } | ||
202 | + return false; | ||
203 | + } | ||
204 | + | ||
205 | + scope.subscriptionId = null; | ||
206 | + | ||
207 | + scope.loadEdgeInfo = function() { | ||
208 | + attributeService.getEntityAttributesValues( | ||
209 | + scope.entityType, | ||
210 | + scope.entityId, | ||
211 | + types.attributesScope.server.value, | ||
212 | + types.edgeAttributeKeys.queueStartTs, | ||
213 | + null).then( | ||
214 | + function success(attributes) { | ||
215 | + attributes.length > 0 ? scope.onEdgeAttributesUpdate(attributes) : scope.queueStartTs = 0; | ||
216 | + }); | ||
217 | + scope.checkSubscription(); | ||
218 | + } | ||
219 | + | ||
220 | + scope.onEdgeAttributesUpdate = function(attributes) { | ||
221 | + let edgeAttributes = attributes.reduce(function (map, attribute) { | ||
222 | + map[attribute.key] = attribute; | ||
223 | + return map; | ||
224 | + }, {}); | ||
225 | + if (edgeAttributes.queueStartTs) { | ||
226 | + scope.queueStartTs = edgeAttributes.queueStartTs.lastUpdateTs; | ||
227 | + } | ||
228 | + } | ||
229 | + | ||
230 | + scope.checkSubscription = function() { | ||
231 | + var newSubscriptionId = null; | ||
232 | + if (scope.entityId && scope.entityType && types.attributesScope.server.value) { | ||
233 | + newSubscriptionId = | ||
234 | + attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value); | ||
235 | + } | ||
236 | + if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) { | ||
237 | + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | ||
238 | + } | ||
239 | + scope.subscriptionId = newSubscriptionId; | ||
240 | + } | ||
241 | + | ||
242 | + scope.$on('$destroy', function () { | ||
243 | + if (scope.subscriptionId) { | ||
244 | + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | ||
245 | + } | ||
246 | + }); | ||
247 | + | ||
248 | + scope.reload(); | ||
249 | + | ||
250 | + $compile(element.contents())(scope); | ||
251 | + } | ||
252 | + function prepareEdgeEventData(data) { | ||
253 | + | ||
254 | + data.forEach( | ||
255 | + edgeEvent => { | ||
256 | + edgeEvent.edgeEventActionText = $translate.instant(types.edgeEventActionType[edgeEvent.action].name); | ||
257 | + edgeEvent.edgeEventTypeText = $translate.instant(types.edgeEventTypeTranslations[edgeEvent.edgeId.entityType].name); | ||
258 | + } | ||
259 | + ); | ||
260 | + return data; | ||
261 | + } | ||
262 | + | ||
263 | + return { | ||
264 | + restrict: "E", | ||
265 | + link: linker, | ||
266 | + scope: { | ||
267 | + entityType: '=', | ||
268 | + entityId: '=', | ||
269 | + tenantId: '=' | ||
270 | + } | ||
271 | + }; | ||
272 | +} |
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-event-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()">event.no-events-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-event-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> |
@@ -46,7 +46,7 @@ export default function EventHeaderDirective($compile, $templateCache, types) { | @@ -46,7 +46,7 @@ export default function EventHeaderDirective($compile, $templateCache, types) { | ||
46 | case types.debugEventType.debugRuleChain.value: | 46 | case types.debugEventType.debugRuleChain.value: |
47 | template = eventHeaderDebugRuleNodeTemplate; | 47 | template = eventHeaderDebugRuleNodeTemplate; |
48 | break; | 48 | break; |
49 | - case types.eventType.edgeEvent.value: | 49 | + case types.edgeDownlinks.value: |
50 | template = eventHeaderEdgeEventTemplate; | 50 | template = eventHeaderEdgeEventTemplate; |
51 | break; | 51 | break; |
52 | } | 52 | } |
@@ -49,7 +49,7 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | @@ -49,7 +49,7 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | ||
49 | case types.debugEventType.debugRuleChain.value: | 49 | case types.debugEventType.debugRuleChain.value: |
50 | template = eventRowDebugRuleNodeTemplate; | 50 | template = eventRowDebugRuleNodeTemplate; |
51 | break; | 51 | break; |
52 | - case types.eventType.edgeEvent.value: | 52 | + case types.edgeDownlinks.value: |
53 | template = eventRowEdgeEventTemplate; | 53 | template = eventRowEdgeEventTemplate; |
54 | break; | 54 | break; |
55 | } | 55 | } |
@@ -22,8 +22,7 @@ import eventTableTemplate from './event-table.tpl.html'; | @@ -22,8 +22,7 @@ import eventTableTemplate from './event-table.tpl.html'; | ||
22 | /* eslint-enable import/no-unresolved, import/default */ | 22 | /* eslint-enable import/no-unresolved, import/default */ |
23 | 23 | ||
24 | /*@ngInject*/ | 24 | /*@ngInject*/ |
25 | -export default function EventTableDirective($compile, $templateCache, $rootScope, $translate, types, | ||
26 | - eventService, edgeService, attributeService) { | 25 | +export default function EventTableDirective($compile, $templateCache, $rootScope, types, eventService) { |
27 | 26 | ||
28 | var linker = function (scope, element, attrs) { | 27 | var linker = function (scope, element, attrs) { |
29 | 28 | ||
@@ -31,16 +30,11 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -31,16 +30,11 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
31 | 30 | ||
32 | element.html(template); | 31 | element.html(template); |
33 | 32 | ||
34 | - scope.eventTypeScope = angular.copy(types.eventType); | ||
35 | - if (scope.entityType !== types.entityType.edge) { | ||
36 | - delete scope.eventTypeScope.edgeEvent; | ||
37 | - } | ||
38 | - | ||
39 | if (attrs.disabledEventTypes) { | 33 | if (attrs.disabledEventTypes) { |
40 | var disabledEventTypes = attrs.disabledEventTypes.split(','); | 34 | var disabledEventTypes = attrs.disabledEventTypes.split(','); |
41 | scope.eventTypes = {}; | 35 | scope.eventTypes = {}; |
42 | - for (var type in scope.eventTypeScope) { | ||
43 | - var eventType = scope.eventTypeScope[type]; | 36 | + for (var type in types.eventType) { |
37 | + var eventType = types.eventType[type]; | ||
44 | var enabled = true; | 38 | var enabled = true; |
45 | for (var i=0;i<disabledEventTypes.length;i++) { | 39 | for (var i=0;i<disabledEventTypes.length;i++) { |
46 | if (eventType.value === disabledEventTypes[i]) { | 40 | if (eventType.value === disabledEventTypes[i]) { |
@@ -53,7 +47,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -53,7 +47,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
53 | } | 47 | } |
54 | } | 48 | } |
55 | } else { | 49 | } else { |
56 | - scope.eventTypes = angular.copy(scope.eventTypeScope); | 50 | + scope.eventTypes = angular.copy(types.eventType); |
57 | } | 51 | } |
58 | 52 | ||
59 | if (attrs.debugEventTypes) { | 53 | if (attrs.debugEventTypes) { |
@@ -106,23 +100,13 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -106,23 +100,13 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
106 | fetchMoreItems_: function () { | 100 | fetchMoreItems_: function () { |
107 | if (scope.events.hasNext && !scope.events.pending) { | 101 | if (scope.events.hasNext && !scope.events.pending) { |
108 | if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) { | 102 | if (scope.entityType && scope.entityId && scope.eventType && scope.tenantId) { |
109 | - var promise = ''; | ||
110 | - if (scope.eventType !== types.eventType.edgeEvent.value) { | ||
111 | - promise = eventService.getEvents(scope.entityType, scope.entityId, | ||
112 | - scope.eventType, scope.tenantId, scope.events.nextPageLink); | ||
113 | - } else { | ||
114 | - promise = edgeService.getEdgeEvents(scope.entityId, scope.events.nextPageLink); | ||
115 | - scope.loadEdgeInfo(); | ||
116 | - } | 103 | + var promise = eventService.getEvents(scope.entityType, scope.entityId, |
104 | + scope.eventType, scope.tenantId, scope.events.nextPageLink); | ||
117 | if (promise) { | 105 | if (promise) { |
118 | scope.events.pending = true; | 106 | scope.events.pending = true; |
119 | promise.then( | 107 | promise.then( |
120 | function success(events) { | 108 | function success(events) { |
121 | - if (scope.eventType === types.eventType.edgeEvent.value) { | ||
122 | - scope.events.data = scope.events.data.concat(prepareEdgeEventData(events.data)); | ||
123 | - } else { | ||
124 | - scope.events.data = scope.events.data.concat(events.data); | ||
125 | - } | 109 | + scope.events.data = scope.events.data.concat(events.data); |
126 | scope.events.nextPageLink = events.nextPageLink; | 110 | scope.events.nextPageLink = events.nextPageLink; |
127 | scope.events.hasNext = events.hasNext; | 111 | scope.events.hasNext = events.hasNext; |
128 | if (scope.events.hasNext) { | 112 | if (scope.events.hasNext) { |
@@ -223,64 +207,10 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -223,64 +207,10 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
223 | return false; | 207 | return false; |
224 | } | 208 | } |
225 | 209 | ||
226 | - scope.subscriptionId = null; | ||
227 | - | ||
228 | - scope.loadEdgeInfo = function() { | ||
229 | - attributeService.getEntityAttributesValues( | ||
230 | - scope.entityType, | ||
231 | - scope.entityId, | ||
232 | - types.attributesScope.server.value, | ||
233 | - types.edgeAttributeKeys.queueStartTs, | ||
234 | - null).then( | ||
235 | - function success(attributes) { | ||
236 | - attributes.length > 0 ? scope.onEdgeAttributesUpdate(attributes) : scope.queueStartTs = 0; | ||
237 | - }); | ||
238 | - scope.checkSubscription(); | ||
239 | - } | ||
240 | - | ||
241 | - scope.onEdgeAttributesUpdate = function(attributes) { | ||
242 | - let edgeAttributes = attributes.reduce(function (map, attribute) { | ||
243 | - map[attribute.key] = attribute; | ||
244 | - return map; | ||
245 | - }, {}); | ||
246 | - if (edgeAttributes.queueStartTs) { | ||
247 | - scope.queueStartTs = edgeAttributes.queueStartTs.lastUpdateTs; | ||
248 | - } | ||
249 | - } | ||
250 | - | ||
251 | - scope.checkSubscription = function() { | ||
252 | - var newSubscriptionId = null; | ||
253 | - if (scope.entityId && scope.entityType && types.attributesScope.server.value) { | ||
254 | - newSubscriptionId = | ||
255 | - attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value); | ||
256 | - } | ||
257 | - if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) { | ||
258 | - attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | ||
259 | - } | ||
260 | - scope.subscriptionId = newSubscriptionId; | ||
261 | - } | ||
262 | - | ||
263 | - scope.$on('$destroy', function () { | ||
264 | - if (scope.subscriptionId) { | ||
265 | - attributeService.unsubscribeForEntityAttributes(scope.subscriptionId); | ||
266 | - } | ||
267 | - }); | ||
268 | - | ||
269 | scope.reload(); | 210 | scope.reload(); |
270 | 211 | ||
271 | $compile(element.contents())(scope); | 212 | $compile(element.contents())(scope); |
272 | } | 213 | } |
273 | - | ||
274 | - function prepareEdgeEventData(data) { | ||
275 | - data.forEach( | ||
276 | - edgeEvent => { | ||
277 | - edgeEvent.edgeEventActionText = $translate.instant(types.edgeEventActionType[edgeEvent.action].name); | ||
278 | - edgeEvent.edgeEventTypeText = $translate.instant(types.edgeEventTypeTranslations[edgeEvent.edgeId.entityType].name); | ||
279 | - } | ||
280 | - ); | ||
281 | - return data; | ||
282 | - } | ||
283 | - | ||
284 | return { | 214 | return { |
285 | restrict: "E", | 215 | restrict: "E", |
286 | link: linker, | 216 | link: linker, |
@@ -85,6 +85,78 @@ md-list.tb-event-table { | @@ -85,6 +85,78 @@ md-list.tb-event-table { | ||
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | +md-list.tb-edge-downlinks-table { | ||
89 | + padding: 0; | ||
90 | + | ||
91 | + md-list-item { | ||
92 | + padding: 0; | ||
93 | + } | ||
94 | + | ||
95 | + .tb-row { | ||
96 | + height: 48px; | ||
97 | + padding: 0; | ||
98 | + overflow: hidden; | ||
99 | + | ||
100 | + .tb-cell { | ||
101 | + text-overflow: ellipsis; | ||
102 | + | ||
103 | + &.tb-scroll { | ||
104 | + overflow-x: auto; | ||
105 | + overflow-y: hidden; | ||
106 | + white-space: nowrap; | ||
107 | + } | ||
108 | + | ||
109 | + &.tb-nowrap { | ||
110 | + white-space: nowrap; | ||
111 | + } | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + .tb-row:hover { | ||
116 | + background-color: #eee; | ||
117 | + } | ||
118 | + | ||
119 | + .tb-header:hover { | ||
120 | + background: none; | ||
121 | + } | ||
122 | + | ||
123 | + .tb-header { | ||
124 | + .tb-cell { | ||
125 | + font-size: 12px; | ||
126 | + font-weight: 700; | ||
127 | + color: rgba(0, 0, 0, .54); | ||
128 | + white-space: nowrap; | ||
129 | + background: none; | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + .tb-cell { | ||
134 | + &:first-child { | ||
135 | + padding-left: 14px; | ||
136 | + } | ||
137 | + | ||
138 | + &:last-child { | ||
139 | + padding-right: 14px; | ||
140 | + } | ||
141 | + padding: 0 6px; | ||
142 | + margin: auto 0; | ||
143 | + overflow: hidden; | ||
144 | + font-size: 13px; | ||
145 | + color: rgba(0, 0, 0, .87); | ||
146 | + text-align: left; | ||
147 | + vertical-align: middle; | ||
148 | + | ||
149 | + .md-button { | ||
150 | + padding: 0; | ||
151 | + margin: 0; | ||
152 | + } | ||
153 | + } | ||
154 | + | ||
155 | + .tb-cell.tb-number { | ||
156 | + text-align: right; | ||
157 | + } | ||
158 | +} | ||
159 | + | ||
88 | #tb-event-content { | 160 | #tb-event-content { |
89 | width: 100%; | 161 | width: 100%; |
90 | min-width: 400px; | 162 | min-width: 400px; |
@@ -19,6 +19,7 @@ import EventContentDialogController from './event-content-dialog.controller'; | @@ -19,6 +19,7 @@ import EventContentDialogController from './event-content-dialog.controller'; | ||
19 | import EventHeaderDirective from './event-header.directive'; | 19 | import EventHeaderDirective from './event-header.directive'; |
20 | import EventRowDirective from './event-row.directive'; | 20 | import EventRowDirective from './event-row.directive'; |
21 | import EventTableDirective from './event-table.directive'; | 21 | import EventTableDirective from './event-table.directive'; |
22 | +import EdgeDownlinksDirective from "./edge-downlinks-table.directive"; | ||
22 | 23 | ||
23 | export default angular.module('thingsboard.event', [ | 24 | export default angular.module('thingsboard.event', [ |
24 | thingsboardApiEvent | 25 | thingsboardApiEvent |
@@ -27,4 +28,5 @@ export default angular.module('thingsboard.event', [ | @@ -27,4 +28,5 @@ export default angular.module('thingsboard.event', [ | ||
27 | .directive('tbEventHeader', EventHeaderDirective) | 28 | .directive('tbEventHeader', EventHeaderDirective) |
28 | .directive('tbEventRow', EventRowDirective) | 29 | .directive('tbEventRow', EventRowDirective) |
29 | .directive('tbEventTable', EventTableDirective) | 30 | .directive('tbEventTable', EventTableDirective) |
31 | + .directive('tbEdgeDownlinksTable', EdgeDownlinksDirective) | ||
30 | .name; | 32 | .name; |
@@ -856,7 +856,9 @@ | @@ -856,7 +856,9 @@ | ||
856 | "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.", | 856 | "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.", |
857 | "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.", | 857 | "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.", |
858 | "missing-related-rule-chains-title": "Edge has missing related rule chain(s)", | 858 | "missing-related-rule-chains-title": "Edge has missing related rule chain(s)", |
859 | - "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}}" | 859 | + "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}}", |
860 | + "downlinks": "Downlinks", | ||
861 | + "no-downlinks-prompt": "No downlinks found" | ||
860 | }, | 862 | }, |
861 | "error": { | 863 | "error": { |
862 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", | 864 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", |
@@ -1097,7 +1099,6 @@ | @@ -1097,7 +1099,6 @@ | ||
1097 | "type-debug-rule-chain": "Debug", | 1099 | "type-debug-rule-chain": "Debug", |
1098 | "no-events-prompt": "No events found", | 1100 | "no-events-prompt": "No events found", |
1099 | "error": "Error", | 1101 | "error": "Error", |
1100 | - "type-edge-event": "Downlink", | ||
1101 | "alarm": "Alarm", | 1102 | "alarm": "Alarm", |
1102 | "event-time": "Event time", | 1103 | "event-time": "Event time", |
1103 | "server": "Server", | 1104 | "server": "Server", |