UI: Improved layout manage dialog (breakpoints table) and added new dialog add new breakpoint

This commit is contained in:
Vladyslav_Prykhodko 2024-08-09 18:37:54 +03:00
parent 38ecf3526b
commit 796e9c44ad
8 changed files with 260 additions and 220 deletions

View File

@ -1145,7 +1145,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
private updateLayout(layout: DashboardPageLayout, layoutInfo: DashboardLayoutInfo) { private updateLayout(layout: DashboardPageLayout, layoutInfo: DashboardLayoutInfo) {
layout.layoutCtx.layoutData = layoutInfo; layout.layoutCtx.layoutData = layoutInfo;
layout.layoutCtx.layoutDataChanged.next(); layout.layoutCtx.layoutDataChanged.next();
layout.layoutCtx.ctrl?.updatedCurrentBreakpoint(null, layout.show); layout.layoutCtx.ctrl?.updatedCurrentBreakpoint(this.isEdit ? layout.layoutCtx.breakpoint : null, layout.show);
this.updateLayoutSizes(); this.updateLayoutSizes();
} }

View File

@ -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.
-->
<mat-toolbar color="primary">
<h2 translate>layout.add-new-breakpoint</h2>
<span fxFlex></span>
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<div mat-dialog-content style="width: 400px">
<form [formGroup]="addBreakpointFormGroup">
<mat-form-field appearance="outline">
<mat-label translate>layout.breakpoint</mat-label>
<mat-select formControlName="newBreakpointId">
<mat-option *ngFor="let breakpoint of allowBreakpointIds" [value]="breakpoint">
{{ breakpoint }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-label translate>layout.copy-from</mat-label>
<mat-select formControlName="copyFrom">
<mat-option *ngFor="let breakpoint of selectedBreakpointIds" [value]="breakpoint">
{{ breakpoint }}
</mat-option>
</mat-select>
</mat-form-field>
</form>
</div>
<div mat-dialog-actions fxLayoutAlign="end center">
<button mat-button
color="primary"
type="button"
(click)="cancel()">
{{ 'action.cancel' | translate }}
</button>
<button mat-raised-button color="primary"
type="button"
(click)="save()"
[disabled]="addBreakpointFormGroup.invalid">
{{ 'action.add' | translate }}
</button>
</div>

View File

@ -0,0 +1,70 @@
///
/// 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, Inject } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component';
import { FormBuilder, FormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
export interface AddNewBreakpointDialogData {
allowBreakpointIds: string[];
selectedBreakpointIds: string[];
}
export interface AddNewBreakpointDialogResult {
newBreakpointId: string;
copyFrom: string;
}
@Component({
selector: 'add-new-breakpoint-dialog',
templateUrl: './add-new-breakpoint-dialog.component.html',
})
export class AddNewBreakpointDialogComponent extends DialogComponent<AddNewBreakpointDialogComponent, AddNewBreakpointDialogResult> {
addBreakpointFormGroup: FormGroup;
allowBreakpointIds = [];
selectedBreakpointIds = [];
constructor(protected store: Store<AppState>,
protected router: Router,
private fb: FormBuilder,
@Inject(MAT_DIALOG_DATA) private data: AddNewBreakpointDialogData,
protected dialogRef: MatDialogRef<AddNewBreakpointDialogComponent, AddNewBreakpointDialogResult>,) {
super(store, router, dialogRef);
this.allowBreakpointIds = data.allowBreakpointIds;
this.selectedBreakpointIds = data.selectedBreakpointIds;
this.addBreakpointFormGroup = this.fb.group({
newBreakpointId: [{value: this.allowBreakpointIds[0], disabled: this.allowBreakpointIds.length === 1}],
copyFrom: [{value: 'default', disabled: this.selectedBreakpointIds.length === 1}],
});
}
cancel(): void {
this.dialogRef.close(null);
}
save(): void {
this.dialogRef.close(this.addBreakpointFormGroup.getRawValue());
}
}

View File

@ -36,155 +36,58 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<!-- <div fxLayout="row" fxLayoutAlign="start center">--> <div *ngIf="!isDividerLayout; else dividerLayout" class="tb-form-panel stroked" style="width: 500px">
<!-- <mat-slide-toggle formControlName="right" color="accent">--> <div class="tb-form-table tb-layout-breakpoints">
<!-- {{ 'layout.divider' | translate }}--> <div class="tb-form-table-header no-padding-right">
<!-- </mat-slide-toggle>--> <div class="tb-form-table-header-cell tb-icon"></div>
<!-- </div>--> <div class="tb-form-table-header-cell tb-breakpoint" translate>layout.breakpoints</div>
<div *ngIf="!isDividerLayout; else dividerLayout" class="tb-form-panel no-padding no-border"> <div class="tb-form-table-header-cell tb-size" translate>layout.size</div>
<!-- <div class="tb-form-table tb-layout-breakpoints">--> <div class="tb-form-table-header-cell tb-actions"></div>
<!-- <div class="tb-form-table-header">--> </div>
<!-- <div class="tb-form-table-header-cell tb-icon-breakpoint"></div>--> <div class="tb-form-table-body no-gap">
<!-- <div class="tb-form-table-header-cell tb-devices-header">Devices</div>--> <ng-container *ngFor="let breakpoint of layoutBreakpoints; let last = last">
<!-- <div class="tb-form-table-header-cell tb-size-header">Size</div>--> <div class="tb-form-table-row no-padding-right">
<!-- <div class="tb-form-table-header-cell tb-actions-header"></div>--> <div class="tb-form-table-row-cell tb-icon">
<!-- </div>--> <tb-icon>{{ breakpoint.icon }}</tb-icon>
<!-- <div class="tb-form-table-body">--> </div>
<!-- <div class="tb-form-table-row">--> <div class="tb-form-table-row-cell tb-breakpoint">
<!-- <div class="tb-form-table-row-cell tb-icon-breakpoint"></div>--> {{ breakpoint.name }}
<!-- <div class="tb-form-table-row-cell tb-devices-header">Default</div>--> </div>
<!-- <div class="tb-form-table-row-cell tb-size-header"></div>--> <div class="tb-form-table-row-cell tb-size">
<!-- <div class="tb-form-table-row-cell tb-actions-header">--> {{ breakpoint.descriptionSize }}
<!-- <button mat-icon-button class="tb-mat-20"--> </div>
<!-- (click)="openLayoutSettings('main')"--> <div class="tb-form-table-row-cell-buttons tb-actions">
<!-- type="button" >-->
<!-- <mat-icon>settings</mat-icon>-->
<!-- </button>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="tb-form-table-row">-->
<!-- <div class="tb-form-table-row-cell tb-icon-breakpoint"></div>-->
<!-- <div class="tb-form-table-row-cell tb-devices-header">Md</div>-->
<!-- <div class="tb-form-table-row-cell tb-size-header"></div>-->
<!-- <div class="tb-form-table-row-cell tb-actions-header">-->
<!-- <button mat-icon-button class="tb-mat-20"-->
<!-- (click)="openLayoutSettings('main')"-->
<!-- type="button" >-->
<!-- <mat-icon>settings</mat-icon>-->
<!-- </button>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div class="table-container" style="width: 600px">
<table mat-table [dataSource]="dataSource">
<ng-container [matColumnDef]="'icon'">
<mat-header-cell *matHeaderCellDef [style]="{ minWidth: '48px', maxWidth: '48px', width: '48px', textAlign: 'center'}">
</mat-header-cell>
<mat-cell *matCellDef="let breakpoint" [style]="{ minWidth: '48px', maxWidth: '48px', width: '48px', textAlign: 'center'}">
<tb-icon>{{ breakpoint.icon }}</tb-icon>
</mat-cell>
</ng-container>
<ng-container [matColumnDef]="'name'">
<mat-header-cell *matHeaderCellDef style="width: 15%;min-width: 15%;max-width: 15%;padding-left:0">
Breakpoints
</mat-header-cell>
<mat-cell *matCellDef="let breakpoint" style="width: 15%;min-width: 15%;max-width: 15%;">
{{ breakpoint.name }}
</mat-cell>
</ng-container>
<ng-container [matColumnDef]="'descriptionSize'" style="width: 85%;min-width: 85%;max-width: 85%;">
<mat-header-cell *matHeaderCellDef>
Size
</mat-header-cell>
<mat-cell *matCellDef="let breakpoint" style="width: 85%;min-width: 85%;max-width: 85%;">
{{ breakpoint.descriptionSize }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef
[ngStyle.gt-md]="{ minWidth: '96px', maxWidth: '96px', width: '96px', textAlign: 'center'}">
</mat-header-cell>
<mat-cell *matCellDef="let breakpoint"
[ngStyle.gt-md]="{ minWidth: '96px', maxWidth: '96px', width: '96px'}">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-icon-button <button mat-icon-button
matTooltip="{{ 'dashboard.layout-settings' | translate }}"
matTooltipPosition="above"
(click)="openLayoutSettings('main', breakpoint.breakpoint)" (click)="openLayoutSettings('main', breakpoint.breakpoint)"
type="button" > type="button" >
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
</button> </button>
<button mat-icon-button <button mat-icon-button
matTooltip="{{ 'action.delete' | translate }}"
matTooltipPosition="above"
[disabled]="breakpoint.breakpoint === 'default'" [disabled]="breakpoint.breakpoint === 'default'"
(click)="deleteBreakpoint(breakpoint.breakpoint)" [class.tb-hidden]="breakpoint.breakpoint === 'default'"
(click)="deleteBreakpoint($event, breakpoint.breakpoint)"
type="button" > type="button" >
<tb-icon>delete</tb-icon> <tb-icon>delete</tb-icon>
</button> </button>
</div> </div>
<div fxHide fxShow.lt-lg fxFlex fxLayout="row" fxLayoutAlign="end"> </div>
<button mat-icon-button <mat-divider *ngIf="!last"></mat-divider>
(click)="$event.stopPropagation()"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<button mat-icon-button
(click)="openLayoutSettings('main', breakpoint.breakpoint)"
type="button" >
<mat-icon>settings</mat-icon>
</button>
<button mat-icon-button
(click)="openLayoutSettings('main')"
type="button" >
<tb-icon>delete</tb-icon>-->
</button>
</mat-menu>
</div>
</mat-cell>
</ng-container> </ng-container>
<mat-header-row class="mat-row-select" *matHeaderRowDef="['icon', 'name', 'descriptionSize', 'actions']; sticky: true"></mat-header-row> </div>
<mat-row *matRowDef="let breakpoint; columns: ['icon', 'name', 'descriptionSize', 'actions']"></mat-row>
</table>
</div> </div>
<button mat-button fxFlex class="tb-add-breakpoint-button" <button mat-button fxFlex class="tb-add-breakpoint-button"
matTooltip="Add breakpoint" matTooltip="{{ 'layout.add-new-breakpoint' | translate }}"
matTooltipPosition="above" matTooltipPosition="above"
color="primary"
type="button" type="button"
*ngIf="!addBreakpointMode" [disabled]="!allowBreakpointIds.length"
(click)="addBreakpoint()"> (click)="addBreakpoint()">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button> </button>
<div *ngIf="addBreakpointMode" class="tb-form-row space-between column-lt-md" [formGroup]="addBreakpointFormGroup">
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<div>Add breakpoint</div>
<mat-form-field fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="new">
<mat-option *ngFor="let breakpoint of allowBreakpointIds" [value]="breakpoint">
{{ breakpoint }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<div>Copy from</div>
<mat-form-field fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="copyFrom">
<mat-option *ngFor="let breakpoint of selectedBreakpointIds" [value]="breakpoint">
{{ breakpoint }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayoutGap="8px">
<button mat-icon-button class="tb-mat-20"
type="button" (click)="createdBreakPoint()">
<tb-icon>check</tb-icon>
</button>
<button mat-icon-button class="tb-mat-20"
type="button" (click)="addBreakpoint()">
<tb-icon>close</tb-icon>
</button>
</div>
</div>
</div> </div>
<ng-template #dividerLayout> <ng-template #dividerLayout>
<div fxLayout="column" fxLayoutAlign="start center" fxLayoutGap="20px"> <div fxLayout="column" fxLayoutAlign="start center" fxLayoutGap="20px">

View File

@ -125,27 +125,42 @@ $tb-warn: mat.get-color-from-palette(map-get($tb-theme, warn), text);
.tb-layout-breakpoints { .tb-layout-breakpoints {
.tb-form-table-header-cell, .tb-form-table-row-cell { .tb-form-table-header-cell, .tb-form-table-row-cell {
&.tb-icon-breakpoint { &.tb-icon {
width: 48px; width: 29px;
min-width: 48px; min-width: 29px;
max-width: 29px;
display: flex;
place-content: center;
} }
&.tb-devices-header, &.tb-size-header { &.tb-breakpoint {
flex: 1; flex: 1 1 15%;
min-width: 120px; width: 15%;
min-width: 100px;
} }
&.tb-actions-header { &.tb-size {
width: 80px; flex: 1 1 85%;
min-width: 80px; width: 85%;
min-width: 150px;
}
&.tb-actions {
width: 96pxpx;
min-width: 96px;
max-width: 96px;
display: flex; display: flex;
justify-content: end; justify-content: end;
} }
} }
.mat-divider {
margin-top: 6px;
margin-bottom: 6px;
}
} }
.tb-add-breakpoint-button { .tb-add-breakpoint-button {
cursor: pointer;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -154,7 +169,6 @@ $tb-warn: mat.get-color-from-palette(map-get($tb-theme, warn), text);
padding: 8px; padding: 8px;
border: 2px dashed rgba(0, 0, 0, 0.08); border: 2px dashed rgba(0, 0, 0, 0.08);
border-radius: 10px; border-radius: 10px;
min-height: 56px;
} }
} }

View File

@ -30,7 +30,6 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component'; import { DialogComponent } from '@app/shared/components/dialog.component';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
BreakpointInfo, BreakpointInfo,
@ -53,7 +52,10 @@ import {
} from '@home/components/dashboard-page/layout/layout.models'; } from '@home/components/dashboard-page/layout/layout.models';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { MatTooltip } from '@angular/material/tooltip'; import { MatTooltip } from '@angular/material/tooltip';
import { TbTableDatasource } from '@shared/components/table/table-datasource.abstract'; import {
AddNewBreakpointDialogComponent, AddNewBreakpointDialogData, AddNewBreakpointDialogResult
} from '@home/components/dashboard-page/layout/add-new-breakpoint-dialog.component';
import { DialogService } from '@core/services/dialog.service';
export interface ManageDashboardLayoutsDialogData { export interface ManageDashboardLayoutsDialogData {
layouts: DashboardStateLayouts; layouts: DashboardStateLayouts;
@ -79,7 +81,6 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
@ViewChild('tooltip') tooltip: MatTooltip; @ViewChild('tooltip') tooltip: MatTooltip;
layoutsFormGroup: UntypedFormGroup; layoutsFormGroup: UntypedFormGroup;
addBreakpointFormGroup: UntypedFormGroup;
layoutWidthType = LayoutWidthType; layoutWidthType = LayoutWidthType;
@ -90,19 +91,15 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
layoutTypes = layoutTypes; layoutTypes = layoutTypes;
layoutTypeTranslations = layoutTypeTranslationMap; layoutTypeTranslations = layoutTypeTranslationMap;
dataSource: DashboardLayoutDatasource; layoutBreakpoints: DashboardLayoutSettings[] = [];
addBreakpointMode = false;
private layoutBreakpoints: DashboardLayoutSettings[] = [];
private readonly layouts: DashboardStateLayouts; private readonly layouts: DashboardStateLayouts;
private subscriptions: Array<Subscription> = []; private subscriptions: Array<Subscription> = [];
private submitted = false; private submitted = false;
breakpoints: BreakpointInfo[]; private breakpoints: BreakpointInfo[];
breakpointsData: {[breakpointId in string]: BreakpointInfo} = {}; private breakpointsData: {[breakpointId in string]: BreakpointInfo} = {};
allowBreakpointIds = []; allowBreakpointIds = [];
selectedBreakpointIds = ['default']; selectedBreakpointIds = ['default'];
@ -113,14 +110,13 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
@SkipSelf() private errorStateMatcher: ErrorStateMatcher, @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
protected dialogRef: MatDialogRef<ManageDashboardLayoutsDialogComponent, DashboardStateLayouts>, protected dialogRef: MatDialogRef<ManageDashboardLayoutsDialogComponent, DashboardStateLayouts>,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private utils: UtilsService,
private dashboardUtils: DashboardUtilsService, private dashboardUtils: DashboardUtilsService,
private translate: TranslateService, private translate: TranslateService,
private dialog: MatDialog,) { private dialog: MatDialog,
private dialogs: DialogService) {
super(store, router, dialogRef); super(store, router, dialogRef);
this.layouts = this.data.layouts; this.layouts = this.data.layouts;
this.dataSource = new DashboardLayoutDatasource();
this.breakpoints = this.dashboardUtils.getListBreakpoint(); this.breakpoints = this.dashboardUtils.getListBreakpoint();
this.breakpoints.forEach((breakpoint) => { this.breakpoints.forEach((breakpoint) => {
@ -150,11 +146,6 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
} }
); );
this.addBreakpointFormGroup = this.fb.group({
new: [],
copyFrom: []
});
this.subscriptions.push( this.subscriptions.push(
this.layoutsFormGroup.get('type').valueChanges.subscribe( this.layoutsFormGroup.get('type').valueChanges.subscribe(
(value) => { (value) => {
@ -219,8 +210,6 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
this.allowBreakpointIds = Object.keys(this.breakpointsData) this.allowBreakpointIds = Object.keys(this.breakpointsData)
.filter((item) => !this.selectedBreakpointIds.includes(item)); .filter((item) => !this.selectedBreakpointIds.includes(item));
this.dataSource.loadData(this.layoutBreakpoints);
this.subscriptions.push( this.subscriptions.push(
this.layoutsFormGroup.get('sliderPercentage').valueChanges this.layoutsFormGroup.get('sliderPercentage').valueChanges
.subscribe( .subscribe(
@ -272,13 +261,9 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
return originalErrorState || customErrorState; return originalErrorState || customErrorState;
} }
openLayoutSettings(layoutId: DashboardLayoutId, breakpoint?: string) { openLayoutSettings(layoutId: DashboardLayoutId, breakpointId = 'default') {
let gridSettings; const layout = this.dashboardUtils.getDashboardLayoutConfig(this.layouts[layoutId], breakpointId);
if (isDefined(breakpoint) && breakpoint !== 'default') { const gridSettings = layout.gridSettings;
gridSettings = deepClone(this.layouts[layoutId].breakpoints[breakpoint].gridSettings);
} else {
gridSettings = deepClone(this.layouts[layoutId].gridSettings);
}
this.dialog.open<DashboardSettingsDialogComponent, DashboardSettingsDialogData, this.dialog.open<DashboardSettingsDialogComponent, DashboardSettingsDialogData,
DashboardSettingsDialogData>(DashboardSettingsDialogComponent, { DashboardSettingsDialogData>(DashboardSettingsDialogComponent, {
disableClose: true, disableClose: true,
@ -290,7 +275,7 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
} }
}).afterClosed().subscribe((data) => { }).afterClosed().subscribe((data) => {
if (data && data.gridSettings) { if (data && data.gridSettings) {
this.dashboardUtils.updateLayoutSettings(this.layouts[layoutId], data.gridSettings); this.dashboardUtils.updateLayoutSettings(layout, data.gridSettings);
this.layoutsFormGroup.markAsDirty(); this.layoutsFormGroup.markAsDirty();
} }
}); });
@ -438,51 +423,60 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
return this.layoutsFormGroup.get('layoutType').value === LayoutType.divider; return this.layoutsFormGroup.get('layoutType').value === LayoutType.divider;
} }
deleteBreakpoint(breakpointId: string): void {
delete this.layouts.main.breakpoints[breakpointId];
if (isEqual(this.layouts.main.breakpoints, {})) {
delete this.layouts.main.breakpoints;
}
this.layoutBreakpoints = this.layoutBreakpoints.filter((item) => item.breakpoint !== breakpointId);
this.allowBreakpointIds.push(breakpointId);
this.selectedBreakpointIds = this.selectedBreakpointIds.filter((item) => item !== breakpointId);
this.dataSource.loadData(this.layoutBreakpoints);
this.layoutsFormGroup.markAsDirty();
}
addBreakpoint() { addBreakpoint() {
this.addBreakpointMode = !this.addBreakpointMode; this.dialog.open<AddNewBreakpointDialogComponent, AddNewBreakpointDialogData,
if (this.addBreakpointMode) { AddNewBreakpointDialogResult>(AddNewBreakpointDialogComponent, {
this.addBreakpointFormGroup.reset({ disableClose: true,
new: this.allowBreakpointIds[0], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
copyFrom: 'default' data: {
}); allowBreakpointIds: this.allowBreakpointIds,
} selectedBreakpointIds: this.selectedBreakpointIds
}
}).afterClosed().subscribe((data) => {
if (data) {
this.createdNewBreakpoint(data.newBreakpointId, data.copyFrom);
this.layoutsFormGroup.markAsDirty();
}
});
} }
createdBreakPoint() { deleteBreakpoint($event: Event, breakpointId: string): void {
if ($event) {
$event.stopPropagation();
}
const title = this.translate.instant('layout.delete-breakpoint-title', {name: breakpointId});
const content = this.translate.instant('layout.delete-breakpoint-text');
this.dialogs.confirm(title, content, this.translate.instant('action.no'),
this.translate.instant('action.yes')).subscribe((res) => {
if (res) {
delete this.layouts.main.breakpoints[breakpointId];
if (isEqual(this.layouts.main.breakpoints, {})) {
delete this.layouts.main.breakpoints;
}
this.layoutBreakpoints = this.layoutBreakpoints.filter((item) => item.breakpoint !== breakpointId);
this.allowBreakpointIds.push(breakpointId);
this.selectedBreakpointIds = this.selectedBreakpointIds.filter((item) => item !== breakpointId);
this.layoutsFormGroup.markAsDirty();
}
}
);
}
private createdNewBreakpoint(newBreakpointId: string, copyFromBreakpointId: string): void {
const layoutConfig = this.layouts.main; const layoutConfig = this.layouts.main;
const newBreakpoint = this.addBreakpointFormGroup.value.new; const sourceLayout = copyFromBreakpointId === 'default' ? layoutConfig : layoutConfig.breakpoints[copyFromBreakpointId];
const sourceBreakpoint = this.addBreakpointFormGroup.value.copyFrom;
const sourceLayout = sourceBreakpoint === 'default' ? layoutConfig : layoutConfig.breakpoints[sourceBreakpoint];
if (!layoutConfig.breakpoints) { if (!layoutConfig.breakpoints) {
layoutConfig.breakpoints = {}; layoutConfig.breakpoints = {};
} }
layoutConfig.breakpoints[newBreakpoint] = { layoutConfig.breakpoints[newBreakpointId] = {
gridSettings: deepClone(sourceLayout.gridSettings), gridSettings: deepClone(sourceLayout.gridSettings),
widgets: deepClone(sourceLayout.widgets), widgets: deepClone(sourceLayout.widgets),
}; };
this.selectedBreakpointIds.push(newBreakpoint); this.selectedBreakpointIds.push(newBreakpointId);
this.allowBreakpointIds = this.allowBreakpointIds.filter((item) => item !== newBreakpoint); this.allowBreakpointIds = this.allowBreakpointIds.filter((item) => item !== newBreakpointId);
this.addLayoutConfiguration(newBreakpoint); this.addLayoutConfiguration(newBreakpointId);
this.dataSource.loadData(this.layoutBreakpoints);
this.addBreakpointMode = false;
this.layoutsFormGroup.markAsDirty();
} }
private addLayoutConfiguration(breakpointId: string) { private addLayoutConfiguration(breakpointId: string) {
@ -499,21 +493,8 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
private createDescriptionSize(breakpointId: string): string { private createDescriptionSize(breakpointId: string): string {
const currentData = this.breakpointsData[breakpointId]; const currentData = this.breakpointsData[breakpointId];
const minStr = isDefined(currentData.minWidth) ? `min-width: ${currentData.minWidth}px` : ''; const minStr = isDefined(currentData.minWidth) ? `min ${currentData.minWidth}px` : '';
const maxStr = isDefined(currentData.maxWidth) ? `min-width: ${currentData.maxWidth}px` : ''; const maxStr = isDefined(currentData.maxWidth) ? `max ${currentData.maxWidth}px` : '';
return minStr && maxStr ? `${minStr} and ${maxStr}` : `${minStr}${maxStr}`; return minStr && maxStr ? `${minStr} - ${maxStr}` : `${minStr}${maxStr}`;
}
}
export class DashboardLayoutDatasource extends TbTableDatasource<DashboardLayoutSettings> {
constructor() {
super();
}
connect() {
if (this.dataSubject.isStopped) {
this.dataSubject.isStopped = false;
}
return this.dataSubject.asObservable();
} }
} }

View File

@ -114,6 +114,9 @@ import { EditWidgetComponent } from '@home/components/dashboard-page/edit-widget
import { DashboardWidgetSelectComponent } from '@home/components/dashboard-page/dashboard-widget-select.component'; import { DashboardWidgetSelectComponent } from '@home/components/dashboard-page/dashboard-widget-select.component';
import { AddWidgetDialogComponent } from '@home/components/dashboard-page/add-widget-dialog.component'; import { AddWidgetDialogComponent } from '@home/components/dashboard-page/add-widget-dialog.component';
import { ManageDashboardLayoutsDialogComponent } from '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component'; import { ManageDashboardLayoutsDialogComponent } from '@home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component';
import {
AddNewBreakpointDialogComponent
} from '@home/components/dashboard-page/layout/add-new-breakpoint-dialog.component';
import { DashboardSettingsDialogComponent } from '@home/components/dashboard-page/dashboard-settings-dialog.component'; import { DashboardSettingsDialogComponent } from '@home/components/dashboard-page/dashboard-settings-dialog.component';
import { ManageDashboardStatesDialogComponent } from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component'; import { ManageDashboardStatesDialogComponent } from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component';
import { DashboardStateDialogComponent } from '@home/components/dashboard-page/states/dashboard-state-dialog.component'; import { DashboardStateDialogComponent } from '@home/components/dashboard-page/states/dashboard-state-dialog.component';
@ -294,6 +297,7 @@ import {
AddWidgetDialogComponent, AddWidgetDialogComponent,
MoveWidgetsDialogComponent, MoveWidgetsDialogComponent,
ManageDashboardLayoutsDialogComponent, ManageDashboardLayoutsDialogComponent,
AddNewBreakpointDialogComponent,
DashboardSettingsDialogComponent, DashboardSettingsDialogComponent,
ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogComponent,
DashboardStateDialogComponent, DashboardStateDialogComponent,
@ -428,6 +432,7 @@ import {
AddWidgetDialogComponent, AddWidgetDialogComponent,
MoveWidgetsDialogComponent, MoveWidgetsDialogComponent,
ManageDashboardLayoutsDialogComponent, ManageDashboardLayoutsDialogComponent,
AddNewBreakpointDialogComponent,
DashboardSettingsDialogComponent, DashboardSettingsDialogComponent,
ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogComponent,
DashboardStateDialogComponent, DashboardStateDialogComponent,

View File

@ -3778,7 +3778,14 @@
"left-width-percentage-required": "Left percentage is required", "left-width-percentage-required": "Left percentage is required",
"divider": "Divider", "divider": "Divider",
"right-side": "Right side layout", "right-side": "Right side layout",
"left-side": "Left side layout" "left-side": "Left side layout",
"add-new-breakpoint": "Add new breakpoint",
"breakpoint": "Breakpoint",
"breakpoints": "Breakpoints",
"copy-from": "Copy from",
"size": "Size",
"delete-breakpoint-title": "Are you sure you want to delete the breakpoint '{{name}}'?",
"delete-breakpoint-text": "Please note, after confirmation, the breakpoint will become unrecoverable, and the settings will revert to the default breakpoint."
}, },
"legend": { "legend": {
"direction": "Direction", "direction": "Direction",