Commit 69a0b74c6b066a37f480b27db1e9b48d9d264c94

Authored by Igor Kulikov
1 parent 8a37cf0d

TB-63: Improve alarms widget. Introduce auto-fill height setting for dashboard layout.

... ... @@ -31,7 +31,7 @@
31 31 on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)"
32 32 on-delete-asset="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-asset>
33 33 </md-tab>
34   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}">
  34 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
35 35 <tb-attribute-table flex
36 36 entity-id="vm.grid.operatingItem().id.id"
37 37 entity-type="{{vm.types.entityType.asset}}"
... ... @@ -39,7 +39,7 @@
39 39 default-attribute-scope="{{vm.types.attributesScope.server.value}}">
40 40 </tb-attribute-table>
41 41 </md-tab>
42   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}">
  42 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
43 43 <tb-attribute-table flex
44 44 entity-id="vm.grid.operatingItem().id.id"
45 45 entity-type="{{vm.types.entityType.asset}}"
... ... @@ -48,19 +48,19 @@
48 48 disable-attribute-scope-selection="true">
49 49 </tb-attribute-table>
50 50 </md-tab>
51   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
  51 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
52 52 <tb-alarm-table flex entity-type="vm.types.entityType.asset"
53 53 entity-id="vm.grid.operatingItem().id.id">
54 54 </tb-alarm-table>
55 55 </md-tab>
56   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'asset.events' | translate }}">
  56 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'asset.events' | translate }}">
57 57 <tb-event-table flex entity-type="vm.types.entityType.asset"
58 58 entity-id="vm.grid.operatingItem().id.id"
59 59 tenant-id="vm.grid.operatingItem().tenantId.id"
60 60 default-event-type="{{vm.types.eventType.error.value}}">
61 61 </tb-event-table>
62 62 </md-tab>
63   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
  63 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
64 64 <tb-relation-table flex
65 65 entity-id="vm.grid.operatingItem().id.id"
66 66 entity-type="{{vm.types.entityType.asset}}">
... ...
... ... @@ -394,7 +394,6 @@ export default angular.module('thingsboard.types', [])
394 394 cards: "cards"
395 395 },
396 396 translate: {
397   - dashboardStatePrefix: "dashboardState.state.",
398 397 customTranslationsPrefix: "custom."
399 398 }
400 399 }
... ...
... ... @@ -135,7 +135,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, types) {
135 135 isLocalUrl: isLocalUrl,
136 136 validateDatasources: validateDatasources,
137 137 createKey: createKey,
138   - createLabelFromDatasource: createLabelFromDatasource
  138 + createLabelFromDatasource: createLabelFromDatasource,
  139 + insertVariable: insertVariable
139 140 }
140 141
141 142 return service;
... ... @@ -407,4 +408,18 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, types) {
407 408 return label;
408 409 }
409 410
  411 + function insertVariable(pattern, name, value) {
  412 + var result = angular.copy(pattern);
  413 + var match = varsRegex.exec(pattern);
  414 + while (match !== null) {
  415 + var variable = match[0];
  416 + var variableName = match[1];
  417 + if (variableName === name) {
  418 + result = result.split(variable).join(value);
  419 + }
  420 + match = varsRegex.exec(pattern);
  421 + }
  422 + return result;
  423 + }
  424 +
