UI: Improve dashboard layout settings.
This commit is contained in:
		
							parent
							
								
									9bd923a878
								
							
						
					
					
						commit
						8fad8245df
					
				
							
								
								
									
										44
									
								
								ui-ngx/patches/angular-gridster2+15.0.4.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								ui-ngx/patches/angular-gridster2+15.0.4.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					diff --git a/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs b/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
 | 
				
			||||||
 | 
					index cf4e220..4275d11 100644
 | 
				
			||||||
 | 
					--- a/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
 | 
				
			||||||
 | 
					+++ b/node_modules/angular-gridster2/fesm2020/angular-gridster2.mjs
 | 
				
			||||||
 | 
					@@ -208,6 +208,7 @@ const GridsterConfigService = {
 | 
				
			||||||
 | 
					     useTransformPositioning: true,
 | 
				
			||||||
 | 
					     scrollSensitivity: 10,
 | 
				
			||||||
 | 
					     scrollSpeed: 20,
 | 
				
			||||||
 | 
					+    colWidthUpdateCallback: undefined,
 | 
				
			||||||
 | 
					     initCallback: undefined,
 | 
				
			||||||
 | 
					     destroyCallback: undefined,
 | 
				
			||||||
 | 
					     gridSizeChangedCallback: undefined,
 | 
				
			||||||
 | 
					@@ -1243,6 +1244,9 @@ class GridsterComponent {
 | 
				
			||||||
 | 
					                 this.renderer.setStyle(this.el, 'padding-right', this.$options.margin + 'px');
 | 
				
			||||||
 | 
					             }
 | 
				
			||||||
 | 
					             this.curColWidth = (this.curWidth - marginWidth) / this.columns;
 | 
				
			||||||
 | 
					+            if (this.options.colWidthUpdateCallback) {
 | 
				
			||||||
 | 
					+              this.curColWidth = this.options.colWidthUpdateCallback(this.curColWidth);
 | 
				
			||||||
 | 
					+            }
 | 
				
			||||||
 | 
					             let marginHeight = -this.$options.margin;
 | 
				
			||||||
 | 
					             if (this.$options.outerMarginTop !== null) {
 | 
				
			||||||
 | 
					                 marginHeight += this.$options.outerMarginTop;
 | 
				
			||||||
 | 
					@@ -1266,6 +1270,9 @@ class GridsterComponent {
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					         else {
 | 
				
			||||||
 | 
					             this.curColWidth = (this.curWidth + this.$options.margin) / this.columns;
 | 
				
			||||||
 | 
					+            if (this.options.colWidthUpdateCallback) {
 | 
				
			||||||
 | 
					+              this.curColWidth = this.options.colWidthUpdateCallback(this.curColWidth);
 | 
				
			||||||
 | 
					+            }
 | 
				
			||||||
 | 
					             this.curRowHeight =
 | 
				
			||||||
 | 
					                 ((this.curHeight + this.$options.margin) / this.rows) *
 | 
				
			||||||
 | 
					                     this.$options.rowHeightRatio;
 | 
				
			||||||
 | 
					diff --git a/node_modules/angular-gridster2/lib/gridsterConfig.interface.d.ts b/node_modules/angular-gridster2/lib/gridsterConfig.interface.d.ts
 | 
				
			||||||
 | 
					index 1d7cdf0..a712b35 100644
 | 
				
			||||||
 | 
					--- a/node_modules/angular-gridster2/lib/gridsterConfig.interface.d.ts
 | 
				
			||||||
 | 
					+++ b/node_modules/angular-gridster2/lib/gridsterConfig.interface.d.ts
 | 
				
			||||||
 | 
					@@ -73,6 +73,7 @@ export interface GridsterConfig {
 | 
				
			||||||
 | 
					     useTransformPositioning?: boolean;
 | 
				
			||||||
 | 
					     scrollSensitivity?: number | null;
 | 
				
			||||||
 | 
					     scrollSpeed?: number;
 | 
				
			||||||
 | 
					+    colWidthUpdateCallback?: (colWidth: number) => number; 
 | 
				
			||||||
 | 
					     initCallback?: (gridster: GridsterComponentInterface) => void;
 | 
				
			||||||
 | 
					     destroyCallback?: (gridster: GridsterComponentInterface) => void;
 | 
				
			||||||
 | 
					     gridSizeChangedCallback?: (gridster: GridsterComponentInterface) => void;
 | 
				
			||||||
@ -610,17 +610,15 @@ export class DashboardUtilsService {
 | 
				
			|||||||
      originalColumns = 24;
 | 
					      originalColumns = 24;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const gridSettings = layout.gridSettings;
 | 
					    const gridSettings = layout.gridSettings;
 | 
				
			||||||
    if (!gridSettings.isScada) {
 | 
					    let columns = 24;
 | 
				
			||||||
      let columns = 24;
 | 
					    if (gridSettings && gridSettings.columns) {
 | 
				
			||||||
      if (gridSettings && gridSettings.columns) {
 | 
					      columns = gridSettings.columns;
 | 
				
			||||||
        columns = gridSettings.columns;
 | 
					    }
 | 
				
			||||||
      }
 | 
					    columns = columns * layoutCount;
 | 
				
			||||||
      columns = columns * layoutCount;
 | 
					    if (columns !== originalColumns) {
 | 
				
			||||||
      if (columns !== originalColumns) {
 | 
					      const ratio = columns / originalColumns;
 | 
				
			||||||
        const ratio = columns / originalColumns;
 | 
					      widgetLayout.sizeX *= ratio;
 | 
				
			||||||
        widgetLayout.sizeX *= ratio;
 | 
					      widgetLayout.sizeY *= ratio;
 | 
				
			||||||
        widgetLayout.sizeY *= ratio;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (row > -1 && column > - 1) {
 | 
					    if (row > -1 && column > - 1) {
 | 
				
			||||||
@ -686,35 +684,32 @@ export class DashboardUtilsService {
 | 
				
			|||||||
    const columns = gridSettings.columns || 24;
 | 
					    const columns = gridSettings.columns || 24;
 | 
				
			||||||
    const ratio = columns / prevColumns;
 | 
					    const ratio = columns / prevColumns;
 | 
				
			||||||
    layout.gridSettings = gridSettings;
 | 
					    layout.gridSettings = gridSettings;
 | 
				
			||||||
    if (!gridSettings.isScada) {
 | 
					    for (const w of Object.keys(layout.widgets)) {
 | 
				
			||||||
      let maxRow = 0;
 | 
					      const widget = layout.widgets[w];
 | 
				
			||||||
      for (const w of Object.keys(layout.widgets)) {
 | 
					      if (!widget.sizeX) {
 | 
				
			||||||
        const widget = layout.widgets[w];
 | 
					        widget.sizeX = 1;
 | 
				
			||||||
        if (!widget.sizeX) {
 | 
					 | 
				
			||||||
          widget.sizeX = 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (!widget.sizeY) {
 | 
					 | 
				
			||||||
          widget.sizeY = 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        maxRow = Math.max(maxRow, widget.row + widget.sizeY);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const newMaxRow = Math.round(maxRow * ratio);
 | 
					      if (!widget.sizeY) {
 | 
				
			||||||
      for (const w of Object.keys(layout.widgets)) {
 | 
					        widget.sizeY = 1;
 | 
				
			||||||
        const widget = layout.widgets[w];
 | 
					 | 
				
			||||||
        if (widget.row + widget.sizeY === maxRow) {
 | 
					 | 
				
			||||||
          widget.row = Math.round(widget.row * ratio);
 | 
					 | 
				
			||||||
          widget.sizeY = newMaxRow - widget.row;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          widget.row = Math.round(widget.row * ratio);
 | 
					 | 
				
			||||||
          widget.sizeY = Math.round(widget.sizeY * ratio);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        widget.sizeX = Math.round(widget.sizeX * ratio);
 | 
					 | 
				
			||||||
        widget.col = Math.round(widget.col * ratio);
 | 
					 | 
				
			||||||
        if (widget.col + widget.sizeX > columns) {
 | 
					 | 
				
			||||||
          widget.sizeX = columns - widget.col;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    for (const w of Object.keys(layout.widgets)) {
 | 
				
			||||||
 | 
					      const widget = layout.widgets[w];
 | 
				
			||||||
 | 
					      widget.row = Math.round(widget.row * ratio);
 | 
				
			||||||
 | 
					      widget.col = Math.round(widget.col * ratio);
 | 
				
			||||||
 | 
					      widget.sizeX = Math.round(widget.sizeX * ratio);
 | 
				
			||||||
 | 
					      widget.sizeY = Math.round(widget.sizeY * ratio);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public moveWidgets(layout: DashboardLayout, cols: number, rows: number) {
 | 
				
			||||||
 | 
					    cols = isDefinedAndNotNull(cols) ? Math.round(cols) : 0;
 | 
				
			||||||
 | 
					    rows = isDefinedAndNotNull(rows) ? Math.round(rows) : 0;
 | 
				
			||||||
 | 
					    for (const w of Object.keys(layout.widgets)) {
 | 
				
			||||||
 | 
					      const widget = layout.widgets[w];
 | 
				
			||||||
 | 
					      widget.col = Math.max(0, widget.col + cols);
 | 
				
			||||||
 | 
					      widget.row = Math.max(0, widget.row + rows);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public removeUnusedWidgets(dashboard: Dashboard) {
 | 
					  public removeUnusedWidgets(dashboard: Dashboard) {
 | 
				
			||||||
 | 
				
			|||||||
@ -150,6 +150,10 @@ import { LayoutFixedSize, LayoutWidthType } from '@home/components/dashboard-pag
 | 
				
			|||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
					import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
				
			||||||
import { ResizeObserver } from '@juggle/resize-observer';
 | 
					import { ResizeObserver } from '@juggle/resize-observer';
 | 
				
			||||||
import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
 | 
					import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  MoveWidgetsDialogComponent,
 | 
				
			||||||
 | 
					  MoveWidgetsDialogResult
 | 
				
			||||||
 | 
					} from '@home/components/dashboard-page/layout/move-widgets-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @dynamic
 | 
					// @dynamic
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
@ -285,7 +289,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
 | 
				
			|||||||
        gridSettings: {},
 | 
					        gridSettings: {},
 | 
				
			||||||
        ignoreLoading: true,
 | 
					        ignoreLoading: true,
 | 
				
			||||||
        ctrl: null,
 | 
					        ctrl: null,
 | 
				
			||||||
        dashboardCtrl: this
 | 
					        dashboardCtrl: this,
 | 
				
			||||||
 | 
					        displayGrid: 'onDrag&Resize'
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    right: {
 | 
					    right: {
 | 
				
			||||||
@ -297,7 +302,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
 | 
				
			|||||||
        gridSettings: {},
 | 
					        gridSettings: {},
 | 
				
			||||||
        ignoreLoading: true,
 | 
					        ignoreLoading: true,
 | 
				
			||||||
        ctrl: null,
 | 
					        ctrl: null,
 | 
				
			||||||
        dashboardCtrl: this
 | 
					        dashboardCtrl: this,
 | 
				
			||||||
 | 
					        displayGrid: 'onDrag&Resize'
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -913,6 +919,28 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private moveWidgets($event: Event, layoutId: DashboardLayoutId) {
 | 
				
			||||||
 | 
					    if ($event) {
 | 
				
			||||||
 | 
					      $event.stopPropagation();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.layouts[layoutId].layoutCtx.displayGrid = 'always';
 | 
				
			||||||
 | 
					    this.cd.markForCheck();
 | 
				
			||||||
 | 
					    this.dialog.open<MoveWidgetsDialogComponent, any,
 | 
				
			||||||
 | 
					      MoveWidgetsDialogResult>(MoveWidgetsDialogComponent, {
 | 
				
			||||||
 | 
					      disableClose: true,
 | 
				
			||||||
 | 
					      panelClass: ['tb-dialog', 'tb-fullscreen-dialog']
 | 
				
			||||||
 | 
					    }).afterClosed().subscribe((result) => {
 | 
				
			||||||
 | 
					      this.layouts[layoutId].layoutCtx.displayGrid = 'onDrag&Resize';
 | 
				
			||||||
 | 
					      if (result) {
 | 
				
			||||||
 | 
					        const targetLayout = this.dashboardConfiguration.states[this.dashboardCtx.state].layouts[layoutId];
 | 
				
			||||||
 | 
					        this.dashboardUtils.moveWidgets(targetLayout, result.cols, result.rows);
 | 
				
			||||||
 | 
					        this.updateLayouts();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.cd.markForCheck();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private updateDashboardLayouts(newLayouts: DashboardStateLayouts) {
 | 
					  private updateDashboardLayouts(newLayouts: DashboardStateLayouts) {
 | 
				
			||||||
    this.dashboardUtils.setLayouts(this.dashboard, this.dashboardCtx.state, newLayouts);
 | 
					    this.dashboardUtils.setLayouts(this.dashboard, this.dashboardCtx.state, newLayouts);
 | 
				
			||||||
    this.updateLayouts();
 | 
					    this.updateLayouts();
 | 
				
			||||||
@ -1422,6 +1450,16 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
 | 
				
			|||||||
          shortcut: 'M-I'
 | 
					          shortcut: 'M-I'
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					      dashboardContextActions.push(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          action: ($event) => {
 | 
				
			||||||
 | 
					            this.moveWidgets($event, layoutCtx.id);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          enabled: true,
 | 
				
			||||||
 | 
					          value: 'dashboard.move-all-widgets',
 | 
				
			||||||
 | 
					          icon: 'open_with'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return dashboardContextActions;
 | 
					    return dashboardContextActions;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@ import { IAliasController, IStateController } from '@core/api/widget-api.models'
 | 
				
			|||||||
import { ILayoutController } from './layout/layout.models';
 | 
					import { ILayoutController } from './layout/layout.models';
 | 
				
			||||||
import { DashboardContextMenuItem, WidgetContextMenuItem } from '@home/models/dashboard-component.models';
 | 
					import { DashboardContextMenuItem, WidgetContextMenuItem } from '@home/models/dashboard-component.models';
 | 
				
			||||||
import { Observable } from 'rxjs';
 | 
					import { Observable } from 'rxjs';
 | 
				
			||||||
 | 
					import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export declare type DashboardPageScope = 'tenant' | 'customer';
 | 
					export declare type DashboardPageScope = 'tenant' | 'customer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -69,6 +70,7 @@ export interface DashboardPageLayoutContext {
 | 
				
			|||||||
  ctrl: ILayoutController;
 | 
					  ctrl: ILayoutController;
 | 
				
			||||||
  dashboardCtrl: IDashboardController;
 | 
					  dashboardCtrl: IDashboardController;
 | 
				
			||||||
  ignoreLoading: boolean;
 | 
					  ignoreLoading: boolean;
 | 
				
			||||||
 | 
					  displayGrid: displayGrids;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface DashboardPageLayout {
 | 
					export interface DashboardPageLayout {
 | 
				
			||||||
 | 
				
			|||||||
@ -114,8 +114,9 @@
 | 
				
			|||||||
        <div class="tb-form-panel-title" translate>dashboard.layout-settings</div>
 | 
					        <div class="tb-form-panel-title" translate>dashboard.layout-settings</div>
 | 
				
			||||||
        <div class="tb-form-row space-between">
 | 
					        <div class="tb-form-row space-between">
 | 
				
			||||||
          <div translate>dashboard.columns-count</div>
 | 
					          <div translate>dashboard.columns-count</div>
 | 
				
			||||||
          <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
 | 
					          <mat-form-field *ngIf="!gridSettingsFormGroup.get('isScada').value"
 | 
				
			||||||
            <input matInput formControlName="columns" type="number" min="10" max="1000" step="1"
 | 
					                          appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
 | 
				
			||||||
 | 
					            <input matInput formControlName="columns" type="number" min="10" max="1008" step="1"
 | 
				
			||||||
                   required
 | 
					                   required
 | 
				
			||||||
                   placeholder="{{ 'widget-config.set' | translate }}">
 | 
					                   placeholder="{{ 'widget-config.set' | translate }}">
 | 
				
			||||||
            <mat-icon matSuffix
 | 
					            <mat-icon matSuffix
 | 
				
			||||||
@ -128,6 +129,32 @@
 | 
				
			|||||||
              warning
 | 
					              warning
 | 
				
			||||||
            </mat-icon>
 | 
					            </mat-icon>
 | 
				
			||||||
          </mat-form-field>
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					          <mat-form-field *ngIf="gridSettingsFormGroup.get('isScada').value"
 | 
				
			||||||
 | 
					                          class="medium-width" appearance="outline" subscriptSizing="dynamic">
 | 
				
			||||||
 | 
					            <mat-select required formControlName="columns">
 | 
				
			||||||
 | 
					              <mat-option *ngFor="let columns of scadaColumns" [value]="columns">
 | 
				
			||||||
 | 
					                {{ columns }}
 | 
				
			||||||
 | 
					              </mat-option>
 | 
				
			||||||
 | 
					            </mat-select>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="tb-form-row space-between">
 | 
				
			||||||
 | 
					          <div translate>dashboard.min-layout-width</div>
 | 
				
			||||||
 | 
					          <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
 | 
				
			||||||
 | 
					            <input matInput formControlName="minColumns" type="number" min="10" max="1008" step="1"
 | 
				
			||||||
 | 
					                   required
 | 
				
			||||||
 | 
					                   placeholder="{{ 'widget-config.set' | translate }}">
 | 
				
			||||||
 | 
					            <mat-icon matSuffix
 | 
				
			||||||
 | 
					                      matTooltipPosition="above"
 | 
				
			||||||
 | 
					                      matTooltipClass="tb-error-tooltip"
 | 
				
			||||||
 | 
					                      [matTooltip]="(gridSettingsFormGroup.get('columns').hasError('required') ? 'dashboard.columns-count-required' :
 | 
				
			||||||
 | 
					                                     (gridSettingsFormGroup.get('columns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate"
 | 
				
			||||||
 | 
					                      *ngIf="gridSettingsFormGroup.get('minColumns').invalid && gridSettingsFormGroup.get('minColumns').touched"
 | 
				
			||||||
 | 
					                      class="tb-error">
 | 
				
			||||||
 | 
					              warning
 | 
				
			||||||
 | 
					            </mat-icon>
 | 
				
			||||||
 | 
					            <span translate matSuffix>dashboard.columns-suffix</span>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row space-between">
 | 
					        <div *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row space-between">
 | 
				
			||||||
          <div translate>dashboard.widgets-margins</div>
 | 
					          <div translate>dashboard.widgets-margins</div>
 | 
				
			||||||
 | 
				
			|||||||
@ -54,6 +54,8 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  submitted = false;
 | 
					  submitted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  scadaColumns: number[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private stateControllerTranslationMap = new Map<string, string>([
 | 
					  private stateControllerTranslationMap = new Map<string, string>([
 | 
				
			||||||
    ['default', 'dashboard.state-controller-default'],
 | 
					    ['default', 'dashboard.state-controller-default'],
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
@ -155,10 +157,17 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this.gridSettings) {
 | 
					    if (this.gridSettings) {
 | 
				
			||||||
 | 
					      let columns = 24;
 | 
				
			||||||
 | 
					      while (columns <= 1008) {
 | 
				
			||||||
 | 
					        this.scadaColumns.push(columns);
 | 
				
			||||||
 | 
					        columns += 24;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      const mobileAutoFillHeight = isUndefined(this.gridSettings.mobileAutoFillHeight) ? false : this.gridSettings.mobileAutoFillHeight;
 | 
					      const mobileAutoFillHeight = isUndefined(this.gridSettings.mobileAutoFillHeight) ? false : this.gridSettings.mobileAutoFillHeight;
 | 
				
			||||||
      this.gridSettingsFormGroup = this.fb.group({
 | 
					      this.gridSettingsFormGroup = this.fb.group({
 | 
				
			||||||
        isScada: [this.gridSettings.isScada, []],
 | 
					        isScada: [this.gridSettings.isScada, []],
 | 
				
			||||||
        columns: [this.gridSettings.columns || 24, [Validators.required, Validators.min(10), Validators.max(1000)]],
 | 
					        columns: [this.gridSettings.columns || 24, [Validators.required, Validators.min(10), Validators.max(1008)]],
 | 
				
			||||||
 | 
					        minColumns: [this.gridSettings.minColumns || this.gridSettings.columns || 24,
 | 
				
			||||||
 | 
					          [Validators.required, Validators.min(10), Validators.max(1008)]],
 | 
				
			||||||
        margin: [isDefined(this.gridSettings.margin) ? this.gridSettings.margin : 10,
 | 
					        margin: [isDefined(this.gridSettings.margin) ? this.gridSettings.margin : 10,
 | 
				
			||||||
          [Validators.required, Validators.min(0), Validators.max(50)]],
 | 
					          [Validators.required, Validators.min(0), Validators.max(50)]],
 | 
				
			||||||
        outerMargin: [isUndefined(this.gridSettings.outerMargin) ? true : this.gridSettings.outerMargin, []],
 | 
					        outerMargin: [isUndefined(this.gridSettings.outerMargin) ? true : this.gridSettings.outerMargin, []],
 | 
				
			||||||
@ -228,6 +237,11 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
 | 
				
			|||||||
      this.gridSettingsFormGroup.get('autoFillHeight').disable();
 | 
					      this.gridSettingsFormGroup.get('autoFillHeight').disable();
 | 
				
			||||||
      this.gridSettingsFormGroup.get('mobileAutoFillHeight').disable({emitEvent: false});
 | 
					      this.gridSettingsFormGroup.get('mobileAutoFillHeight').disable({emitEvent: false});
 | 
				
			||||||
      this.gridSettingsFormGroup.get('mobileRowHeight').disable();
 | 
					      this.gridSettingsFormGroup.get('mobileRowHeight').disable();
 | 
				
			||||||
 | 
					      const columns: number = this.gridSettingsFormGroup.get('columns').value;
 | 
				
			||||||
 | 
					      if (columns % 24 !== 0) {
 | 
				
			||||||
 | 
					        const newColumns = Math.min(1008, 24 * Math.ceil(columns / 24));
 | 
				
			||||||
 | 
					        this.gridSettingsFormGroup.get('columns').patchValue(newColumns);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.gridSettingsFormGroup.get('margin').enable();
 | 
					      this.gridSettingsFormGroup.get('margin').enable();
 | 
				
			||||||
      this.gridSettingsFormGroup.get('outerMargin').enable();
 | 
					      this.gridSettingsFormGroup.get('outerMargin').enable();
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,9 @@
 | 
				
			|||||||
                [backgroundImage]="backgroundImage$ | async"
 | 
					                [backgroundImage]="backgroundImage$ | async"
 | 
				
			||||||
                [widgets]="layoutCtx.widgets"
 | 
					                [widgets]="layoutCtx.widgets"
 | 
				
			||||||
                [widgetLayouts]="layoutCtx.widgetLayouts"
 | 
					                [widgetLayouts]="layoutCtx.widgetLayouts"
 | 
				
			||||||
                [columns]="layoutCtx.gridSettings.columns"
 | 
					                [columns]="columns"
 | 
				
			||||||
 | 
					                [displayGrid]="displayGrid"
 | 
				
			||||||
 | 
					                [colWidthInteger]="colWidthInteger"
 | 
				
			||||||
                [outerMargin]="outerMargin"
 | 
					                [outerMargin]="outerMargin"
 | 
				
			||||||
                [margin]="margin"
 | 
					                [margin]="margin"
 | 
				
			||||||
                [aliasController]="dashboardCtx.aliasController"
 | 
					                [aliasController]="dashboardCtx.aliasController"
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component';
 | 
				
			|||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
					import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
				
			||||||
import { ImagePipe } from '@shared/pipe/image.pipe';
 | 
					import { ImagePipe } from '@shared/pipe/image.pipe';
 | 
				
			||||||
import { map } from 'rxjs/operators';
 | 
					import { map } from 'rxjs/operators';
 | 
				
			||||||
 | 
					import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'tb-dashboard-layout',
 | 
					  selector: 'tb-dashboard-layout',
 | 
				
			||||||
@ -86,6 +87,18 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo
 | 
				
			|||||||
    return this.widgetEditMode || this.layoutCtx.gridSettings.isScada;
 | 
					    return this.widgetEditMode || this.layoutCtx.gridSettings.isScada;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get colWidthInteger(): boolean {
 | 
				
			||||||
 | 
					    return this.layoutCtx.gridSettings.isScada;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get columns(): number {
 | 
				
			||||||
 | 
					    return this.layoutCtx.gridSettings.minColumns || this.layoutCtx.gridSettings.columns || 24;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get displayGrid(): displayGrids {
 | 
				
			||||||
 | 
					    return this.layoutCtx.displayGrid || 'onDrag&Resize';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Input()
 | 
					  @Input()
 | 
				
			||||||
  dashboardCtx: DashboardContext;
 | 
					  dashboardCtx: DashboardContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					<!--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Copyright © 2016-2024 The Thingsboard Authors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					    you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					    You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					    distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					    See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					    limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					<form (ngSubmit)="move()">
 | 
				
			||||||
 | 
					  <mat-toolbar color="primary">
 | 
				
			||||||
 | 
					    <h2 translate>dashboard.move-all-widgets</h2>
 | 
				
			||||||
 | 
					    <span fxFlex></span>
 | 
				
			||||||
 | 
					    <button mat-icon-button
 | 
				
			||||||
 | 
					            (click)="cancel()"
 | 
				
			||||||
 | 
					            type="button">
 | 
				
			||||||
 | 
					      <mat-icon class="material-icons">close</mat-icon>
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					  </mat-toolbar>
 | 
				
			||||||
 | 
					  <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
				
			||||||
 | 
					  </mat-progress-bar>
 | 
				
			||||||
 | 
					  <div mat-dialog-content class="tb-form-panel no-border no-padding" [formGroup]="moveWidgetsFormGroup">
 | 
				
			||||||
 | 
					    <div class="tb-form-row space-between column-xs">
 | 
				
			||||||
 | 
					      <div translate>dashboard.move-by</div>
 | 
				
			||||||
 | 
					      <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
 | 
				
			||||||
 | 
					        <mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
 | 
				
			||||||
 | 
					          <input required matInput formControlName="cols"
 | 
				
			||||||
 | 
					                 type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
 | 
				
			||||||
 | 
					          <span translate matSuffix>dashboard.cols</span>
 | 
				
			||||||
 | 
					        </mat-form-field>
 | 
				
			||||||
 | 
					        <mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
 | 
				
			||||||
 | 
					          <input required matInput formControlName="rows"
 | 
				
			||||||
 | 
					                 type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
 | 
				
			||||||
 | 
					          <span translate matSuffix>dashboard.rows</span>
 | 
				
			||||||
 | 
					        </mat-form-field>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <div mat-dialog-actions fxLayoutAlign="end center">
 | 
				
			||||||
 | 
					    <button mat-button color="primary"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
 | 
					            [disabled]="(isLoading$ | async)"
 | 
				
			||||||
 | 
					            (click)="cancel()" cdkFocusInitial>
 | 
				
			||||||
 | 
					      {{ 'action.cancel' | translate }}
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					    <button mat-raised-button color="primary"
 | 
				
			||||||
 | 
					            type="submit"
 | 
				
			||||||
 | 
					            [disabled]="(isLoading$ | async) || moveWidgetsFormGroup.invalid || !moveWidgetsFormGroup.dirty">
 | 
				
			||||||
 | 
					      {{ 'action.move' | translate }}
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Copyright © 2016-2024 The Thingsboard Authors
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					/// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					/// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					///     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					/// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					/// limitations under the License.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component } from '@angular/core';
 | 
				
			||||||
 | 
					import { MatDialog, MatDialogRef } from '@angular/material/dialog';
 | 
				
			||||||
 | 
					import { Store } from '@ngrx/store';
 | 
				
			||||||
 | 
					import { AppState } from '@core/core.state';
 | 
				
			||||||
 | 
					import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
 | 
				
			||||||
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { DialogComponent } from '@app/shared/components/dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface MoveWidgetsDialogResult {
 | 
				
			||||||
 | 
					  cols: number;
 | 
				
			||||||
 | 
					  rows: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'tb-move-widgets-dialog',
 | 
				
			||||||
 | 
					  templateUrl: './move-widgets-dialog.component.html',
 | 
				
			||||||
 | 
					  providers: [],
 | 
				
			||||||
 | 
					  styleUrls: []
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class MoveWidgetsDialogComponent extends DialogComponent<MoveWidgetsDialogComponent, MoveWidgetsDialogResult> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moveWidgetsFormGroup: UntypedFormGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(protected store: Store<AppState>,
 | 
				
			||||||
 | 
					              protected router: Router,
 | 
				
			||||||
 | 
					              protected dialogRef: MatDialogRef<MoveWidgetsDialogComponent, MoveWidgetsDialogResult>,
 | 
				
			||||||
 | 
					              private fb: UntypedFormBuilder,
 | 
				
			||||||
 | 
					              private dialog: MatDialog) {
 | 
				
			||||||
 | 
					    super(store, router, dialogRef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.moveWidgetsFormGroup = this.fb.group({
 | 
				
			||||||
 | 
					        cols: [0, [Validators.required]],
 | 
				
			||||||
 | 
					        rows: [0, [Validators.required]]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cancel(): void {
 | 
				
			||||||
 | 
					    this.dialogRef.close(null);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  move(): void {
 | 
				
			||||||
 | 
					    const result: MoveWidgetsDialogResult = this.moveWidgetsFormGroup.value;
 | 
				
			||||||
 | 
					    this.dialogRef.close(result);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -90,6 +90,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
  @Input()
 | 
					  @Input()
 | 
				
			||||||
  columns: number;
 | 
					  columns: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Input()
 | 
				
			||||||
 | 
					  @coerceBoolean()
 | 
				
			||||||
 | 
					  colWidthInteger = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Input()
 | 
					  @Input()
 | 
				
			||||||
  @coerceBoolean()
 | 
					  @coerceBoolean()
 | 
				
			||||||
  setGridSize = false;
 | 
					  setGridSize = false;
 | 
				
			||||||
@ -256,15 +260,22 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
      itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
 | 
					      itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
 | 
				
			||||||
      itemInitCallback: (item, itemComponent) => {
 | 
					      itemInitCallback: (item, itemComponent) => {
 | 
				
			||||||
        (itemComponent.item as DashboardWidget).gridsterItemComponent = itemComponent;
 | 
					        (itemComponent.item as DashboardWidget).gridsterItemComponent = itemComponent;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      colWidthUpdateCallback: (colWidth) => {
 | 
				
			||||||
 | 
					        if (this.colWidthInteger) {
 | 
				
			||||||
 | 
					          return Math.floor(colWidth);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return colWidth;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.updateMobileOpts();
 | 
					    this.updateGridOpts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.breakpointObserverSubscription = this.breakpointObserver
 | 
					    this.breakpointObserverSubscription = this.breakpointObserver
 | 
				
			||||||
      .observe(MediaBreakpoints['gt-sm']).subscribe(
 | 
					      .observe(MediaBreakpoints['gt-sm']).subscribe(
 | 
				
			||||||
      () => {
 | 
					      () => {
 | 
				
			||||||
        this.updateMobileOpts();
 | 
					        this.updateGridOpts();
 | 
				
			||||||
        this.notifyGridsterOptionsChanged();
 | 
					        this.notifyGridsterOptionsChanged();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@ -291,20 +302,24 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnChanges(changes: SimpleChanges): void {
 | 
					  ngOnChanges(changes: SimpleChanges): void {
 | 
				
			||||||
    let updateMobileOpts = false;
 | 
					    let updateGridOpts = false;
 | 
				
			||||||
    let updateLayoutOpts = false;
 | 
					    let updateColumnOpts = false;
 | 
				
			||||||
    let updateEditingOpts = false;
 | 
					    let updateEditingOpts = false;
 | 
				
			||||||
 | 
					    let updateDisplayGridOpts = false;
 | 
				
			||||||
    let updateWidgets = false;
 | 
					    let updateWidgets = false;
 | 
				
			||||||
    let updateDashboardTimewindow = false;
 | 
					    let updateDashboardTimewindow = false;
 | 
				
			||||||
    for (const propName of Object.keys(changes)) {
 | 
					    for (const propName of Object.keys(changes)) {
 | 
				
			||||||
      const change = changes[propName];
 | 
					      const change = changes[propName];
 | 
				
			||||||
      if (!change.firstChange && change.currentValue !== change.previousValue) {
 | 
					      if (!change.firstChange && change.currentValue !== change.previousValue) {
 | 
				
			||||||
        if (['isMobile', 'isMobileDisabled', 'autofillHeight', 'mobileAutofillHeight', 'mobileRowHeight'].includes(propName)) {
 | 
					        if (['isMobile', 'isMobileDisabled', 'autofillHeight', 'mobileAutofillHeight',
 | 
				
			||||||
          updateMobileOpts = true;
 | 
					              'mobileRowHeight', 'colWidthInteger'].includes(propName)) {
 | 
				
			||||||
 | 
					          updateGridOpts = true;
 | 
				
			||||||
        } else if (['outerMargin', 'margin', 'columns'].includes(propName)) {
 | 
					        } else if (['outerMargin', 'margin', 'columns'].includes(propName)) {
 | 
				
			||||||
          updateLayoutOpts = true;
 | 
					          updateColumnOpts = true;
 | 
				
			||||||
        } else if (['isEdit', 'isEditingWidget'].includes(propName)) {
 | 
					        } else if (['isEdit', 'isEditingWidget'].includes(propName)) {
 | 
				
			||||||
          updateEditingOpts = true;
 | 
					          updateEditingOpts = true;
 | 
				
			||||||
 | 
					        } else if (propName === 'displayGrid') {
 | 
				
			||||||
 | 
					          updateDisplayGridOpts = true;
 | 
				
			||||||
        } else if (['widgets', 'widgetLayouts'].includes(propName)) {
 | 
					        } else if (['widgets', 'widgetLayouts'].includes(propName)) {
 | 
				
			||||||
          updateWidgets = true;
 | 
					          updateWidgets = true;
 | 
				
			||||||
        } else if (propName === 'dashboardTimewindow') {
 | 
					        } else if (propName === 'dashboardTimewindow') {
 | 
				
			||||||
@ -318,16 +333,19 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
      this.dashboardTimewindowChangedSubject.next(this.dashboardTimewindow);
 | 
					      this.dashboardTimewindowChangedSubject.next(this.dashboardTimewindow);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (updateLayoutOpts) {
 | 
					    if (updateColumnOpts) {
 | 
				
			||||||
      this.updateLayoutOpts();
 | 
					      this.updateColumnOpts();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (updateMobileOpts) {
 | 
					    if (updateGridOpts) {
 | 
				
			||||||
      this.updateMobileOpts();
 | 
					      this.updateGridOpts();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (updateEditingOpts) {
 | 
					    if (updateEditingOpts) {
 | 
				
			||||||
      this.updateEditingOpts();
 | 
					      this.updateEditingOpts();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (updateMobileOpts || updateLayoutOpts || updateEditingOpts) {
 | 
					    if (updateDisplayGridOpts) {
 | 
				
			||||||
 | 
					      this.updateDisplayGridOpts();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (updateGridOpts || updateColumnOpts || updateEditingOpts || updateDisplayGridOpts) {
 | 
				
			||||||
      this.notifyGridsterOptionsChanged();
 | 
					      this.notifyGridsterOptionsChanged();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -544,7 +562,15 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private updateMobileOpts(parentHeight?: number) {
 | 
					  private onGridsterParentResize() {
 | 
				
			||||||
 | 
					    const parentHeight = this.gridster.el.offsetHeight;
 | 
				
			||||||
 | 
					    if (this.isMobileSize && this.mobileAutofillHeight && parentHeight) {
 | 
				
			||||||
 | 
					      this.updateGridOpts(parentHeight);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.notifyGridsterOptionsChanged();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private updateGridOpts(parentHeight?: number) {
 | 
				
			||||||
    let updateWidgetRowsAndSort = false;
 | 
					    let updateWidgetRowsAndSort = false;
 | 
				
			||||||
    const isMobileSize = this.checkIsMobileSize();
 | 
					    const isMobileSize = this.checkIsMobileSize();
 | 
				
			||||||
    if (this.isMobileSize !== isMobileSize) {
 | 
					    if (this.isMobileSize !== isMobileSize) {
 | 
				
			||||||
@ -568,15 +594,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private onGridsterParentResize() {
 | 
					  private updateColumnOpts() {
 | 
				
			||||||
    const parentHeight = this.gridster.el.offsetHeight;
 | 
					 | 
				
			||||||
    if (this.isMobileSize && this.mobileAutofillHeight && parentHeight) {
 | 
					 | 
				
			||||||
      this.updateMobileOpts(parentHeight);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    this.notifyGridsterOptionsChanged();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private updateLayoutOpts() {
 | 
					 | 
				
			||||||
    this.gridsterOpts.minCols = this.columns ? this.columns : 24;
 | 
					    this.gridsterOpts.minCols = this.columns ? this.columns : 24;
 | 
				
			||||||
    this.gridsterOpts.outerMargin = isDefined(this.outerMargin) ? this.outerMargin : true;
 | 
					    this.gridsterOpts.outerMargin = isDefined(this.outerMargin) ? this.outerMargin : true;
 | 
				
			||||||
    this.gridsterOpts.margin = isDefined(this.margin) ? this.margin : 10;
 | 
					    this.gridsterOpts.margin = isDefined(this.margin) ? this.margin : 10;
 | 
				
			||||||
@ -587,6 +605,10 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
 | 
				
			|||||||
    this.gridsterOpts.draggable.enabled = this.isEdit && !this.isEditingWidget;
 | 
					    this.gridsterOpts.draggable.enabled = this.isEdit && !this.isEditingWidget;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private updateDisplayGridOpts() {
 | 
				
			||||||
 | 
					    this.gridsterOpts.displayGrid = this.displayGrid;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public notifyGridsterOptionsChanged() {
 | 
					  public notifyGridsterOptionsChanged() {
 | 
				
			||||||
    if (!this.optionsChangeNotificationsPaused) {
 | 
					    if (!this.optionsChangeNotificationsPaused) {
 | 
				
			||||||
      if (this.gridster && this.gridster.options) {
 | 
					      if (this.gridster && this.gridster.options) {
 | 
				
			||||||
 | 
				
			|||||||
@ -174,6 +174,7 @@ import {
 | 
				
			|||||||
import { WidgetConfigComponentsModule } from '@home/components/widget/config/widget-config-components.module';
 | 
					import { WidgetConfigComponentsModule } from '@home/components/widget/config/widget-config-components.module';
 | 
				
			||||||
import { BasicWidgetConfigModule } from '@home/components/widget/config/basic/basic-widget-config.module';
 | 
					import { BasicWidgetConfigModule } from '@home/components/widget/config/basic/basic-widget-config.module';
 | 
				
			||||||
import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delete-timeseries-panel.component';
 | 
					import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delete-timeseries-panel.component';
 | 
				
			||||||
 | 
					import { MoveWidgetsDialogComponent } from '@home/components/dashboard-page/layout/move-widgets-dialog.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@NgModule({
 | 
					@NgModule({
 | 
				
			||||||
  declarations:
 | 
					  declarations:
 | 
				
			||||||
@ -287,6 +288,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
 | 
				
			|||||||
      EditWidgetComponent,
 | 
					      EditWidgetComponent,
 | 
				
			||||||
      DashboardWidgetSelectComponent,
 | 
					      DashboardWidgetSelectComponent,
 | 
				
			||||||
      AddWidgetDialogComponent,
 | 
					      AddWidgetDialogComponent,
 | 
				
			||||||
 | 
					      MoveWidgetsDialogComponent,
 | 
				
			||||||
      ManageDashboardLayoutsDialogComponent,
 | 
					      ManageDashboardLayoutsDialogComponent,
 | 
				
			||||||
      DashboardSettingsDialogComponent,
 | 
					      DashboardSettingsDialogComponent,
 | 
				
			||||||
      ManageDashboardStatesDialogComponent,
 | 
					      ManageDashboardStatesDialogComponent,
 | 
				
			||||||
@ -419,6 +421,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
 | 
				
			|||||||
    EditWidgetComponent,
 | 
					    EditWidgetComponent,
 | 
				
			||||||
    DashboardWidgetSelectComponent,
 | 
					    DashboardWidgetSelectComponent,
 | 
				
			||||||
    AddWidgetDialogComponent,
 | 
					    AddWidgetDialogComponent,
 | 
				
			||||||
 | 
					    MoveWidgetsDialogComponent,
 | 
				
			||||||
    ManageDashboardLayoutsDialogComponent,
 | 
					    ManageDashboardLayoutsDialogComponent,
 | 
				
			||||||
    DashboardSettingsDialogComponent,
 | 
					    DashboardSettingsDialogComponent,
 | 
				
			||||||
    ManageDashboardStatesDialogComponent,
 | 
					    ManageDashboardStatesDialogComponent,
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,7 @@ export interface WidgetLayouts {
 | 
				
			|||||||
export interface GridSettings {
 | 
					export interface GridSettings {
 | 
				
			||||||
  backgroundColor?: string;
 | 
					  backgroundColor?: string;
 | 
				
			||||||
  columns?: number;
 | 
					  columns?: number;
 | 
				
			||||||
 | 
					  minColumns?: number;
 | 
				
			||||||
  margin?: number;
 | 
					  margin?: number;
 | 
				
			||||||
  outerMargin?: boolean;
 | 
					  outerMargin?: boolean;
 | 
				
			||||||
  backgroundSizeMode?: string;
 | 
					  backgroundSizeMode?: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1163,12 +1163,18 @@
 | 
				
			|||||||
        "maximum-upload-file-size": "Maximum upload file size: {{ size }}",
 | 
					        "maximum-upload-file-size": "Maximum upload file size: {{ size }}",
 | 
				
			||||||
        "cannot-upload-file": "Cannot upload file",
 | 
					        "cannot-upload-file": "Cannot upload file",
 | 
				
			||||||
        "settings": "Settings",
 | 
					        "settings": "Settings",
 | 
				
			||||||
 | 
					        "move-all-widgets": "Move all widgets",
 | 
				
			||||||
 | 
					        "move-by": "Move by",
 | 
				
			||||||
 | 
					        "cols": "cols",
 | 
				
			||||||
 | 
					        "rows": "rows",
 | 
				
			||||||
        "scada-layout": "SCADA layout",
 | 
					        "scada-layout": "SCADA layout",
 | 
				
			||||||
        "layout-settings": "Layout settings",
 | 
					        "layout-settings": "Layout settings",
 | 
				
			||||||
        "columns-count": "Columns count",
 | 
					        "columns-count": "Columns count",
 | 
				
			||||||
        "columns-count-required": "Columns count is required.",
 | 
					        "columns-count-required": "Columns count is required.",
 | 
				
			||||||
        "min-columns-count-message": "Only 10 minimum column count is allowed.",
 | 
					        "min-columns-count-message": "Only 10 minimum column count is allowed.",
 | 
				
			||||||
        "max-columns-count-message": "Only 1000 maximum column count is allowed.",
 | 
					        "max-columns-count-message": "Only 1000 maximum column count is allowed.",
 | 
				
			||||||
 | 
					        "min-layout-width": "Minimum layout width",
 | 
				
			||||||
 | 
					        "columns-suffix": "columns",
 | 
				
			||||||
        "widgets-margins": "Margin between widgets",
 | 
					        "widgets-margins": "Margin between widgets",
 | 
				
			||||||
        "margin-required": "Margin value is required.",
 | 
					        "margin-required": "Margin value is required.",
 | 
				
			||||||
        "min-margin-message": "Only 0 is allowed as minimum margin value.",
 | 
					        "min-margin-message": "Only 0 is allowed as minimum margin value.",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user