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;
|
||||
}
|
||||
const gridSettings = layout.gridSettings;
|
||||
if (!gridSettings.isScada) {
|
||||
let columns = 24;
|
||||
if (gridSettings && gridSettings.columns) {
|
||||
columns = gridSettings.columns;
|
||||
}
|
||||
columns = columns * layoutCount;
|
||||
if (columns !== originalColumns) {
|
||||
const ratio = columns / originalColumns;
|
||||
widgetLayout.sizeX *= ratio;
|
||||
widgetLayout.sizeY *= ratio;
|
||||
}
|
||||
let columns = 24;
|
||||
if (gridSettings && gridSettings.columns) {
|
||||
columns = gridSettings.columns;
|
||||
}
|
||||
columns = columns * layoutCount;
|
||||
if (columns !== originalColumns) {
|
||||
const ratio = columns / originalColumns;
|
||||
widgetLayout.sizeX *= ratio;
|
||||
widgetLayout.sizeY *= ratio;
|
||||
}
|
||||
|
||||
if (row > -1 && column > - 1) {
|
||||
@ -686,35 +684,32 @@ export class DashboardUtilsService {
|
||||
const columns = gridSettings.columns || 24;
|
||||
const ratio = columns / prevColumns;
|
||||
layout.gridSettings = gridSettings;
|
||||
if (!gridSettings.isScada) {
|
||||
let maxRow = 0;
|
||||
for (const w of Object.keys(layout.widgets)) {
|
||||
const widget = layout.widgets[w];
|
||||
if (!widget.sizeX) {
|
||||
widget.sizeX = 1;
|
||||
}
|
||||
if (!widget.sizeY) {
|
||||
widget.sizeY = 1;
|
||||
}
|
||||
maxRow = Math.max(maxRow, widget.row + widget.sizeY);
|
||||
for (const w of Object.keys(layout.widgets)) {
|
||||
const widget = layout.widgets[w];
|
||||
if (!widget.sizeX) {
|
||||
widget.sizeX = 1;
|
||||
}
|
||||
const newMaxRow = Math.round(maxRow * ratio);
|
||||
for (const w of Object.keys(layout.widgets)) {
|
||||
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;
|
||||
}
|
||||
if (!widget.sizeY) {
|
||||
widget.sizeY = 1;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
@ -150,6 +150,10 @@ import { LayoutFixedSize, LayoutWidthType } from '@home/components/dashboard-pag
|
||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||
import { ResizeObserver } from '@juggle/resize-observer';
|
||||
import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
|
||||
import {
|
||||
MoveWidgetsDialogComponent,
|
||||
MoveWidgetsDialogResult
|
||||
} from '@home/components/dashboard-page/layout/move-widgets-dialog.component';
|
||||
|
||||
// @dynamic
|
||||
@Component({
|
||||
@ -285,7 +289,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
|
||||
gridSettings: {},
|
||||
ignoreLoading: true,
|
||||
ctrl: null,
|
||||
dashboardCtrl: this
|
||||
dashboardCtrl: this,
|
||||
displayGrid: 'onDrag&Resize'
|
||||
}
|
||||
},
|
||||
right: {
|
||||
@ -297,7 +302,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
|
||||
gridSettings: {},
|
||||
ignoreLoading: true,
|
||||
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) {
|
||||
this.dashboardUtils.setLayouts(this.dashboard, this.dashboardCtx.state, newLayouts);
|
||||
this.updateLayouts();
|
||||
@ -1422,6 +1450,16 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
|
||||
shortcut: 'M-I'
|
||||
}
|
||||
);
|
||||
dashboardContextActions.push(
|
||||
{
|
||||
action: ($event) => {
|
||||
this.moveWidgets($event, layoutCtx.id);
|
||||
},
|
||||
enabled: true,
|
||||
value: 'dashboard.move-all-widgets',
|
||||
icon: 'open_with'
|
||||
}
|
||||
);
|
||||
}
|
||||
return dashboardContextActions;
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import { IAliasController, IStateController } from '@core/api/widget-api.models'
|
||||
import { ILayoutController } from './layout/layout.models';
|
||||
import { DashboardContextMenuItem, WidgetContextMenuItem } from '@home/models/dashboard-component.models';
|
||||
import { Observable } from 'rxjs';
|
||||
import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
|
||||
|
||||
export declare type DashboardPageScope = 'tenant' | 'customer';
|
||||
|
||||
@ -69,6 +70,7 @@ export interface DashboardPageLayoutContext {
|
||||
ctrl: ILayoutController;
|
||||
dashboardCtrl: IDashboardController;
|
||||
ignoreLoading: boolean;
|
||||
displayGrid: displayGrids;
|
||||
}
|
||||
|
||||
export interface DashboardPageLayout {
|
||||
|
||||
@ -114,8 +114,9 @@
|
||||
<div class="tb-form-panel-title" translate>dashboard.layout-settings</div>
|
||||
<div class="tb-form-row space-between">
|
||||
<div translate>dashboard.columns-count</div>
|
||||
<mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
|
||||
<input matInput formControlName="columns" type="number" min="10" max="1000" step="1"
|
||||
<mat-form-field *ngIf="!gridSettingsFormGroup.get('isScada').value"
|
||||
appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic">
|
||||
<input matInput formControlName="columns" type="number" min="10" max="1008" step="1"
|
||||
required
|
||||
placeholder="{{ 'widget-config.set' | translate }}">
|
||||
<mat-icon matSuffix
|
||||
@ -128,6 +129,32 @@
|
||||
warning
|
||||
</mat-icon>
|
||||
</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 *ngIf="!gridSettingsFormGroup.get('isScada').value" class="tb-form-row space-between">
|
||||
<div translate>dashboard.widgets-margins</div>
|
||||
|
||||
@ -54,6 +54,8 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
|
||||
|
||||
submitted = false;
|
||||
|
||||
scadaColumns: number[] = [];
|
||||
|
||||
private stateControllerTranslationMap = new Map<string, string>([
|
||||
['default', 'dashboard.state-controller-default'],
|
||||
]);
|
||||
@ -155,10 +157,17 @@ export class DashboardSettingsDialogComponent extends DialogComponent<DashboardS
|
||||
}
|
||||
|
||||
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;
|
||||
this.gridSettingsFormGroup = this.fb.group({
|
||||
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,
|
||||
[Validators.required, Validators.min(0), Validators.max(50)]],
|
||||
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('mobileAutoFillHeight').disable({emitEvent: false});
|
||||
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 {
|
||||
this.gridSettingsFormGroup.get('margin').enable();
|
||||
this.gridSettingsFormGroup.get('outerMargin').enable();
|
||||
|
||||
@ -41,7 +41,9 @@
|
||||
[backgroundImage]="backgroundImage$ | async"
|
||||
[widgets]="layoutCtx.widgets"
|
||||
[widgetLayouts]="layoutCtx.widgetLayouts"
|
||||
[columns]="layoutCtx.gridSettings.columns"
|
||||
[columns]="columns"
|
||||
[displayGrid]="displayGrid"
|
||||
[colWidthInteger]="colWidthInteger"
|
||||
[outerMargin]="outerMargin"
|
||||
[margin]="margin"
|
||||
[aliasController]="dashboardCtx.aliasController"
|
||||
|
||||
@ -36,6 +36,7 @@ import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component';
|
||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||
import { ImagePipe } from '@shared/pipe/image.pipe';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { displayGrids } from 'angular-gridster2/lib/gridsterConfig.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-dashboard-layout',
|
||||
@ -86,6 +87,18 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo
|
||||
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()
|
||||
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()
|
||||
columns: number;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
colWidthInteger = false;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
setGridSize = false;
|
||||
@ -256,15 +260,22 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
|
||||
itemInitCallback: (item, 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
|
||||
.observe(MediaBreakpoints['gt-sm']).subscribe(
|
||||
() => {
|
||||
this.updateMobileOpts();
|
||||
this.updateGridOpts();
|
||||
this.notifyGridsterOptionsChanged();
|
||||
}
|
||||
);
|
||||
@ -291,20 +302,24 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
let updateMobileOpts = false;
|
||||
let updateLayoutOpts = false;
|
||||
let updateGridOpts = false;
|
||||
let updateColumnOpts = false;
|
||||
let updateEditingOpts = false;
|
||||
let updateDisplayGridOpts = false;
|
||||
let updateWidgets = false;
|
||||
let updateDashboardTimewindow = false;
|
||||
for (const propName of Object.keys(changes)) {
|
||||
const change = changes[propName];
|
||||
if (!change.firstChange && change.currentValue !== change.previousValue) {
|
||||
if (['isMobile', 'isMobileDisabled', 'autofillHeight', 'mobileAutofillHeight', 'mobileRowHeight'].includes(propName)) {
|
||||
updateMobileOpts = true;
|
||||
if (['isMobile', 'isMobileDisabled', 'autofillHeight', 'mobileAutofillHeight',
|
||||
'mobileRowHeight', 'colWidthInteger'].includes(propName)) {
|
||||
updateGridOpts = true;
|
||||
} else if (['outerMargin', 'margin', 'columns'].includes(propName)) {
|
||||
updateLayoutOpts = true;
|
||||
updateColumnOpts = true;
|
||||
} else if (['isEdit', 'isEditingWidget'].includes(propName)) {
|
||||
updateEditingOpts = true;
|
||||
} else if (propName === 'displayGrid') {
|
||||
updateDisplayGridOpts = true;
|
||||
} else if (['widgets', 'widgetLayouts'].includes(propName)) {
|
||||
updateWidgets = true;
|
||||
} else if (propName === 'dashboardTimewindow') {
|
||||
@ -318,16 +333,19 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
this.dashboardTimewindowChangedSubject.next(this.dashboardTimewindow);
|
||||
}
|
||||
|
||||
if (updateLayoutOpts) {
|
||||
this.updateLayoutOpts();
|
||||
if (updateColumnOpts) {
|
||||
this.updateColumnOpts();
|
||||
}
|
||||
if (updateMobileOpts) {
|
||||
this.updateMobileOpts();
|
||||
if (updateGridOpts) {
|
||||
this.updateGridOpts();
|
||||
}
|
||||
if (updateEditingOpts) {
|
||||
this.updateEditingOpts();
|
||||
}
|
||||
if (updateMobileOpts || updateLayoutOpts || updateEditingOpts) {
|
||||
if (updateDisplayGridOpts) {
|
||||
this.updateDisplayGridOpts();
|
||||
}
|
||||
if (updateGridOpts || updateColumnOpts || updateEditingOpts || updateDisplayGridOpts) {
|
||||
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;
|
||||
const isMobileSize = this.checkIsMobileSize();
|
||||
if (this.isMobileSize !== isMobileSize) {
|
||||
@ -568,15 +594,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
|
||||
}
|
||||
}
|
||||
|
||||
private onGridsterParentResize() {
|
||||
const parentHeight = this.gridster.el.offsetHeight;
|
||||
if (this.isMobileSize && this.mobileAutofillHeight && parentHeight) {
|
||||
this.updateMobileOpts(parentHeight);
|
||||
}
|
||||
this.notifyGridsterOptionsChanged();
|
||||
}
|
||||
|
||||
private updateLayoutOpts() {
|
||||
private updateColumnOpts() {
|
||||
this.gridsterOpts.minCols = this.columns ? this.columns : 24;
|
||||
this.gridsterOpts.outerMargin = isDefined(this.outerMargin) ? this.outerMargin : true;
|
||||
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;
|
||||
}
|
||||
|
||||
private updateDisplayGridOpts() {
|
||||
this.gridsterOpts.displayGrid = this.displayGrid;
|
||||
}
|
||||
|
||||
public notifyGridsterOptionsChanged() {
|
||||
if (!this.optionsChangeNotificationsPaused) {
|
||||
if (this.gridster && this.gridster.options) {
|
||||
|
||||
@ -174,6 +174,7 @@ import {
|
||||
import { WidgetConfigComponentsModule } from '@home/components/widget/config/widget-config-components.module';
|
||||
import { BasicWidgetConfigModule } from '@home/components/widget/config/basic/basic-widget-config.module';
|
||||
import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delete-timeseries-panel.component';
|
||||
import { MoveWidgetsDialogComponent } from '@home/components/dashboard-page/layout/move-widgets-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations:
|
||||
@ -287,6 +288,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
|
||||
EditWidgetComponent,
|
||||
DashboardWidgetSelectComponent,
|
||||
AddWidgetDialogComponent,
|
||||
MoveWidgetsDialogComponent,
|
||||
ManageDashboardLayoutsDialogComponent,
|
||||
DashboardSettingsDialogComponent,
|
||||
ManageDashboardStatesDialogComponent,
|
||||
@ -419,6 +421,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet
|
||||
EditWidgetComponent,
|
||||
DashboardWidgetSelectComponent,
|
||||
AddWidgetDialogComponent,
|
||||
MoveWidgetsDialogComponent,
|
||||
ManageDashboardLayoutsDialogComponent,
|
||||
DashboardSettingsDialogComponent,
|
||||
ManageDashboardStatesDialogComponent,
|
||||
|
||||
@ -52,6 +52,7 @@ export interface WidgetLayouts {
|
||||
export interface GridSettings {
|
||||
backgroundColor?: string;
|
||||
columns?: number;
|
||||
minColumns?: number;
|
||||
margin?: number;
|
||||
outerMargin?: boolean;
|
||||
backgroundSizeMode?: string;
|
||||
|
||||
@ -1163,12 +1163,18 @@
|
||||
"maximum-upload-file-size": "Maximum upload file size: {{ size }}",
|
||||
"cannot-upload-file": "Cannot upload file",
|
||||
"settings": "Settings",
|
||||
"move-all-widgets": "Move all widgets",
|
||||
"move-by": "Move by",
|
||||
"cols": "cols",
|
||||
"rows": "rows",
|
||||
"scada-layout": "SCADA layout",
|
||||
"layout-settings": "Layout settings",
|
||||
"columns-count": "Columns count",
|
||||
"columns-count-required": "Columns count is required.",
|
||||
"min-columns-count-message": "Only 10 minimum 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",
|
||||
"margin-required": "Margin value is required.",
|
||||
"min-margin-message": "Only 0 is allowed as minimum margin value.",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user