thingsboard-memoizeit

UI: Dashboard layout improvements.

6/23/2017 6:59:10 AM

Details

diff --git a/ui/src/app/common/dashboard-utils.service.js b/ui/src/app/common/dashboard-utils.service.js
index 915d550..0fc940d 100644
--- a/ui/src/app/common/dashboard-utils.service.js
+++ b/ui/src/app/common/dashboard-utils.service.js
@@ -215,6 +215,12 @@ function DashboardUtils(types, utils, timeService) {
                     row: widget.row,
                     col: widget.col,
                 };
+                if (angular.isDefined(widget.config.mobileHeight)) {
+                    mainLayout.widgets[id].mobileHeight = widget.config.mobileHeight;
+                }
+                if (angular.isDefined(widget.config.mobileOrder)) {
+                    mainLayout.widgets[id].mobileOrder = widget.config.mobileOrder;
+                }
             }
         } else {
             var states = dashboard.configuration.states;
diff --git a/ui/src/app/components/dashboard.directive.js b/ui/src/app/components/dashboard.directive.js
index 1a4cdba..a722e04 100644
--- a/ui/src/app/components/dashboard.directive.js
+++ b/ui/src/app/components/dashboard.directive.js
@@ -60,6 +60,8 @@ function Dashboard() {
             margins: '=',
             isEdit: '=',
             autofillHeight: '=',
+            mobileAutofillHeight: '=?',
+            mobileRowHeight: '=?',
             isMobile: '=',
             isMobileDisabled: '=?',
             isEditActionEnabled: '=',
@@ -124,8 +126,8 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         maxRows: 100,
         columns: vm.columns ? vm.columns : 24,
         margins: vm.margins ? vm.margins : [10, 10],
-        minSizeX: 2,
-        minSizeY: 2,
+        minSizeX: 1,
+        minSizeY: 1,
         defaultSizeX: 8,
         defaultSizeY: 6,
         resizable: {
@@ -170,6 +172,8 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
 
     vm.onWidgetFullscreenChanged = onWidgetFullscreenChanged;
 
+    vm.isAutofillHeight = autofillHeight;
+
     vm.widgetMouseDown = widgetMouseDown;
     vm.widgetClicked = widgetClicked;
 
@@ -177,9 +181,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
     vm.widgetSizeY = widgetSizeY;
     vm.widgetRow = widgetRow;
     vm.widgetCol = widgetCol;
-    vm.widgetColor = widgetColor;
-    vm.widgetBackgroundColor = widgetBackgroundColor;
-    vm.widgetPadding = widgetPadding;
+    vm.widgetStyle = widgetStyle;
     vm.showWidgetTitle = showWidgetTitle;
     vm.hasWidgetTitleTemplate = hasWidgetTitleTemplate;
     vm.widgetTitleTemplate = widgetTitleTemplate;
@@ -236,7 +238,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
     });
 
     function onGirdsterParentResize() {
-        if (gridsterParent.height() && vm.autofillHeight) {
+        if (gridsterParent.height() && autofillHeight()) {
             updateMobileOpts();
         }
     }
@@ -279,7 +281,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
                 delete vm.widgetLayoutInfo[widgetId];
             }
         }
-        if (vm.autofillHeight) {
+        if (autofillHeight()) {
             updateMobileOpts();
         }
     });
@@ -295,15 +297,13 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
 
     function updateMobileOpts() {
         var isMobileDisabled = vm.isMobileDisabled === true;
-        var isMobile = vm.isMobile === true && !isMobileDisabled || vm.autofillHeight;
+        var isMobile = vm.isMobile === true && !isMobileDisabled;
         var mobileBreakPoint = isMobileDisabled ? 0 : (isMobile ? 20000 : 960);
 
         if (!isMobile && !isMobileDisabled) {
             isMobile = !$mdMedia('gt-sm');
         }
 
-        var rowHeight = detectRowSize(isMobile);
-
         if (vm.gridsterOpts.isMobile != isMobile) {
             vm.gridsterOpts.isMobile = isMobile;
             vm.gridsterOpts.mobileModeEnabled = isMobile;
@@ -311,6 +311,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         if (vm.gridsterOpts.mobileBreakPoint != mobileBreakPoint) {
             vm.gridsterOpts.mobileBreakPoint = mobileBreakPoint;
         }
+        var rowHeight = detectRowSize(isMobile);
         if (vm.gridsterOpts.rowHeight != rowHeight) {
             vm.gridsterOpts.rowHeight = rowHeight;
         }
@@ -339,6 +340,14 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         updateMobileOpts();
     });
 