410 425 }
... ...
... ... @@ -58,6 +58,7 @@ function Dashboard() {
58 58 columns: '=',
59 59 margins: '=',
60 60 isEdit: '=',
  61 + autofillHeight: '=',
61 62 isMobile: '=',
62 63 isMobileDisabled: '=?',
63 64 isEditActionEnabled: '=',
... ... @@ -102,6 +103,8 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
102 103
103 104 vm.isMobileDisabled = angular.isDefined(vm.isMobileDisabled) ? vm.isMobileDisabled : false;
104 105
  106 + vm.isMobileSize = false;
  107 +
105 108 if (!('dashboardTimewindow' in vm)) {
106 109 vm.dashboardTimewindow = timeService.defaultTimewindow();
107 110 }
... ... @@ -178,6 +181,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
178 181 vm.widgetPadding = widgetPadding;
179 182 vm.showWidgetTitle = showWidgetTitle;
180 183 vm.showWidgetTitlePanel = showWidgetTitlePanel;
  184 + vm.showWidgetActions = showWidgetActions;
181 185 vm.widgetTitleStyle = widgetTitleStyle;
182 186 vm.widgetTitle = widgetTitle;
183 187 vm.widgetActions = widgetActions;
... ... @@ -271,12 +275,15 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
271 275
272 276 function updateMobileOpts() {
273 277 var isMobileDisabled = vm.isMobileDisabled === true;
274   - var isMobile = vm.isMobile === true && !isMobileDisabled;
  278 + var isMobile = vm.isMobile === true && !isMobileDisabled || vm.autofillHeight;
275 279 var mobileBreakPoint = isMobileDisabled ? 0 : (isMobile ? 20000 : 960);
  280 +
276 281 if (!isMobile && !isMobileDisabled) {
277 282 isMobile = !$mdMedia('gt-sm');
278 283 }
279   - var rowHeight = isMobile ? 70 : 'match';
  284 +
  285 + var rowHeight = detectRowSize(isMobile);
  286 +
280 287 if (vm.gridsterOpts.isMobile != isMobile) {
281 288 vm.gridsterOpts.isMobile = isMobile;
282 289 vm.gridsterOpts.mobileModeEnabled = isMobile;
... ... @@ -287,6 +294,17 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
287 294 if (vm.gridsterOpts.rowHeight != rowHeight) {
288 295 vm.gridsterOpts.rowHeight = rowHeight;
289 296 }
  297 +
  298 + vm.isMobileSize = checkIsMobileSize();
  299 + }
  300 +
  301 + function checkIsMobileSize() {
  302 + var isMobileDisabled = vm.isMobileDisabled === true;
  303 + var isMobileSize = vm.isMobile === true && !isMobileDisabled;
  304 + if (!isMobileSize && !isMobileDisabled) {
  305 + isMobileSize = !$mdMedia('gt-sm');
  306 + }
  307 + return isMobileSize;
290 308 }
291 309
292 310 $scope.$watch(function() { return $mdMedia('gt-sm'); }, function() {
... ... @@ -297,6 +315,34 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
297 315 updateMobileOpts();
298 316 });
299 317
  318 + $scope.$watch('vm.autofillHeight', function () {
  319 + if (vm.autofillHeight) {
  320 + //if (gridsterParent.height()) {
  321 + // updateMobileOpts();
  322 + //} else {
  323 + if ($scope.parentHeighWatcher) {
  324 + $scope.parentHeighWatcher();
  325 + }
  326 + if (gridsterParent.height()) {
  327 + updateMobileOpts();
  328 + }
  329 + $scope.parentHeighWatcher = $scope.$watch(function() { return gridsterParent.height(); },
  330 + function(newHeight) {
  331 + if (newHeight) {
  332 + updateMobileOpts();
  333 + }
  334 + }
  335 + );
  336 + } else {
  337 + if ($scope.parentHeighWatcher) {
  338 + $scope.parentHeighWatcher();
  339 + $scope.parentHeighWatcher = null;
  340 + }
  341 +
  342 + updateMobileOpts();
  343 + }
  344 + });
  345 +
300 346 $scope.$watch('vm.isMobileDisabled', function () {
301 347 updateMobileOpts();
302 348 });
... ... @@ -333,6 +379,12 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
333 379 $scope.$broadcast('toggleDashboardEditMode', vm.isEdit);
334 380 });
335 381
  382 + $scope.$watch('vm.isMobileSize', function (newVal, prevVal) {
  383 + if (!angular.equals(newVal, prevVal)) {
  384 + $scope.$broadcast('mobileModeChanged', vm.isMobileSize);
  385 + }
  386 + });
  387 +
