Merge branch 'rc'
This commit is contained in:
commit
609a68c991
@ -58,7 +58,7 @@ import {
|
|||||||
} from '@app/shared/models/dashboard.models';
|
} from '@app/shared/models/dashboard.models';
|
||||||
import { WINDOW } from '@core/services/window.service';
|
import { WINDOW } from '@core/services/window.service';
|
||||||
import { WindowMessage } from '@shared/models/window-message.model';
|
import { WindowMessage } from '@shared/models/window-message.model';
|
||||||
import { deepClone, guid, isDefined, isDefinedAndNotNull, isEqual, isNotEmptyStr } from '@app/core/utils';
|
import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils';
|
||||||
import {
|
import {
|
||||||
DashboardContext,
|
DashboardContext,
|
||||||
DashboardPageInitData,
|
DashboardPageInitData,
|
||||||
@ -119,7 +119,8 @@ import {
|
|||||||
} from '@home/components/dashboard-page/dashboard-settings-dialog.component';
|
} from '@home/components/dashboard-page/dashboard-settings-dialog.component';
|
||||||
import {
|
import {
|
||||||
ManageDashboardStatesDialogComponent,
|
ManageDashboardStatesDialogComponent,
|
||||||
ManageDashboardStatesDialogData
|
ManageDashboardStatesDialogData,
|
||||||
|
ManageDashboardStatesDialogResult
|
||||||
} from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component';
|
} from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component';
|
||||||
import { ImportExportService } from '@shared/import-export/import-export.service';
|
import { ImportExportService } from '@shared/import-export/import-export.service';
|
||||||
import { AuthState } from '@app/core/auth/auth.models';
|
import { AuthState } from '@app/core/auth/auth.models';
|
||||||
@ -964,17 +965,17 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
|
|||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
this.dialog.open<ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogData,
|
this.dialog.open<ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogData,
|
||||||
{states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>(ManageDashboardStatesDialogComponent, {
|
ManageDashboardStatesDialogResult>(ManageDashboardStatesDialogComponent, {
|
||||||
disableClose: true,
|
disableClose: true,
|
||||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
data: {
|
data: {
|
||||||
states: deepClone(this.dashboard.configuration.states),
|
states: deepClone(this.dashboard.configuration.states),
|
||||||
widgets: deepClone(this.dashboard.configuration.widgets) as {[id: string]: Widget}
|
widgets: this.dashboard.configuration.widgets as {[id: string]: Widget}
|
||||||
}
|
}
|
||||||
}).afterClosed().subscribe((result) => {
|
}).afterClosed().subscribe((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
if (!isEqual(result.widgets, this.dashboard.configuration.widgets)) {
|
if (result.addWidgets) {
|
||||||
this.dashboard.configuration.widgets = result.widgets;
|
Object.assign(this.dashboard.configuration.widgets, result.addWidgets);
|
||||||
}
|
}
|
||||||
if (result.states) {
|
if (result.states) {
|
||||||
this.updateStates(result.states);
|
this.updateStates(result.states);
|
||||||
|
|||||||
@ -15,143 +15,134 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<form [formGroup]="statesFormGroup" (ngSubmit)="save()" style="width: 750px;">
|
<mat-toolbar color="primary">
|
||||||
<mat-toolbar color="primary">
|
<h2 translate>dashboard.manage-states</h2>
|
||||||
<h2 translate>dashboard.manage-states</h2>
|
<span class="flex-1"></span>
|
||||||
<span class="flex-1"></span>
|
<button mat-icon-button
|
||||||
<button mat-icon-button
|
(click)="cancel()"
|
||||||
(click)="cancel()"
|
type="button">
|
||||||
type="button">
|
<mat-icon class="material-icons">close</mat-icon>
|
||||||
<mat-icon class="material-icons">close</mat-icon>
|
</button>
|
||||||
</button>
|
</mat-toolbar>
|
||||||
</mat-toolbar>
|
<div mat-dialog-content class="manage-dashboard-states">
|
||||||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
<div class="tb-entity-table-content flex flex-col">
|
||||||
</mat-progress-bar>
|
<mat-toolbar class="mat-mdc-table-toolbar" [class.!hidden]="textSearchMode">
|
||||||
<div mat-dialog-content>
|
<div class="mat-toolbar-tools">
|
||||||
<fieldset [disabled]="isLoading$ | async">
|
<span class="tb-entity-table-title" translate>dashboard.states</span>
|
||||||
<div class="manage-dashboard-states">
|
<span class="flex-1"></span>
|
||||||
<div class="tb-entity-table">
|
<button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
<div class="tb-entity-table-content flex flex-col">
|
type="button"
|
||||||
<mat-toolbar class="mat-mdc-table-toolbar" [class.!hidden]="textSearchMode">
|
(click)="addState($event)"
|
||||||
<div class="mat-toolbar-tools">
|
matTooltip="{{ 'dashboard.add-state' | translate }}"
|
||||||
<span class="tb-entity-table-title" translate>dashboard.states</span>
|
matTooltipPosition="above">
|
||||||
<span class="flex-1"></span>
|
<mat-icon>add</mat-icon>
|
||||||
<button mat-icon-button [disabled]="isLoading$ | async"
|
</button>
|
||||||
type="button"
|
<button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
|
||||||
(click)="addState($event)"
|
type="button"
|
||||||
matTooltip="{{ 'dashboard.add-state' | translate }}"
|
matTooltip="{{ 'action.search' | translate }}"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>search</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button [disabled]="isLoading$ | async" (click)="enterFilterMode()"
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'action.search' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>search</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</mat-toolbar>
|
|
||||||
<mat-toolbar class="mat-mdc-table-toolbar" [class.!hidden]="!textSearchMode">
|
|
||||||
<div class="mat-toolbar-tools">
|
|
||||||
<button mat-icon-button
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'dashboard.search-states' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>search</mat-icon>
|
|
||||||
</button>
|
|
||||||
<mat-form-field class="flex-1">
|
|
||||||
<mat-label> </mat-label>
|
|
||||||
<input #searchInput matInput
|
|
||||||
[(ngModel)]="pageLink.textSearch"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
placeholder="{{ 'dashboard.search-states' | translate }}"/>
|
|
||||||
</mat-form-field>
|
|
||||||
<button mat-icon-button (click)="exitFilterMode()"
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'action.close' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>close</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</mat-toolbar>
|
|
||||||
<div class="table-container">
|
|
||||||
<table mat-table [dataSource]="dataSource"
|
|
||||||
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
|
|
||||||
<ng-container matColumnDef="name">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 60%"> {{ 'dashboard.state-name' | translate }} </mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let state">
|
|
||||||
{{ state.name }}
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container matColumnDef="id">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 40%"> {{ 'dashboard.state-id' | translate }} </mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let state">
|
|
||||||
{{ state.id }}
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container matColumnDef="root">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 80px"> {{ 'dashboard.is-root-state' | translate }} </mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let state">
|
|
||||||
<mat-icon class="material-icons mat-icon">{{state.root ? 'check_box' : 'check_box_outline_blank'}}</mat-icon>
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container matColumnDef="actions" stickyEnd>
|
|
||||||
<mat-header-cell *matHeaderCellDef style="min-width: 120px; max-width: 120px; width: 120px">
|
|
||||||
</mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let state">
|
|
||||||
<div class="flex flex-1 flex-row">
|
|
||||||
<button mat-icon-button [disabled]="isLoading$ | async"
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'dashboard.edit-state' | translate }}"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
(click)="editState($event, state)">
|
|
||||||
<mat-icon>edit</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button [disabled]="isLoading$ | async"
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'dashboard.duplicate-state-action' | translate }}"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
(click)="duplicateState($event, state)">
|
|
||||||
<mat-icon>content_copy</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button [class.!hidden]="state.root" mat-icon-button [disabled]="isLoading$ | async"
|
|
||||||
type="button"
|
|
||||||
matTooltip="{{ 'dashboard.delete-state' | translate }}"
|
|
||||||
matTooltipPosition="above"
|
|
||||||
(click)="deleteState($event, state)">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
<mat-header-row class="mat-row-select" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
|
|
||||||
<mat-row class="mat-row-select"
|
|
||||||
*matRowDef="let state; columns: displayedColumns;"></mat-row>
|
|
||||||
</table>
|
|
||||||
<span [class.!hidden]="(dataSource.isEmpty() | async) === false"
|
|
||||||
class="no-data-found flex items-center justify-center" translate>{{ 'dashboard.no-states-text' }}</span>
|
|
||||||
</div>
|
|
||||||
<mat-divider></mat-divider>
|
|
||||||
<mat-paginator [length]="dataSource.total() | async"
|
|
||||||
[pageIndex]="pageLink.page"
|
|
||||||
[pageSize]="pageLink.pageSize"
|
|
||||||
[pageSizeOptions]="[5, 10, 15]"></mat-paginator>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</mat-toolbar>
|
||||||
|
<mat-toolbar class="mat-mdc-table-toolbar" [class.!hidden]="!textSearchMode">
|
||||||
|
<div class="mat-toolbar-tools">
|
||||||
|
<button mat-icon-button
|
||||||
|
type="button"
|
||||||
|
matTooltip="{{ 'dashboard.search-states' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon>search</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-form-field class="flex-1">
|
||||||
|
<mat-label> </mat-label>
|
||||||
|
<input #searchInput matInput
|
||||||
|
[(ngModel)]="pageLink.textSearch"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="{{ 'dashboard.search-states' | translate }}"/>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-icon-button (click)="exitFilterMode()"
|
||||||
|
type="button"
|
||||||
|
matTooltip="{{ 'action.close' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div class="table-container">
|
||||||
|
<table mat-table [dataSource]="dataSource"
|
||||||
|
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 60%"> {{ 'dashboard.state-name' | translate }} </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let state">
|
||||||
|
{{ state.name }}
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="id">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 40%"> {{ 'dashboard.state-id' | translate }} </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let state">
|
||||||
|
{{ state.id }}
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="root">
|
||||||
|
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 80px"> {{ 'dashboard.is-root-state' | translate }} </mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let state">
|
||||||
|
<mat-icon class="material-icons mat-icon">{{state.root ? 'check_box' : 'check_box_outline_blank'}}</mat-icon>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="actions" stickyEnd>
|
||||||
|
<mat-header-cell *matHeaderCellDef style="min-width: 120px; max-width: 120px; width: 120px">
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let state">
|
||||||
|
<div class="flex flex-1 flex-row">
|
||||||
|
<button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
type="button"
|
||||||
|
matTooltip="{{ 'dashboard.edit-state' | translate }}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
(click)="editState($event, state)">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
type="button"
|
||||||
|
matTooltip="{{ 'dashboard.duplicate-state-action' | translate }}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
(click)="duplicateState($event, state)">
|
||||||
|
<mat-icon>content_copy</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button [class.!hidden]="state.root" mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
type="button"
|
||||||
|
matTooltip="{{ 'dashboard.delete-state' | translate }}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
(click)="deleteState($event, state)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<mat-header-row class="mat-row-select" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
|
||||||
|
<mat-row class="mat-row-select"
|
||||||
|
*matRowDef="let state; columns: displayedColumns;"></mat-row>
|
||||||
|
</table>
|
||||||
|
<span [class.!hidden]="(dataSource.isEmpty() | async) === false"
|
||||||
|
class="no-data-found flex items-center justify-center" translate>{{ 'dashboard.no-states-text' }}</span>
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<mat-paginator [length]="dataSource.total() | async"
|
||||||
|
[pageIndex]="pageLink.page"
|
||||||
|
[pageSize]="pageLink.pageSize"
|
||||||
|
[pageSizeOptions]="[5, 10, 15]"></mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions class="flex items-center justify-end">
|
</div>
|
||||||
<button mat-button color="primary"
|
<div mat-dialog-actions class="flex items-center justify-end">
|
||||||
type="button"
|
<button mat-button color="primary"
|
||||||
[disabled]="(isLoading$ | async)"
|
type="button"
|
||||||
(click)="cancel()" cdkFocusInitial>
|
[disabled]="(isLoading$ | async)"
|
||||||
{{ 'action.cancel' | translate }}
|
(click)="cancel()" cdkFocusInitial>
|
||||||
</button>
|
{{ 'action.cancel' | translate }}
|
||||||
<button mat-raised-button color="primary"
|
</button>
|
||||||
type="submit"
|
<button mat-raised-button color="primary"
|
||||||
[disabled]="(isLoading$ | async) || statesFormGroup.invalid || !statesFormGroup.dirty">
|
type="submit"
|
||||||
{{ 'action.save' | translate }}
|
(click)="save()"
|
||||||
</button>
|
[disabled]="(isLoading$ | async) || !isDirty">
|
||||||
</div>
|
{{ 'action.save' | translate }}
|
||||||
</form>
|
</button>
|
||||||
|
</div>
|
||||||
|
|||||||
@ -13,27 +13,39 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
@import "../scss/constants";
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: min-content auto min-content;
|
||||||
|
|
||||||
.manage-dashboard-states {
|
.manage-dashboard-states {
|
||||||
.tb-entity-table {
|
.tb-entity-table-content {
|
||||||
.tb-entity-table-content {
|
width: 100%;
|
||||||
width: 100%;
|
height: 100%;
|
||||||
height: 100%;
|
background: #fff;
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
.tb-entity-table-title {
|
.tb-entity-table-title {
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-container {
|
.table-container {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media #{$mat-sm} {
|
||||||
|
min-width: 470px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media #{$mat-gt-sm} {
|
||||||
|
min-width: 750px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:host ::ng-deep {
|
:host ::ng-deep {
|
||||||
|
|||||||
@ -14,21 +14,10 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import {
|
import { AfterViewInit, Component, ElementRef, Inject, OnInit, SecurityContext, ViewChild } from '@angular/core';
|
||||||
AfterViewInit,
|
|
||||||
Component,
|
|
||||||
ElementRef,
|
|
||||||
Inject,
|
|
||||||
OnInit,
|
|
||||||
SecurityContext,
|
|
||||||
SkipSelf,
|
|
||||||
ViewChild
|
|
||||||
} from '@angular/core';
|
|
||||||
import { ErrorStateMatcher } from '@angular/material/core';
|
|
||||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { FormGroupDirective, NgForm, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } 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 { DashboardState } from '@app/shared/models/dashboard.models';
|
import { DashboardState } from '@app/shared/models/dashboard.models';
|
||||||
@ -44,7 +33,7 @@ import { fromEvent, merge } from 'rxjs';
|
|||||||
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { DialogService } from '@core/services/dialog.service';
|
import { DialogService } from '@core/services/dialog.service';
|
||||||
import { deepClone, isDefined } from '@core/utils';
|
import { deepClone, isDefined, isEqual } from '@core/utils';
|
||||||
import {
|
import {
|
||||||
DashboardStateDialogComponent,
|
DashboardStateDialogComponent,
|
||||||
DashboardStateDialogData
|
DashboardStateDialogData
|
||||||
@ -58,42 +47,42 @@ export interface ManageDashboardStatesDialogData {
|
|||||||
widgets: {[id: string]: Widget };
|
widgets: {[id: string]: Widget };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ManageDashboardStatesDialogResult {
|
||||||
|
states: {[id: string]: DashboardState };
|
||||||
|
addWidgets?: {[id: string]: Widget };
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-manage-dashboard-states-dialog',
|
selector: 'tb-manage-dashboard-states-dialog',
|
||||||
templateUrl: './manage-dashboard-states-dialog.component.html',
|
templateUrl: './manage-dashboard-states-dialog.component.html',
|
||||||
providers: [{provide: ErrorStateMatcher, useExisting: ManageDashboardStatesDialogComponent}],
|
|
||||||
styleUrls: ['./manage-dashboard-states-dialog.component.scss']
|
styleUrls: ['./manage-dashboard-states-dialog.component.scss']
|
||||||
})
|
})
|
||||||
export class ManageDashboardStatesDialogComponent
|
export class ManageDashboardStatesDialogComponent
|
||||||
extends DialogComponent<ManageDashboardStatesDialogComponent, {states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>
|
extends DialogComponent<ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogResult>
|
||||||
implements OnInit, ErrorStateMatcher, AfterViewInit {
|
implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
statesFormGroup: UntypedFormGroup;
|
@ViewChild('searchInput', {static: false}) searchInputField: ElementRef;
|
||||||
|
|
||||||
states: {[id: string]: DashboardState };
|
@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
|
||||||
widgets: {[id: string]: Widget};
|
@ViewChild(MatSort, {static: false}) sort: MatSort;
|
||||||
|
|
||||||
|
isDirty = false;
|
||||||
|
|
||||||
displayedColumns: string[];
|
displayedColumns: string[];
|
||||||
pageLink: PageLink;
|
pageLink: PageLink;
|
||||||
textSearchMode = false;
|
textSearchMode = false;
|
||||||
dataSource: DashboardStatesDatasource;
|
dataSource: DashboardStatesDatasource;
|
||||||
|
|
||||||
submitted = false;
|
private states: {[id: string]: DashboardState };
|
||||||
|
private widgets: {[id: string]: Widget};
|
||||||
|
|
||||||
stateNames: Set<string> = new Set<string>();
|
private stateNames: Set<string> = new Set<string>();
|
||||||
|
private addWidgets: {[id: string]: Widget} = {};
|
||||||
@ViewChild('searchInput') searchInputField: ElementRef;
|
|
||||||
|
|
||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: ManageDashboardStatesDialogData,
|
@Inject(MAT_DIALOG_DATA) public data: ManageDashboardStatesDialogData,
|
||||||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
public dialogRef: MatDialogRef<ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogResult>,
|
||||||
public dialogRef: MatDialogRef<ManageDashboardStatesDialogComponent,
|
|
||||||
{states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>,
|
|
||||||
private fb: UntypedFormBuilder,
|
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private dialogs: DialogService,
|
private dialogs: DialogService,
|
||||||
private utils: UtilsService,
|
private utils: UtilsService,
|
||||||
@ -103,7 +92,6 @@ export class ManageDashboardStatesDialogComponent
|
|||||||
|
|
||||||
this.states = this.data.states;
|
this.states = this.data.states;
|
||||||
this.widgets = this.data.widgets;
|
this.widgets = this.data.widgets;
|
||||||
this.statesFormGroup = this.fb.group({});
|
|
||||||
Object.values(this.states).forEach(value => this.stateNames.add(value.name));
|
Object.values(this.states).forEach(value => this.stateNames.add(value.name));
|
||||||
|
|
||||||
const sortOrder: SortOrder = { property: 'name', direction: Direction.ASC };
|
const sortOrder: SortOrder = { property: 'name', direction: Direction.ASC };
|
||||||
@ -258,77 +246,65 @@ export class ManageDashboardStatesDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
duplicateState($event: Event, state: DashboardStateInfo) {
|
duplicateState($event: Event, state: DashboardStateInfo) {
|
||||||
const originalState = state;
|
|
||||||
const newStateName = this.getNextDuplicatedName(state.name);
|
|
||||||
if (newStateName) {
|
|
||||||
const newStateId = newStateName.toLowerCase().replace(/\W/g, '_');
|
|
||||||
if (this.states[newStateId]) {
|
|
||||||
this.stateNames.add(newStateName);
|
|
||||||
this.duplicateState(null, state);
|
|
||||||
}
|
|
||||||
const duplicatedStates = deepClone(originalState);
|
|
||||||
const duplicatedWidgets = deepClone(this.widgets);
|
|
||||||
const mainWidgets = {};
|
|
||||||
const rightWidgets = {};
|
|
||||||
duplicatedStates.id = newStateId;
|
|
||||||
duplicatedStates.name = newStateName;
|
|
||||||
duplicatedStates.root = false;
|
|
||||||
this.stateNames.add(duplicatedStates.name);
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(duplicatedStates.layouts.main.widgets)) {
|
|
||||||
const guid = this.utils.guid();
|
|
||||||
mainWidgets[guid] = value;
|
|
||||||
duplicatedWidgets[guid] = this.widgets[key];
|
|
||||||
duplicatedWidgets[guid].id = guid;
|
|
||||||
}
|
|
||||||
duplicatedStates.layouts.main.widgets = mainWidgets;
|
|
||||||
|
|
||||||
if (isDefined(duplicatedStates.layouts?.right)) {
|
|
||||||
for (const [key, value] of Object.entries(duplicatedStates.layouts.right.widgets)) {
|
|
||||||
const guid = this.utils.guid();
|
|
||||||
rightWidgets[guid] = value;
|
|
||||||
duplicatedWidgets[guid] = this.widgets[key];
|
|
||||||
duplicatedWidgets[guid].id = guid;
|
|
||||||
}
|
|
||||||
duplicatedStates.layouts.right.widgets = rightWidgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.states[duplicatedStates.id] = duplicatedStates;
|
|
||||||
this.widgets = duplicatedWidgets;
|
|
||||||
this.onStatesUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getNextDuplicatedName(stateName: string): string {
|
|
||||||
const suffix = ` - ${this.translate.instant('action.copy')} `;
|
const suffix = ` - ${this.translate.instant('action.copy')} `;
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
while (++counter < Number.MAX_SAFE_INTEGER) {
|
const maxAttempts = 1000;
|
||||||
const newName = `${stateName}${suffix}${counter}`;
|
|
||||||
if (!this.stateNames.has(newName)) {
|
|
||||||
return newName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
while (counter++ < maxAttempts) {
|
||||||
|
const candidateName = `${state.name}${suffix}${counter}`;
|
||||||
|
if (this.stateNames.has(candidateName)) continue;
|
||||||
|
|
||||||
|
const candidateId = candidateName.toLowerCase().replace(/\W/g, '_');
|
||||||
|
if (this.states[candidateId]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicatedState = deepClone(state);
|
||||||
|
const mainWidgets = {};
|
||||||
|
const rightWidgets = {};
|
||||||
|
duplicatedState.id = candidateId;
|
||||||
|
duplicatedState.name = candidateName;
|
||||||
|
duplicatedState.root = false;
|
||||||
|
this.stateNames.add(duplicatedState.name);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(duplicatedState.layouts.main.widgets)) {
|
||||||
|
const guid = this.utils.guid();
|
||||||
|
mainWidgets[guid] = value;
|
||||||
|
this.addWidgets[guid] = deepClone(this.widgets[key] ?? this.addWidgets[key]);
|
||||||
|
this.addWidgets[guid].id = guid;
|
||||||
|
}
|
||||||
|
duplicatedState.layouts.main.widgets = mainWidgets;
|
||||||
|
|
||||||
|
if (isDefined(duplicatedState.layouts?.right)) {
|
||||||
|
for (const [key, value] of Object.entries(duplicatedState.layouts.right.widgets)) {
|
||||||
|
const guid = this.utils.guid();
|
||||||
|
rightWidgets[guid] = value;
|
||||||
|
this.addWidgets[guid] = deepClone(this.widgets[key] ?? this.addWidgets[key]);
|
||||||
|
this.addWidgets[guid].id = guid;
|
||||||
|
}
|
||||||
|
duplicatedState.layouts.right.widgets = rightWidgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.states[duplicatedState.id] = duplicatedState;
|
||||||
|
this.onStatesUpdated();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onStatesUpdated() {
|
private onStatesUpdated() {
|
||||||
this.statesFormGroup.markAsDirty();
|
this.isDirty = true;
|
||||||
this.updateData(true);
|
this.updateData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
|
||||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
|
||||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
|
||||||
return originalErrorState || customErrorState;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
cancel(): void {
|
||||||
this.dialogRef.close(null);
|
this.dialogRef.close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
save(): void {
|
save(): void {
|
||||||
this.submitted = true;
|
const result: ManageDashboardStatesDialogResult = {states: this.states};
|
||||||
this.dialogRef.close({ states: this.states, widgets: this.widgets });
|
if (!isEqual(this.addWidgets, {})) {
|
||||||
|
result.addWidgets = this.addWidgets;
|
||||||
|
}
|
||||||
|
this.dialogRef.close(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user