Showing
7 changed files
with
240 additions
and
17 deletions
@@ -21,6 +21,7 @@ import thingsboardLedLight from '../components/led-light.directive'; | @@ -21,6 +21,7 @@ import thingsboardLedLight from '../components/led-light.directive'; | ||
21 | import thingsboardTimeseriesTableWidget from '../widget/lib/timeseries-table-widget'; | 21 | import thingsboardTimeseriesTableWidget from '../widget/lib/timeseries-table-widget'; |
22 | import thingsboardAlarmsTableWidget from '../widget/lib/alarms-table-widget'; | 22 | import thingsboardAlarmsTableWidget from '../widget/lib/alarms-table-widget'; |
23 | import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget'; | 23 | import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget'; |
24 | +import thingsboardExtensionsTableWidget from '../widget/lib/extensions-table-widget'; | ||
24 | 25 | ||
25 | import thingsboardRpcWidgets from '../widget/lib/rpc'; | 26 | import thingsboardRpcWidgets from '../widget/lib/rpc'; |
26 | 27 | ||
@@ -42,7 +43,7 @@ import thingsboardTypes from '../common/types.constant'; | @@ -42,7 +43,7 @@ import thingsboardTypes from '../common/types.constant'; | ||
42 | import thingsboardUtils from '../common/utils.service'; | 43 | import thingsboardUtils from '../common/utils.service'; |
43 | 44 | ||
44 | export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, thingsboardTimeseriesTableWidget, | 45 | export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, thingsboardTimeseriesTableWidget, |
45 | - thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils]) | 46 | + thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, thingsboardExtensionsTableWidget, thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils]) |
46 | .factory('widgetService', WidgetService) | 47 | .factory('widgetService', WidgetService) |
47 | .name; | 48 | .name; |
48 | 49 |
@@ -34,7 +34,9 @@ export default function ExtensionTableDirective() { | @@ -34,7 +34,9 @@ export default function ExtensionTableDirective() { | ||
34 | scope: true, | 34 | scope: true, |
35 | bindToController: { | 35 | bindToController: { |
36 | entityId: '=', | 36 | entityId: '=', |
37 | - entityType: '@' | 37 | + entityType: '@', |
38 | + inWidget: '@?', | ||
39 | + ctx: '=?' | ||
38 | }, | 40 | }, |
39 | controller: ExtensionTableController, | 41 | controller: ExtensionTableController, |
40 | controllerAs: 'vm', | 42 | controllerAs: 'vm', |
@@ -70,7 +72,6 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | @@ -70,7 +72,6 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | ||
70 | vm.reloadExtensions = reloadExtensions; | 72 | vm.reloadExtensions = reloadExtensions; |
71 | vm.updateExtensions = updateExtensions; | 73 | vm.updateExtensions = updateExtensions; |
72 | 74 | ||
73 | - | ||
74 | $scope.$watch("vm.entityId", function(newVal) { | 75 | $scope.$watch("vm.entityId", function(newVal) { |
75 | if (newVal) { | 76 | if (newVal) { |
76 | if ($scope.subscriber) { | 77 | if ($scope.subscriber) { |
@@ -92,13 +93,50 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | @@ -92,13 +93,50 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | ||
92 | } | 93 | } |
93 | }); | 94 | }); |
94 | 95 | ||
96 | + $scope.$watch('vm.selectedExtensions.length', function (newLength) { | ||
97 | + var selectionMode = newLength ? true : false; | ||
98 | + if (vm.ctx) { | ||
99 | + if (selectionMode) { | ||
100 | + vm.ctx.hideTitlePanel = true; | ||
101 | + $scope.$emit("selectedExtensions", true); | ||
102 | + } else if (vm.query.search == null) { | ||
103 | + vm.ctx.hideTitlePanel = false; | ||
104 | + $scope.$emit("selectedExtensions", false); | ||
105 | + } | ||
106 | + } | ||
107 | + }); | ||
108 | + | ||
109 | + $scope.$on("showSearch", function($event, source) { | ||
110 | + if(source.entityId == vm.entityId) { | ||
111 | + enterFilterMode(); | ||
112 | + $scope.$emit("filterMode", true); | ||
113 | + } | ||
114 | + }); | ||
115 | + $scope.$on("refreshExtensions", function($event, source) { | ||
116 | + if(source.entityId == vm.entityId) { | ||
117 | + reloadExtensions(); | ||
118 | + } | ||
119 | + }); | ||
120 | + $scope.$on("addExtension", function($event, source) { | ||
121 | + if(source.entityId == vm.entityId) { | ||
122 | + addExtension(); | ||
123 | + } | ||
124 | + }); | ||
125 | + | ||
95 | function enterFilterMode() { | 126 | function enterFilterMode() { |
96 | vm.query.search = ''; | 127 | vm.query.search = ''; |
128 | + if(vm.inWidget) { | ||
129 | + vm.ctx.hideTitlePanel = true; | ||
130 | + } | ||
97 | } | 131 | } |
98 | 132 | ||
99 | function exitFilterMode() { | 133 | function exitFilterMode() { |
100 | vm.query.search = null; | 134 | vm.query.search = null; |
101 | updateExtensions(); | 135 | updateExtensions(); |
136 | + if(vm.inWidget) { | ||
137 | + vm.ctx.hideTitlePanel = false; | ||
138 | + $scope.$emit("filterMode", false); | ||
139 | + } | ||
102 | } | 140 | } |
103 | 141 | ||
104 | function onReorder() { | 142 | function onReorder() { |
@@ -256,8 +294,7 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | @@ -256,8 +294,7 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | ||
256 | vm.extensions = result.slice(startIndex, startIndex + vm.query.limit); | 294 | vm.extensions = result.slice(startIndex, startIndex + vm.query.limit); |
257 | 295 | ||
258 | vm.extensionsJSON = angular.toJson(vm.extensions); | 296 | vm.extensionsJSON = angular.toJson(vm.extensions); |
259 | - checkForSync() | ||
260 | - | 297 | + checkForSync(); |
261 | } | 298 | } |
262 | 299 | ||
263 | function subscribeForClientAttributes() { | 300 | function subscribeForClientAttributes() { |
@@ -320,7 +357,6 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | @@ -320,7 +357,6 @@ function ExtensionTableController($scope, $filter, $document, $translate, types, | ||
320 | d = d.getFullYear() +'/'+ addZero(d.getMonth()+1) +'/'+ addZero(d.getDate()) + ' ' + addZero(d.getHours()) + ':' + addZero(d.getMinutes()) +':'+ addZero(d.getSeconds()); | 357 | d = d.getFullYear() +'/'+ addZero(d.getMonth()+1) +'/'+ addZero(d.getDate()) + ' ' + addZero(d.getHours()) + ':' + addZero(d.getMinutes()) +':'+ addZero(d.getSeconds()); |
321 | return d; | 358 | return d; |
322 | 359 | ||
323 | - | ||
324 | function addZero(num) { | 360 | function addZero(num) { |
325 | if ((angular.isNumber(num) && num < 10) || (angular.isString(num) && num.length === 1)) { | 361 | if ((angular.isNumber(num) && num < 10) || (angular.isString(num) && num.length === 1)) { |
326 | num = '0' + num; | 362 | num = '0' + num; |
@@ -20,6 +20,18 @@ | @@ -20,6 +20,18 @@ | ||
20 | min-height: 0; | 20 | min-height: 0; |
21 | } | 21 | } |
22 | 22 | ||
23 | +.extension-table { | ||
24 | + .sync-widget { | ||
25 | + max-height: 90px; | ||
26 | + overflow: hidden; | ||
27 | + } | ||
28 | + .toolbar-widget { | ||
29 | + min-height: 39px; | ||
30 | + max-height: 39px; | ||
31 | + } | ||
32 | +} | ||
33 | + | ||
34 | + | ||
23 | .extension__syncStatus--black { | 35 | .extension__syncStatus--black { |
24 | color: #000000!important; | 36 | color: #000000!important; |
25 | } | 37 | } |
@@ -17,9 +17,9 @@ | @@ -17,9 +17,9 @@ | ||
17 | --> | 17 | --> |
18 | 18 | ||
19 | <md-content flex class="md-padding tb-absolute-fill tb-data-table extension-table" layout="column"> | 19 | <md-content flex class="md-padding tb-absolute-fill tb-data-table extension-table" layout="column"> |
20 | - <div layout="column" class="md-whiteframe-z1"> | ||
21 | - <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedExtensions.length | ||
22 | - && vm.query.search === null"> | 20 | + <div layout="column" class="md-whiteframe-z1" ng-class="{'tb-absolute-fill' : vm.inWidget}"> |
21 | + <md-toolbar ng-if="!vm.inWidget" class="md-table-toolbar md-default" ng-show="!vm.selectedExtensions.length | ||
22 | + && vm.query.search === null"> | ||
23 | <div class="md-toolbar-tools"> | 23 | <div class="md-toolbar-tools"> |
24 | <span translate>{{ 'extension.extensions' }}</span> | 24 | <span translate>{{ 'extension.extensions' }}</span> |
25 | <span flex></span> | 25 | <span flex></span> |
@@ -44,7 +44,7 @@ | @@ -44,7 +44,7 @@ | ||
44 | </div> | 44 | </div> |
45 | </md-toolbar> | 45 | </md-toolbar> |
46 | <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedExtensions.length | 46 | <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedExtensions.length |
47 | - && vm.query.search != null""> | 47 | + && vm.query.search != null" ng-class="{'toolbar-widget' : vm.inWidget}"> |
48 | <div class="md-toolbar-tools"> | 48 | <div class="md-toolbar-tools"> |
49 | <md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}"> | 49 | <md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}"> |
50 | <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon> | 50 | <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon> |
@@ -58,13 +58,13 @@ | @@ -58,13 +58,13 @@ | ||
58 | </md-input-container> | 58 | </md-input-container> |
59 | <md-button class="md-icon-button" aria-label="{{ 'action.back' | translate }}" ng-click="vm.exitFilterMode()"> | 59 | <md-button class="md-icon-button" aria-label="{{ 'action.back' | translate }}" ng-click="vm.exitFilterMode()"> |
60 | <md-icon aria-label="{{ 'action.close' | translate }}" class="material-icons">close</md-icon> | 60 | <md-icon aria-label="{{ 'action.close' | translate }}" class="material-icons">close</md-icon> |
61 | - <md-tooltip md-direction="top"> | 61 | + <md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}"> |
62 | {{ 'action.close' | translate }} | 62 | {{ 'action.close' | translate }} |
63 | </md-tooltip> | 63 | </md-tooltip> |
64 | </md-button> | 64 | </md-button> |
65 | </div> | 65 | </div> |
66 | </md-toolbar> | 66 | </md-toolbar> |
67 | - <md-toolbar class="md-table-toolbar alternate" ng-show="vm.selectedExtensions.length"> | 67 | + <md-toolbar class="md-table-toolbar alternate" ng-show="vm.selectedExtensions.length" ng-class="{'toolbar-widget' : vm.inWidget}"> |
68 | <div class="md-toolbar-tools"> | 68 | <div class="md-toolbar-tools"> |
69 | <span translate | 69 | <span translate |
70 | translate-values="{count: vm.selectedExtensions.length}" | 70 | translate-values="{count: vm.selectedExtensions.length}" |
@@ -72,14 +72,14 @@ | @@ -72,14 +72,14 @@ | ||
72 | <span flex></span> | 72 | <span flex></span> |
73 | <md-button class="md-icon-button" ng-click="vm.deleteExtensions($event)"> | 73 | <md-button class="md-icon-button" ng-click="vm.deleteExtensions($event)"> |
74 | <md-icon>delete</md-icon> | 74 | <md-icon>delete</md-icon> |
75 | - <md-tooltip md-direction="top"> | 75 | + <md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}"> |
76 | {{ 'action.delete' | translate }} | 76 | {{ 'action.delete' | translate }} |
77 | </md-tooltip> | 77 | </md-tooltip> |
78 | </md-button> | 78 | </md-button> |
79 | </div> | 79 | </div> |
80 | </md-toolbar> | 80 | </md-toolbar> |
81 | 81 | ||
82 | - <div class="md-padding" flex layout="row"> | 82 | + <div class="md-padding" flex layout="row" ng-class="{'sync-widget' : vm.inWidget}"> |
83 | <md-input-container flex="50" class="md-block"> | 83 | <md-input-container flex="50" class="md-block"> |
84 | <label translate>extension.sync.status</label> | 84 | <label translate>extension.sync.status</label> |
85 | <input ng-model="vm.syncStatus" | 85 | <input ng-model="vm.syncStatus" |
@@ -97,7 +97,7 @@ | @@ -97,7 +97,7 @@ | ||
97 | </md-input-container> | 97 | </md-input-container> |
98 | </div> | 98 | </div> |
99 | 99 | ||
100 | - <md-table-container> | 100 | + <md-table-container flex> |
101 | <table md-table md-row-select multiple="" ng-model="vm.selectedExtensions" md-progress="vm.extensionsDeferred.promise"> | 101 | <table md-table md-row-select multiple="" ng-model="vm.selectedExtensions" md-progress="vm.extensionsDeferred.promise"> |
102 | <thead md-head md-order="vm.query.order" md-on-reorder="vm.onReorder"> | 102 | <thead md-head md-order="vm.query.order" md-on-reorder="vm.onReorder"> |
103 | <tr md-row> | 103 | <tr md-row> |
@@ -117,7 +117,7 @@ | @@ -117,7 +117,7 @@ | ||
117 | {{ 'extension.edit' | translate }} | 117 | {{ 'extension.edit' | translate }} |
118 | </md-tooltip> | 118 | </md-tooltip> |
119 | </md-button> | 119 | </md-button> |
120 | - <md-button class="md-icon-button" aria-label="{{ 'action.delete' | translate }}" ng-click="vm.deleteExtension($event, extension)"> <!-- add click-function --> | 120 | + <md-button class="md-icon-button" aria-label="{{ 'action.delete' | translate }}" ng-click="vm.deleteExtension($event, extension)"> |
121 | <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons">delete</md-icon> | 121 | <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons">delete</md-icon> |
122 | <md-tooltip md-direction="top"> | 122 | <md-tooltip md-direction="top"> |
123 | {{ 'extension.delete' | translate }} | 123 | {{ 'extension.delete' | translate }} |
@@ -127,11 +127,12 @@ | @@ -127,11 +127,12 @@ | ||
127 | </tr> | 127 | </tr> |
128 | </tbody> | 128 | </tbody> |
129 | </table> | 129 | </table> |
130 | + <md-divider ng-if="vm.inWidget"></md-divider> | ||
130 | </md-table-container> | 131 | </md-table-container> |
131 | <md-table-pagination md-limit="vm.query.limit" md-limit-options="[5, 10, 15]" | 132 | <md-table-pagination md-limit="vm.query.limit" md-limit-options="[5, 10, 15]" |
132 | md-page="vm.query.page" md-total="{{vm.extensionsCount}}" | 133 | md-page="vm.query.page" md-total="{{vm.extensionsCount}}" |
133 | md-on-paginate="vm.onPaginate" md-page-select> | 134 | md-on-paginate="vm.onPaginate" md-page-select> |
134 | </md-table-pagination> | 135 | </md-table-pagination> |
135 | </div> | 136 | </div> |
136 | - <div></div> <!-- div for testing values --> | 137 | + |
137 | </md-content> | 138 | </md-content> |
1 | +/* | ||
2 | + * Copyright © 2016-2017 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 | + | ||
17 | +import './extensions-table-widget.scss'; | ||
18 | + | ||
19 | +/* eslint-disable import/no-unresolved, import/default */ | ||
20 | + | ||
21 | +import extensionsTableWidgetTemplate from './extensions-table-widget.tpl.html'; | ||
22 | + | ||
23 | +/* eslint-enable import/no-unresolved, import/default */ | ||
24 | + | ||
25 | +export default angular.module('thingsboard.widgets.extensionsTableWidget', []) | ||
26 | + .directive('tbExtensionsTableWidget', ExtensionsTableWidget) | ||
27 | + .name; | ||
28 | + | ||
29 | +/*@ngInject*/ | ||
30 | +function ExtensionsTableWidget() { | ||
31 | + return { | ||
32 | + restrict: "E", | ||
33 | + scope: true, | ||
34 | + bindToController: { | ||
35 | + ctx: '=' | ||
36 | + }, | ||
37 | + controller: ExtensionsTableWidgetController, | ||
38 | + controllerAs: 'vm', | ||
39 | + templateUrl: extensionsTableWidgetTemplate | ||
40 | + }; | ||
41 | +} | ||
42 | + | ||
43 | +/*@ngInject*/ | ||
44 | +function ExtensionsTableWidgetController($scope, $translate, utils) { | ||
45 | + var vm = this; | ||
46 | + | ||
47 | + vm.datasources = null; | ||
48 | + vm.tabsHidden = false; | ||
49 | + | ||
50 | + $scope.$watch('vm.ctx', function() { | ||
51 | + if (vm.ctx && vm.ctx.defaultSubscription) { | ||
52 | + vm.settings = vm.ctx.settings; | ||
53 | + vm.subscription = vm.ctx.defaultSubscription; | ||
54 | + vm.datasources = vm.subscription.datasources; | ||
55 | + initializeConfig(); | ||
56 | + updateDatasources(); | ||
57 | + } | ||
58 | + }); | ||
59 | + | ||
60 | + function initializeConfig() { | ||
61 | + | ||
62 | + if (vm.settings.extensionsTitle && vm.settings.extensionsTitle.length) { | ||
63 | + vm.extensionsTitle = utils.customTranslation(vm.settings.extensionsTitle, vm.settings.extensionsTitle); | ||
64 | + } else { | ||
65 | + vm.extensionsTitle = $translate.instant('extension.extensions'); | ||
66 | + } | ||
67 | + vm.ctx.widgetTitle = vm.extensionsTitle; | ||
68 | + | ||
69 | + vm.ctx.widgetActions = [vm.addAction, vm.searchAction, vm.refreshAction]; | ||
70 | + } | ||
71 | + | ||
72 | + function updateDatasources() { | ||
73 | + | ||
74 | + var datasource = vm.datasources[0]; | ||
75 | + vm.selectedSource = vm.datasources[0]; | ||
76 | + vm.ctx.widgetTitle = utils.createLabelFromDatasource(datasource, vm.extensionsTitle); | ||
77 | + } | ||
78 | + | ||
79 | + vm.changeSelectedSource = function(source) { | ||
80 | + vm.selectedSource = source; | ||
81 | + } | ||
82 | + | ||
83 | + vm.searchAction = { | ||
84 | + name: "action.search", | ||
85 | + show: true, | ||
86 | + onAction: function() { | ||
87 | + $scope.$broadcast("showSearch", vm.selectedSource); | ||
88 | + }, | ||
89 | + icon: "search" | ||
90 | + }; | ||
91 | + | ||
92 | + vm.refreshAction = { | ||
93 | + name: "action.refresh", | ||
94 | + show: true, | ||
95 | + onAction: function() { | ||
96 | + $scope.$broadcast("refreshExtensions", vm.selectedSource); | ||
97 | + }, | ||
98 | + icon: "refresh" | ||
99 | + } | ||
100 | + | ||
101 | + vm.addAction = { | ||
102 | + name: "action.add", | ||
103 | + show: true, | ||
104 | + onAction: function() { | ||
105 | + $scope.$broadcast("addExtension", vm.selectedSource); | ||
106 | + }, | ||
107 | + icon: "add" | ||
108 | + } | ||
109 | + | ||
110 | + $scope.$on("filterMode", function($event, mode) { | ||
111 | + vm.tabsHidden = mode; | ||
112 | + }); | ||
113 | + | ||
114 | + $scope.$on("selectedExtensions", function($event, mode) { | ||
115 | + vm.tabsHidden = mode; | ||
116 | + }); | ||
117 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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 | + | ||
17 | +tb-extension-table { | ||
18 | + md-content { | ||
19 | + background-color: #fff; | ||
20 | + } | ||
21 | +} | ||
22 | +md-tabs.hide-tabs-menu { | ||
23 | + md-tabs-wrapper { | ||
24 | + display: none; | ||
25 | + } | ||
26 | + md-tabs-content-wrapper { | ||
27 | + top: 0 !important; | ||
28 | + } | ||
29 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2017 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-tabs id="tabs" md-border-bottom flex class="tb-absolute-fill" ng-class="{'hide-tabs-menu': vm.datasources.length == 1 || vm.tabsHidden}"> | ||
19 | + <md-tab ng-repeat="source in vm.datasources" label="{{ source.name }}" md-on-select="vm.changeSelectedSource(source)"> | ||
20 | + <tb-extension-table flex | ||
21 | + entity-id="source.entityId" | ||
22 | + entity-type="{{source.entityType}}" | ||
23 | + in-widget="true" | ||
24 | + ctx="vm.ctx"> | ||
25 | + </tb-extension-table> | ||
26 | + </md-tab> | ||
27 | +</md-tabs> |