336 388 $scope.$on('gridster-resized', function (event, sizes, theGridster) {
337 389 if (checkIsLocalGridsterElement(theGridster)) {
338 390 vm.gridster = theGridster;
... ... @@ -345,13 +397,12 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
345 397 $scope.$on('gridster-mobile-changed', function (event, theGridster) {
346 398 if (checkIsLocalGridsterElement(theGridster)) {
347 399 vm.gridster = theGridster;
348   - var rowHeight = vm.gridster.isMobile ? 70 : 'match';
  400 + var rowHeight = detectRowSize(vm.gridster.isMobile);
349 401 if (vm.gridsterOpts.rowHeight != rowHeight) {
350 402 vm.gridsterOpts.rowHeight = rowHeight;
351 403 updateGridsterParams();
352 404 }
353   -
354   - $scope.$broadcast('mobileModeChanged', vm.gridster.isMobile);
  405 + vm.isMobileSize = checkIsMobileSize();
355 406
356 407 //TODO: widgets visibility
357 408 /*$timeout(function () {
... ... @@ -360,6 +411,21 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
360 411 }
361 412 });
362 413
  414 + function detectRowSize(isMobile) {
  415 + var rowHeight = isMobile ? 70 : 'match';
  416 + if (vm.autofillHeight) {
  417 + var viewportHeight = gridsterParent.height();
  418 + var totalRows = 0;
  419 + for (var i = 0; i < vm.widgets.length; i++) {
  420 + var w = vm.widgets[i];
  421 + var sizeY = widgetSizeY(w);
  422 + totalRows += sizeY;
  423 + }
  424 + rowHeight = (viewportHeight - (vm.gridsterOpts.margins[1])) / totalRows;
  425 + }
  426 + return rowHeight;
  427 + }
  428 +
363 429 function widgetOrder(widget) {
364 430 var order;
365 431 if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
... ... @@ -650,7 +716,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
650 716 }
651 717
652 718 function widgetSizeY(widget) {
653   - if (vm.gridsterOpts.isMobile) {
  719 + if (vm.gridsterOpts.isMobile && !vm.autofillHeight) {
654 720 var mobileHeight;
655 721 if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
656 722 mobileHeight = vm.widgetLayouts[widget.id].mobileHeight;
... ... @@ -673,7 +739,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
673 739 }
674 740
675 741 function setWidgetSizeY(widget, sizeY) {
676   - if (!vm.gridsterOpts.isMobile) {
  742 + if (!vm.gridsterOpts.isMobile && !vm.autofillHeight) {
677 743 if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
678 744 vm.widgetLayouts[widget.id].sizeY = sizeY;
679 745 } else {
... ... @@ -759,6 +825,15 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
759 825 }
760 826 }
761 827
  828 + function showWidgetActions(widget) {
  829 + var ctx = widgetContext(widget);
  830 + if (ctx && ctx.hideTitlePanel) {
  831 + return false;
  832 + } else {
  833 + return true;
  834 + }
  835 + }
  836 +
762 837 function widgetTitleStyle(widget) {
763 838 if (angular.isDefined(widget.config.titleStyle)) {
764 839 return widget.config.titleStyle;
... ...
... ... @@ -23,7 +23,7 @@
23 23 </md-content>
24 24 <md-menu md-position-mode="target target" tb-mousepoint-menu>
25 25 <md-content id="gridster-parent" class="tb-dashboard-content" flex layout-wrap ng-click="" tb-contextmenu="vm.openDashboardContextMenu($event, $mdOpenMousepointMenu)">
26   - <div ng-class="vm.dashboardClass" id="gridster-background" style="height: auto; min-height: 100%;">
  26 + <div ng-class="vm.dashboardClass" id="gridster-background" style="height: auto; min-height: 100%; display: inline;">
27 27 <div id="gridster-child" gridster="vm.gridsterOpts">
28 28 <ul>
29 29 <li gridster-item="vm.widgetItemMap" class="tb-noselect" ng-repeat="widget in vm.widgets">
... ... @@ -50,7 +50,7 @@
50 50 <span ng-show="vm.showWidgetTitle(widget)" ng-style="vm.widgetTitleStyle(widget)" class="md-subhead">{{vm.widgetTitle(widget)}}</span>
51 51 <tb-timewindow aggregation="{{vm.hasAggregation(widget)}}" ng-if="vm.hasTimewindow(widget)" ng-model="widget.config.timewindow"></tb-timewindow>
52 52 </div>
53   - <div class="tb-widget-actions" layout="row" layout-align="start center" ng-show="vm.showWidgetTitlePanel(widget)" tb-mousedown="$event.stopPropagation()">
  53 + <div class="tb-widget-actions" layout="row" layout-align="start center" ng-show="vm.showWidgetActions(widget)" tb-mousedown="$event.stopPropagation()">
54 54 <md-button ng-repeat="action in vm.widgetActions(widget)"
55 55 aria-label="{{ action.name | translate }}"
56 56 ng-show="!vm.isEdit && action.show"
... ... @@ -103,6 +103,7 @@
103 103 aliasController: vm.aliasController,
104 104 stateController: vm.stateController,
105 105 isEdit: vm.isEdit,
  106 + isMobile: vm.isMobileSize,
106 107 stDiff: vm.stDiff,
107 108 dashboardTimewindow: vm.dashboardTimewindow,
108 109 dashboardTimewindowApi: vm.dashboardTimewindowApi }">
... ...
... ... @@ -124,7 +124,7 @@ function Grid() {
124 124 }
125 125
126 126 /*@ngInject*/
127   -function GridController($scope, $state, $mdDialog, $document, $q, $timeout, $translate, $mdMedia, $templateCache) {
  127 +function GridController($scope, $state, $mdDialog, $document, $q, $timeout, $translate, $mdMedia, $templateCache, $window) {
128 128
129 129 var vm = this;
130 130
... ... @@ -155,6 +155,7 @@ function GridController($scope, $state, $mdDialog, $document, $q, $timeout, $tra
155 155 vm.refreshList = refreshList;
156 156 vm.saveItem = saveItem;
157 157 vm.toggleItemSelection = toggleItemSelection;
  158 + vm.triggerResize = triggerResize;
158 159
159 160 $scope.$watch(function () {
160 161 return $mdMedia('xs') || $mdMedia('sm');
... ... @@ -600,6 +601,11 @@ function GridController($scope, $state, $mdDialog, $document, $q, $timeout, $tra
600 601 }
601 602 }
602 603
  604 + function triggerResize() {
  605 + var w = angular.element($window);
  606 + w.triggerHandler('resize');
  607 + }
  608 +
603 609 function moveToTop() {
604 610 moveToIndex(0, true);
605 611 }
... ...
... ... @@ -21,7 +21,7 @@ import Subscription from '../api/subscription';
21 21
22 22 /*@ngInject*/
23 23 export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, $compile, tbRaf, types, utils, timeService,
24   - datasourceService, alarmService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow,
  24 + datasourceService, alarmService, entityService, deviceService, visibleRect, isEdit, isMobile, stDiff, dashboardTimewindow,
25 25 dashboardTimewindowApi, widget, aliasController, stateController, widgetInfo, widgetType) {
26 26
27 27 var vm = this;
... ... @@ -50,7 +50,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
50 50 height: 0,
51 51 hideTitlePanel: false,
52 52 isEdit: isEdit,
53   - isMobile: false,
  53 + isMobile: isMobile,
54 54 widgetConfig: widget.config,
55 55 settings: widget.config.settings,
56 56 units: widget.config.units || '',
... ... @@ -618,7 +618,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
618 618
619 619 function gridsterItemInitialized(item) {
620 620 if (item && item.gridster) {
621   - widgetContext.isMobile = item.gridster.isMobile;
622 621 gridsterItemInited = true;
623 622 onInit();
624 623 // gridsterItemElement = $(item.$element);
... ...
... ... @@ -31,7 +31,7 @@
31 31 on-manage-dashboards="vm.openCustomerDashboards(event, vm.grid.detailsConfig.currentItem)"
32 32 on-delete-customer="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-customer>
33 33 </md-tab>
34   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}">
  34 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
35 35 <tb-attribute-table flex
36 36 entity-id="vm.grid.operatingItem().id.id"
37 37 entity-type="{{vm.types.entityType.customer}}"
... ... @@ -39,7 +39,7 @@
39 39 default-attribute-scope="{{vm.types.attributesScope.server.value}}">
40 40 </tb-attribute-table>
41 41 </md-tab>
42   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}">
  42 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
43 43 <tb-attribute-table flex
44 44 entity-id="vm.grid.operatingItem().id.id"
45 45 entity-type="{{vm.types.entityType.customer}}"
... ... @@ -48,19 +48,19 @@
48 48 disable-attribute-scope-selection="true">
49 49 </tb-attribute-table>
50 50 </md-tab>
51   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
  51 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
52 52 <tb-alarm-table flex entity-type="vm.types.entityType.customer"
53 53 entity-id="vm.grid.operatingItem().id.id">
54 54 </tb-alarm-table>
55 55 </md-tab>
56   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'customer.events' | translate }}">
  56 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'customer.events' | translate }}">
57 57 <tb-event-table flex entity-type="vm.types.entityType.customer"
58 58 entity-id="vm.grid.operatingItem().id.id"
59 59 tenant-id="vm.grid.operatingItem().tenantId.id"
60 60 default-event-type="{{vm.types.eventType.error.value}}">
61 61 </tb-event-table>
62 62 </md-tab>
63   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
  63 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
64 64 <tb-relation-table flex
65 65 entity-id="vm.grid.operatingItem().id.id"
66 66 entity-type="{{vm.types.entityType.customer}}">
... ...
... ... @@ -68,6 +68,7 @@ export default function DashboardSettingsController($scope, $mdDialog, statesCon
68 68 vm.gridSettings.color = vm.gridSettings.color || 'rgba(0,0,0,0.870588)';
69 69 vm.gridSettings.columns = vm.gridSettings.columns || 24;
70 70 vm.gridSettings.margins = vm.gridSettings.margins || [10, 10];
  71 + vm.gridSettings.autoFillHeight = angular.isDefined(vm.gridSettings.autoFillHeight) ? vm.gridSettings.autoFillHeight : false;
71 72 vm.hMargin = vm.gridSettings.margins[0];
72 73 vm.vMargin = vm.gridSettings.margins[1];
73 74 vm.gridSettings.backgroundSizeMode = vm.gridSettings.backgroundSizeMode || '100%';
... ...
... ... @@ -121,6 +121,9 @@
121 121 </div>
122 122 </md-input-container>
123 123 </div>
  124 + <md-checkbox flex aria-label="{{ 'dashboard.autofill-height' | translate }}"
  125 + ng-model="vm.gridSettings.autoFillHeight">{{ 'dashboard.autofill-height' | translate }}
  126 + </md-checkbox>
124 127 <div flex
125 128 ng-required="false"
126 129 md-color-picker
... ...
... ... @@ -49,6 +49,7 @@
49 49 state-controller="vm.dashboardCtx.stateController"
50 50 dashboard-timewindow="vm.dashboardCtx.dashboardTimewindow"
51 51 is-edit="vm.isEdit"
  52 + autofill-height="vm.layoutCtx.gridSettings.autoFillHeight && !vm.isEdit"
52 53 is-mobile="vm.isMobile"
53 54 is-mobile-disabled="vm.widgetEditMode"
54 55 is-edit-action-enabled="vm.isEdit"
... ...
... ... @@ -53,12 +53,6 @@ export default function DashboardStateDialogController($scope, $mdDialog, $filte
53 53 if (!vm.stateIdTouched && vm.isAdd) {
54 54 vm.state.id = vm.state.name.toLowerCase().replace(/\W/g,"_");
55 55 }
56   - var result = $filter('filter')(vm.allStates, {name: vm.state.name}, true);
57   - if (result && result.length && result[0].id !== vm.prevStateId) {
58   - $scope.theForm.name.$setValidity('stateExists', false);
59   - } else {
60   - $scope.theForm.name.$setValidity('stateExists', true);
61   - }
62 56 }
63 57
64 58 function checkStateId() {
... ...
... ... @@ -37,18 +37,15 @@
37 37 <input name="name" required ng-model="vm.state.name">
38 38 <div ng-messages="theForm.name.$error">
39 39 <div ng-message="required" translate>dashboard.state-name-required</div>
40   - <div ng-message="stateExists" translate>dashboard.state-name-exists</div>
41 40 </div>
42 41 </md-input-container>
43 42 <md-input-container class="md-block">
44 43 <label translate>dashboard.state-id</label>
45   - <input name="stateId" ng-model="vm.state.id"
46   - ng-change="vm.stateIdTouched = true"
47   - ng-pattern="/^[a-zA-Z0-9_]*$/">
  44 + <input name="stateId" required ng-model="vm.state.id"
  45 + ng-change="vm.stateIdTouched = true">
48 46 <div ng-messages="theForm.stateId.$error">
49 47 <div ng-message="required" translate>dashboard.state-id-required</div>
50 48 <div ng-message="stateExists" translate>dashboard.state-id-exists</div>
51   - <div ng-message="pattern" translate>dashboard.invalid-state-id-format</div>
52 49 </div>
53 50 </md-input-container>
54 51 <md-checkbox flex aria-label="{{ 'dashboard.is-root-state' | translate }}"
... ...
... ... @@ -97,10 +97,10 @@ export default function DefaultStateController($scope, $location, $state, $state
97 97
98 98 function getStateName(id, state) {
99 99 var result = '';
100   - var translationId = types.translate.dashboardStatePrefix + id;
  100 + var translationId = types.translate.customTranslationsPrefix + state.name;
101 101 var translation = $translate.instant(translationId);
102 102 if (translation != translationId) {
103   - result = translation;
  103 + result = translation + '';
104 104 } else {
105 105 result = state.name;
106 106 }
... ...
... ... @@ -17,7 +17,7 @@
17 17 import './entity-state-controller.scss';
18 18
19 19 /*@ngInject*/
20   -export default function EntityStateController($scope, $location, $state, $stateParams, $q, $translate, types, dashboardUtils, entityService) {
  20 +export default function EntityStateController($scope, $location, $state, $stateParams, $q, $translate, utils, types, dashboardUtils, entityService) {
21 21
22 22 var vm = this;
23 23
... ... @@ -106,18 +106,17 @@ export default function EntityStateController($scope, $location, $state, $stateP
106 106 function getStateName(index) {
107 107 var result = '';
108 108 if (vm.stateObject[index]) {
  109 + var stateName = vm.states[vm.stateObject[index].id].name;
  110 + var translationId = types.translate.customTranslationsPrefix + stateName;
  111 + var translation = $translate.instant(translationId);
  112 + if (translation != translationId) {
  113 + stateName = translation + '';
  114 + }
109 115 var params = vm.stateObject[index].params;
110 116 if (params && params.entityName) {
111   - result = params.entityName;
  117 + result = utils.insertVariable(stateName, 'entityName', params.entityName);
112 118 } else {
113   - var id = vm.stateObject[index].id;
114   - var translationId = types.translate.dashboardStatePrefix + id;
115   - var translation = $translate.instant(translationId);
116   - if (translation != translationId) {
117   - result = translation;
118   - } else {
119   - result = vm.states[vm.stateObject[index].id].name;
120   - }
  119 + result = stateName;
121 120 }
122 121 }
123 122 return result;
... ...
... ... @@ -32,7 +32,7 @@
32 32 on-manage-credentials="vm.manageCredentials(event, vm.grid.detailsConfig.currentItem)"
33 33 on-delete-device="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-device>
34 34 </md-tab>
35   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}">
  35 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
36 36 <tb-attribute-table flex
37 37 entity-id="vm.grid.operatingItem().id.id"
38 38 entity-type="{{vm.types.entityType.device}}"
... ... @@ -40,7 +40,7 @@
40 40 default-attribute-scope="{{vm.types.attributesScope.client.value}}">
41 41 </tb-attribute-table>
42 42 </md-tab>
43   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}">
  43 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
44 44 <tb-attribute-table flex
45 45 entity-id="vm.grid.operatingItem().id.id"
46 46 entity-type="{{vm.types.entityType.device}}"
... ... @@ -49,19 +49,19 @@
49 49 disable-attribute-scope-selection="true">
50 50 </tb-attribute-table>
51 51 </md-tab>
52   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
  52 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
53 53 <tb-alarm-table flex entity-type="vm.types.entityType.device"
54 54 entity-id="vm.grid.operatingItem().id.id">
55 55 </tb-alarm-table>
56 56 </md-tab>
57   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'device.events' | translate }}">
  57 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'device.events' | translate }}">
58 58 <tb-event-table flex entity-type="vm.types.entityType.device"
59 59 entity-id="vm.grid.operatingItem().id.id"
60 60 tenant-id="vm.grid.operatingItem().tenantId.id"
61 61 default-event-type="{{vm.types.eventType.error.value}}">
62 62 </tb-event-table>
63 63 </md-tab>
64   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
  64 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
65 65 <tb-relation-table flex
66 66 entity-id="vm.grid.operatingItem().id.id"
67 67 entity-type="{{vm.types.entityType.device}}">
... ...
... ... @@ -431,6 +431,7 @@ export default angular.module('thingsboard.locale', [])
431 431 "vertical-margin-required": "Vertical margin value is required.",
432 432 "min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.",
433 433 "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
  434 + "autofill-height": "Auto fill layout height",
434 435 "display-title": "Display dashboard title",
435 436 "toolbar-always-open": "Keep toolbar opened",
436 437 "title-color": "Title color",
... ... @@ -472,11 +473,9 @@ export default angular.module('thingsboard.locale', [])
472 473 "state": "Dashboard state",
473 474 "state-name": "Name",
474 475 "state-name-required": "Dashboard state name is required.",
475   - "state-name-exists": "Dashboard state with the same name is already exists.",
476 476 "state-id": "State Id",
477 477 "state-id-required": "Dashboard state id is required.",
478 478 "state-id-exists": "Dashboard state with the same id is already exists.",
479   - "invalid-state-id-format": "Only alphanumeric characters and underscore are allowed.",
480 479 "is-root-state": "Root state",
481 480 "delete-state-title": "Delete dashboard state",
482 481 "delete-state-text": "Are you sure you want delete dashboard state with name '{{stateName}}'?",
... ... @@ -1169,9 +1168,6 @@ export default angular.module('thingsboard.locale', [])
1169 1168 "es_ES": "Spanish"
1170 1169 },
1171 1170 "custom": {
1172   - "alarms": {
1173   - "title": "Super ${entityName}"
1174   - }
1175 1171 }
1176 1172 }
1177 1173 }
... ...
... ... @@ -18,8 +18,7 @@
18 18 export default function ThingsboardMissingTranslateHandler($log, types) {
19 19
20 20 return function (translationId) {
21   - if (translationId && !translationId.startsWith(types.translate.dashboardStatePrefix) &&
22   - !translationId.startsWith(types.translate.customTranslationsPrefix)) {
  21 + if (translationId && !translationId.startsWith(types.translate.customTranslationsPrefix)) {
23 22 $log.warn('Translation for ' + translationId + ' doesn\'t exist');
24 23 }
25 24 };
... ...
... ... @@ -31,7 +31,7 @@
31 31 on-export-plugin="vm.exportPlugin(event, vm.grid.detailsConfig.currentItem)"
32 32 on-delete-plugin="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-plugin>
33 33 </md-tab>
34   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'attribute.attributes' | translate }}">
  34 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
35 35 <tb-attribute-table flex
36 36 entity-id="vm.grid.operatingItem().id.id"
37 37 entity-type="{{vm.types.entityType.plugin}}"
... ... @@ -39,7 +39,7 @@
39 39 default-attribute-scope="{{vm.types.attributesScope.server.value}}">
40 40 </tb-attribute-table>
41 41 </md-tab>
42   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'attribute.latest-telemetry' | translate }}">
  42 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
43 43 <tb-attribute-table flex
44 44 entity-id="vm.grid.operatingItem().id.id"
45 45 entity-type="{{vm.types.entityType.plugin}}"
... ... @@ -48,19 +48,19 @@
48 48 disable-attribute-scope-selection="true">
49 49 </tb-attribute-table>
50 50 </md-tab>
51   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}">
  51 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
52 52 <tb-alarm-table flex entity-type="vm.types.entityType.plugin"
53 53 entity-id="vm.grid.operatingItem().id.id">
54 54 </tb-alarm-table>
55 55 </md-tab>
56   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'plugin.events' | translate }}">
  56 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'plugin.events' | translate }}">