+    $scope.$watch('vm.mobileAutofillHeight', function () {
+        updateMobileOpts();
+    });
+
+    $scope.$watch('vm.mobileRowHeight', function () {
+        updateMobileOpts();
+    });
+
     $scope.$watch('vm.isMobileDisabled', function () {
         updateMobileOpts();
     });
@@ -408,32 +417,49 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         }
     });
 
+    function autofillHeight() {
+        if (vm.gridsterOpts.isMobile) {
+            return angular.isDefined(vm.mobileAutofillHeight) ? vm.mobileAutofillHeight : false;
+        } else {
+            return angular.isDefined(vm.autofillHeight) ? vm.autofillHeight : false;
+        }
+    }
+
     function detectRowSize(isMobile) {
-        var rowHeight = isMobile ? 70 : 'match';
-        if (vm.autofillHeight) {
+        var rowHeight;
+        if (autofillHeight()) {
             var viewportHeight = gridsterParent.height();
             var totalRows = 0;
             for (var i = 0; i < vm.widgets.length; i++) {
                 var w = vm.widgets[i];
                 var sizeY = widgetSizeY(w);
-                totalRows += sizeY;
+                if (isMobile) {
+                    totalRows += sizeY;
+                } else {
+                    var row = widgetRow(w);
+                    var bottom = row + sizeY;
+                    totalRows = Math.max(totalRows, bottom);
+                }
             }
             rowHeight = (viewportHeight - vm.gridsterOpts.margins[1]*(vm.widgets.length+1) + vm.gridsterOpts.margins[0]*vm.widgets.length) / totalRows;
+        } else if (isMobile) {
+            rowHeight = angular.isDefined(vm.mobileRowHeight) ? vm.mobileRowHeight : 70;
+        } else {
+            rowHeight = 'match';
         }
         return rowHeight;
     }
 
     function widgetOrder(widget) {
         var order;
-        if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
-            if (angular.isDefined(vm.widgetLayouts[widget.id].mobileOrder)
+        var hasLayout = vm.widgetLayouts && vm.widgetLayouts[widget.id];
+        if (hasLayout && angular.isDefined(vm.widgetLayouts[widget.id].mobileOrder)
                 && vm.widgetLayouts[widget.id].mobileOrder >= 0) {
-                order = vm.widgetLayouts[widget.id].mobileOrder;
-            } else {
-                order = vm.widgetLayouts[widget.id].row;
-            }
+            order = vm.widgetLayouts[widget.id].mobileOrder;
         } else if (angular.isDefined(widget.config.mobileOrder) && widget.config.mobileOrder >= 0) {
             order = widget.config.mobileOrder;
+        } else if (hasLayout) {
+            order = vm.widgetLayouts[widget.id].row;
         } else {
             order = widget.row;
         }
@@ -722,7 +748,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
     }
 
     function widgetSizeY(widget) {
-        if (vm.gridsterOpts.isMobile && !vm.autofillHeight) {
+        if (vm.gridsterOpts.isMobile && !vm.mobileAutofillHeight) {
             var mobileHeight;
             if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
                 mobileHeight = vm.widgetLayouts[widget.id].mobileHeight;
@@ -790,6 +816,18 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         }
     }
 
+    function widgetStyle(widget) {
+        var style = {cursor: 'pointer',
+                     color: widgetColor(widget),
+                     backgroundColor: widgetBackgroundColor(widget),
+                     padding: widgetPadding(widget),
+                     margin: widgetMargin(widget)};
+        if (angular.isDefined(widget.config.widgetStyle)) {
+            Object.assign(style, widget.config.widgetStyle);
+        }
+        return style;
+    }
+
     function widgetColor(widget) {
         if (widget.config.color) {
             return widget.config.color;
@@ -814,6 +852,14 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
         }
     }
 
+    function widgetMargin(widget) {
+        if (widget.config.margin) {
+            return widget.config.margin;
+        } else {
+            return '0px';
+        }
+    }
+
     function showWidgetTitle(widget) {
         if (angular.isDefined(widget.config.showTitle)) {
             return widget.config.showTitle;
diff --git a/ui/src/app/components/dashboard.tpl.html b/ui/src/app/components/dashboard.tpl.html
index 5d46fea..2887419 100644
--- a/ui/src/app/components/dashboard.tpl.html
+++ b/ui/src/app/components/dashboard.tpl.html
@@ -22,7 +22,8 @@
 	</md-progress-circular>
 </md-content>
 <md-menu md-position-mode="target target" tb-mousepoint-menu>
-	<md-content id="gridster-parent" class="tb-dashboard-content" flex layout-wrap ng-click="" tb-contextmenu="vm.openDashboardContextMenu($event, $mdOpenMousepointMenu)">
+	<md-content id="gridster-parent" class="tb-dashboard-content" flex layout-wrap ng-click="" ng-style="{'overflowY': vm.isAutofillHeight() ? 'hidden' : 'auto'}"
+				tb-contextmenu="vm.openDashboardContextMenu($event, $mdOpenMousepointMenu)">
 		<div ng-class="vm.dashboardClass" id="gridster-background" style="height: auto; min-height: 100%; display: inline;">
 			<div id="gridster-child" gridster="vm.gridsterOpts">
 				<ul>
@@ -42,10 +43,7 @@
 										tb-mousedown="vm.widgetMouseDown($event, widget)"
 										ng-click="vm.widgetClicked($event, widget)"
 										tb-contextmenu="vm.openWidgetContextMenu($event, widget, $mdOpenMousepointMenu)"
-									    ng-style="{cursor: 'pointer',
-            									   color: vm.widgetColor(widget),
-            									   backgroundColor: vm.widgetBackgroundColor(widget),
-            									   padding: vm.widgetPadding(widget)}">
+									    ng-style="vm.widgetStyle(widget)">
 								<div class="tb-widget-title" layout="column" layout-align="center start" ng-show="vm.showWidgetTitlePanel(widget)">
 									<div ng-if="vm.hasWidgetTitleTemplate(widget)" ng-include="vm.widgetTitleTemplate(widget)"></div>
 									<span ng-show="vm.showWidgetTitle(widget)" ng-style="vm.widgetTitleStyle(widget)" class="md-subhead">{{vm.widgetTitle(widget)}}</span>
diff --git a/ui/src/app/components/widget/widget-config.directive.js b/ui/src/app/components/widget/widget-config.directive.js
index afdaf8d..8ec91a8 100644
--- a/ui/src/app/components/widget/widget-config.directive.js
+++ b/ui/src/app/components/widget/widget-config.directive.js
@@ -64,7 +64,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
             '*'
         ];
 
-        scope.titleStyleEditorOptions = {
+        scope.styleEditorOptions = {
             useWrapMode: true,
             mode: 'json',
             advanced: {
@@ -106,6 +106,9 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
                     scope.backgroundColor = config.backgroundColor;
                     scope.color = config.color;
                     scope.padding = config.padding;
+                    scope.margin = config.margin;
+                    scope.widgetStyle =
+                        angular.toJson(angular.isDefined(config.widgetStyle) ? config.widgetStyle : {}, true);
                     scope.titleStyle =
                         angular.toJson(angular.isDefined(config.titleStyle) ? config.titleStyle : {
                             fontSize: '16px',
@@ -205,6 +208,12 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
                         ngModelCtrl.$setValidity('datasources', valid);
                     }
                     try {
+                        angular.fromJson(scope.widgetStyle);
+                        ngModelCtrl.$setValidity('widgetStyle', true);
+                    } catch (e) {
+                        ngModelCtrl.$setValidity('widgetStyle', false);
+                    }
+                    try {
                         angular.fromJson(scope.titleStyle);
                         ngModelCtrl.$setValidity('titleStyle', true);
                     } catch (e) {
@@ -215,7 +224,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
         };
 
         scope.$watch('title + showTitle + dropShadow + enableFullscreen + backgroundColor + color + ' +
-            'padding + titleStyle + mobileOrder + mobileHeight + units + decimals + useDashboardTimewindow + ' +
+            'padding + margin + widgetStyle + titleStyle + mobileOrder + mobileHeight + units + decimals + useDashboardTimewindow + ' +
             'alarmSearchStatus + alarmsPollingInterval + showLegend', function () {
             if (ngModelCtrl.$viewValue) {
                 var value = ngModelCtrl.$viewValue;
@@ -228,6 +237,12 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
                     config.backgroundColor = scope.backgroundColor;
                     config.color = scope.color;
                     config.padding = scope.padding;
+                    config.margin = scope.margin;
+                    try {
+                        config.widgetStyle = angular.fromJson(scope.widgetStyle);
+                    } catch (e) {
+                        config.widgetStyle = {};
+                    }
                     try {
                         config.titleStyle = angular.fromJson(scope.titleStyle);
                     } catch (e) {
diff --git a/ui/src/app/components/widget/widget-config.tpl.html b/ui/src/app/components/widget/widget-config.tpl.html
index f2ee0f1..6851ee8 100644
--- a/ui/src/app/components/widget/widget-config.tpl.html
+++ b/ui/src/app/components/widget/widget-config.tpl.html
@@ -179,7 +179,7 @@
                     </md-input-container>
                     <div flex ng-show="showTitle">
                         <label translate>widget-config.title-style</label>
-                        <div ui-ace="titleStyleEditorOptions" ng-model="titleStyle" ng-style="{ minHeight: '100px' }">
+                        <div ui-ace="styleEditorOptions" ng-model="titleStyle" ng-style="{ minHeight: '100px' }">
                         </div>
                     </div>
                 </div>
@@ -199,6 +199,11 @@
                                      ng-model="enableFullscreen">{{ 'widget-config.enable-fullscreen' | translate }}
                         </md-checkbox>
                     </div>
+                    <div flex>
+                        <label translate>widget-config.widget-style</label>
+                        <div ui-ace="styleEditorOptions" ng-model="widgetStyle" ng-style="{ minHeight: '100px' }">
+                        </div>
+                    </div>
                 </div>
                 <div layout='column' layout-align="center" layout-gt-sm='row' layout-align-gt-sm="start center">
                     <div flex
@@ -227,6 +232,10 @@
                         <label translate>widget-config.padding</label>
                         <input ng-model="padding">
                     </md-input-container>
+                    <md-input-container flex>
+                        <label translate>widget-config.margin</label>
+                        <input ng-model="margin">
+                    </md-input-container>
                 </div>
                 <div layout='column' layout-align="center" layout-gt-sm='row' layout-align-gt-sm="start center">
                     <md-input-container flex>
diff --git a/ui/src/app/dashboard/dashboard-settings.controller.js b/ui/src/app/dashboard/dashboard-settings.controller.js
index c5743c9..749b7d6 100644
--- a/ui/src/app/dashboard/dashboard-settings.controller.js
+++ b/ui/src/app/dashboard/dashboard-settings.controller.js
@@ -69,6 +69,8 @@ export default function DashboardSettingsController($scope, $mdDialog, statesCon
         vm.gridSettings.columns = vm.gridSettings.columns || 24;
         vm.gridSettings.margins = vm.gridSettings.margins || [10, 10];
         vm.gridSettings.autoFillHeight = angular.isDefined(vm.gridSettings.autoFillHeight) ? vm.gridSettings.autoFillHeight : false;
+        vm.gridSettings.mobileAutoFillHeight = angular.isDefined(vm.gridSettings.mobileAutoFillHeight) ? vm.gridSettings.mobileAutoFillHeight : false;
+        vm.gridSettings.mobileRowHeight = angular.isDefined(vm.gridSettings.mobileRowHeight) ? vm.gridSettings.mobileRowHeight : 70;
         vm.hMargin = vm.gridSettings.margins[0];
         vm.vMargin = vm.gridSettings.margins[1];
         vm.gridSettings.backgroundSizeMode = vm.gridSettings.backgroundSizeMode || '100%';
diff --git a/ui/src/app/dashboard/dashboard-settings.tpl.html b/ui/src/app/dashboard/dashboard-settings.tpl.html
index 427ca19..0d69287 100644
--- a/ui/src/app/dashboard/dashboard-settings.tpl.html
+++ b/ui/src/app/dashboard/dashboard-settings.tpl.html
@@ -171,6 +171,22 @@
                                 <md-option value="auto">Original size</md-option>
                             </md-select>
                         </md-input-container>
+                        <small translate>dashboard.mobile-layout</small>
+                        <div flex layout="row" layout-align="start center">
+                            <md-checkbox flex aria-label="{{ 'dashboard.autofill-height' | translate }}"
+                                         ng-model="vm.gridSettings.mobileAutoFillHeight">{{ 'dashboard.autofill-height' | translate }}
+                            </md-checkbox>
+                            <md-input-container flex class="md-block">
+                                <label translate>dashboard.mobile-row-height</label>
+                                <input ng-required="vm.gridSettings" type="number" step="any" name="mobileRowHeight" ng-model="vm.gridSettings.mobileRowHeight"
+                                       min="5" max="200" />
+                                <div ng-messages="theForm.mobileRowHeight.$error" multiple md-auto-hide="false">
+                                    <div ng-message="required" translate>dashboard.mobile-row-height-required</div>
+                                    <div ng-message="min" translate>dashboard.min-mobile-row-height-message</div>
+                                    <div ng-message="max" translate>dashboard.max-mobile-row-height-message</div>
+                                </div>
+                            </md-input-container>
+                        </div>
                     </div>
                 </fieldset>
             </div>
diff --git a/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html b/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
index 3df1327..90a10b1 100644
--- a/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
+++ b/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
@@ -50,6 +50,8 @@
             dashboard-timewindow="vm.dashboardCtx.dashboardTimewindow"
             is-edit="vm.isEdit"
             autofill-height="vm.layoutCtx.gridSettings.autoFillHeight && !vm.isEdit"
+            mobile-autofill-height="vm.layoutCtx.gridSettings.mobileAutoFillHeight && !vm.isEdit"
+            mobile-row-height="vm.layoutCtx.gridSettings.mobileRowHeight"
             is-mobile="vm.isMobile"
             is-mobile-disabled="vm.widgetEditMode"
             is-edit-action-enabled="vm.isEdit"
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 4d4ebe2..819afbb 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -432,6 +432,11 @@ export default angular.module('thingsboard.locale', [])
                     "min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.",
                     "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
                     "autofill-height": "Auto fill layout height",
+                    "mobile-layout": "Mobile layout settings",
+                    "mobile-row-height": "Mobile row height, px",
+                    "mobile-row-height-required": "Mobile row height value is required.",
+                    "min-mobile-row-height-message": "Only 5 pixels is allowed as minimum mobile row height value.",
+                    "max-mobile-row-height-message": "Only 200 pixels is allowed as maximum mobile row height value.",
                     "display-title": "Display dashboard title",
                     "toolbar-always-open": "Keep toolbar opened",
                     "title-color": "Title color",
@@ -1154,6 +1159,8 @@ export default angular.module('thingsboard.locale', [])
                     "background-color": "Background color",
                     "text-color": "Text color",
                     "padding": "Padding",
+                    "margin": "Margin",
+                    "widget-style": "Widget style",
                     "title-style": "Title style",
                     "mobile-mode-settings": "Mobile mode settings",
                     "order": "Order",