Commit 2583cbed40eb0598581cb7fe28585ed9a8292ea4

Authored by Sergey Tarnavskiy
1 parent 32ece471

add extensions-widget

@@ -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>