57 57 <tb-event-table flex entity-type="vm.types.entityType.plugin"
58 58 entity-id="vm.grid.operatingItem().id.id"
59 59 tenant-id="vm.grid.operatingItem().tenantId.id"
60 60 default-event-type="{{vm.types.eventType.lcEvent.value}}">
61 61 </tb-event-table>
62 62 </md-tab>
63   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}">
  63 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
64 64 <tb-relation-table flex
65 65 entity-id="vm.grid.operatingItem().id.id"
66 66 entity-type="{{vm.types.entityType.plugin}}">
... ...
... ... @@ -31,7 +31,7 @@
31 31 on-export-rule="vm.exportRule(event, vm.grid.detailsConfig.currentItem)"
32 32 on-delete-rule="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-rule>
33 33 </md-tab>
34   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'attribute.attributes' | translate }}">
  34 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
35 35 <tb-attribute-table flex
36 36 entity-id="vm.grid.operatingItem().id.id"
37 37 entity-type="{{vm.types.entityType.rule}}"
... ... @@ -39,7 +39,7 @@
39 39 default-attribute-scope="{{vm.types.attributesScope.server.value}}">
40 40 </tb-attribute-table>
41 41 </md-tab>
42   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'attribute.latest-telemetry' | translate }}">
  42 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
43 43 <tb-attribute-table flex
44 44 entity-id="vm.grid.operatingItem().id.id"
45 45 entity-type="{{vm.types.entityType.rule}}"
... ... @@ -48,19 +48,19 @@
48 48 disable-attribute-scope-selection="true">
49 49 </tb-attribute-table>
50 50 </md-tab>
51   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'alarm.alarms' | translate }}">
  51 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
52 52 <tb-alarm-table flex entity-type="vm.types.entityType.rule"
53 53 entity-id="vm.grid.operatingItem().id.id">
54 54 </tb-alarm-table>
55 55 </md-tab>
56   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'rule.events' | translate }}">
  56 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'rule.events' | translate }}">
57 57 <tb-event-table flex entity-type="vm.types.entityType.rule"
58 58 entity-id="vm.grid.operatingItem().id.id"
59 59 tenant-id="vm.grid.operatingItem().tenantId.id"
60 60 default-event-type="{{vm.types.eventType.lcEvent.value}}">
61 61 </tb-event-table>
62 62 </md-tab>
63   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}">
  63 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
64 64 <tb-relation-table flex
65 65 entity-id="vm.grid.operatingItem().id.id"
66 66 entity-type="{{vm.types.entityType.rule}}">
... ...
... ... @@ -29,7 +29,7 @@
29 29 on-manage-users="vm.openTenantUsers(event, vm.grid.detailsConfig.currentItem)"
30 30 on-delete-tenant="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-tenant>
31 31 </md-tab>
32   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}">
  32 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
33 33 <tb-attribute-table flex
34 34 entity-id="vm.grid.operatingItem().id.id"
35 35 entity-type="{{vm.types.entityType.tenant}}"
... ... @@ -37,7 +37,7 @@
37 37 default-attribute-scope="{{vm.types.attributesScope.server.value}}">
38 38 </tb-attribute-table>
39 39 </md-tab>
40   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}">
  40 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">
41 41 <tb-attribute-table flex
42 42 entity-id="vm.grid.operatingItem().id.id"
43 43 entity-type="{{vm.types.entityType.tenant}}"
... ... @@ -46,19 +46,19 @@
46 46 disable-attribute-scope-selection="true">
47 47 </tb-attribute-table>
48 48 </md-tab>
49   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'alarm.alarms' | translate }}">
  49 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">
50 50 <tb-alarm-table flex entity-type="vm.types.entityType.tenant"
51 51 entity-id="vm.grid.operatingItem().id.id">
52 52 </tb-alarm-table>
53 53 </md-tab>
54   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'tenant.events' | translate }}">
  54 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'tenant.events' | translate }}">
55 55 <tb-event-table flex entity-type="vm.types.entityType.tenant"
56 56 entity-id="vm.grid.operatingItem().id.id"
57 57 tenant-id="vm.types.id.nullUid"
58 58 default-event-type="{{vm.types.eventType.error.value}}">
59 59 </tb-event-table>
60 60 </md-tab>
61   - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
  61 + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">
62 62 <tb-relation-table flex
63 63 entity-id="vm.grid.operatingItem().id.id"
64 64 entity-type="{{vm.types.entityType.tenant}}">
... ...
... ... @@ -210,6 +210,9 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
210 210 var cssString = 'table.md-table th.md-column {\n'+
211 211 'color: ' + mdDarkSecondary + ';\n'+
212 212 '}\n'+
  213 + 'table.md-table th.md-column.md-checkbox-column md-checkbox:not(.md-checked) .md-icon {\n'+
  214 + 'border-color: ' + mdDarkSecondary + ';\n'+
  215 + '}\n'+
213 216 'table.md-table th.md-column md-icon.md-sort-icon {\n'+
214 217 'color: ' + mdDarkDisabled + ';\n'+
215 218 '}\n'+
... ... @@ -220,6 +223,9 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
220 223 'color: ' + mdDark + ';\n'+
221 224 'border-top: 1px '+mdDarkDivider+' solid;\n'+
222 225 '}\n'+
  226 + 'table.md-table td.md-cell.md-checkbox-cell md-checkbox:not(.md-checked) .md-icon {\n'+
  227 + 'border-color: ' + mdDarkSecondary + ';\n'+
  228 + '}\n'+
223 229 'table.md-table td.md-cell.md-placeholder {\n'+
224 230 'color: ' + mdDarkDisabled + ';\n'+
225 231 '}\n'+
... ...
... ... @@ -324,8 +324,14 @@ pre.tb-highlight {
324 324 tr {
325 325 &.md-row:not([disabled]) {
326 326 outline: none;
  327 + &:hover {
  328 + background-color: rgba(221, 221, 221, 0.3) !important;
  329 + }
  330 + &.md-selected {
  331 + background-color: rgba(221, 221, 221, 0.5) !important;
  332 + }
327 333 &.tb-current, &.tb-current:hover{
328   - background-color: #dddddd !important;
  334 + background-color: rgba(221, 221, 221, 0.65) !important;
329 335 }
330 336 }
331 337 }
... ...