Dashboard page fixes and improvements

This commit is contained in:
Igor Kulikov 2020-04-29 11:33:42 +03:00
parent 969c03637d
commit 534db078ff
8 changed files with 92 additions and 92 deletions

View File

@ -17,7 +17,7 @@
--> -->
<div fxLayout="column" class="mat-content mat-padding"> <div fxLayout="column" class="mat-content mat-padding">
<div fxLayout="row" *ngFor="let alias of entityAliasesInfo | keyvalue"> <div fxLayout="row" *ngFor="let alias of entityAliasesInfo | keyvalue">
<mat-form-field> <mat-form-field fxFlex>
<mat-label>{{alias.value.alias}}</mat-label> <mat-label>{{alias.value.alias}}</mat-label>
<mat-select [(ngModel)]="alias.value.selectedId" <mat-select [(ngModel)]="alias.value.selectedId"
(ngModelChange)="currentAliasEntityChanged(alias.key, alias.value.selectedId)"> (ngModelChange)="currentAliasEntityChanged(alias.key, alias.value.selectedId)">

View File

@ -22,6 +22,7 @@ export const ALIASES_ENTITY_SELECT_PANEL_DATA = new InjectionToken<any>('Aliases
export interface AliasesEntitySelectPanelData { export interface AliasesEntitySelectPanelData {
aliasController: IAliasController; aliasController: IAliasController;
entityAliasesInfo: {[aliasId: string]: AliasInfo};
} }
@Component({ @Component({
@ -31,18 +32,10 @@ export interface AliasesEntitySelectPanelData {
}) })
export class AliasesEntitySelectPanelComponent { export class AliasesEntitySelectPanelComponent {
entityAliasesInfo: {[aliasId: string]: AliasInfo} = {}; entityAliasesInfo: {[aliasId: string]: AliasInfo};
constructor(@Inject(ALIASES_ENTITY_SELECT_PANEL_DATA) public data: AliasesEntitySelectPanelData) { constructor(@Inject(ALIASES_ENTITY_SELECT_PANEL_DATA) public data: AliasesEntitySelectPanelData) {
const allEntityAliases = this.data.aliasController.getEntityAliases(); this.entityAliasesInfo = this.data.entityAliasesInfo;
for (const aliasId of Object.keys(allEntityAliases)) {
const aliasInfo = this.data.aliasController.getInstantAliasInfo(aliasId);
if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity
&& aliasInfo.resolvedEntities.length > 1) {
this.entityAliasesInfo[aliasId] = deepClone(aliasInfo);
this.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;
}
}
} }
public currentAliasEntityChanged(aliasId: string, selectedId: string) { public currentAliasEntityChanged(aliasId: string, selectedId: string) {

View File

@ -19,13 +19,13 @@
<button mat-icon-button <button mat-icon-button
cdkOverlayOrigin #aliasEntitySelectPanelOrigin="cdkOverlayOrigin" cdkOverlayOrigin #aliasEntitySelectPanelOrigin="cdkOverlayOrigin"
(click)="openEditMode()" (click)="openEditMode()"
matTooltip="{{ 'entity.select-entities' | translate }}" matTooltip="{{ hasSelectableAliasEntities ? ('entity.select-entities' | translate) : '' }}"
[matTooltipPosition]="tooltipPosition"> [matTooltipPosition]="tooltipPosition">
<mat-icon class="material-icons">devices_other</mat-icon> <mat-icon class="material-icons">devices_other</mat-icon>
</button> </button>
<span fxHide.lt-lg <span fxHide.lt-lg
(click)="openEditMode()" (click)="openEditMode()"
matTooltip="{{ 'entity.select-entities' | translate }}" matTooltip="{{ hasSelectableAliasEntities ? ('entity.select-entities' | translate) : '' }}"
[matTooltipPosition]="tooltipPosition"> [matTooltipPosition]="tooltipPosition">
{{displayValue}} {{displayValue}}
</span> </span>

View File

@ -14,23 +14,21 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; import { Component, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { TooltipPosition } from '@angular/material/tooltip'; import { TooltipPosition } from '@angular/material/tooltip';
import { IAliasController } from '@core/api/widget-api.models'; import { AliasInfo, IAliasController } from '@core/api/widget-api.models';
import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { BreakpointObserver } from '@angular/cdk/layout'; import { BreakpointObserver } from '@angular/cdk/layout';
import { DOCUMENT } from '@angular/common';
import { WINDOW } from '@core/services/window.service';
import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; import { ComponentPortal, PortalInjector } from '@angular/cdk/portal';
import { import {
ALIASES_ENTITY_SELECT_PANEL_DATA, ALIASES_ENTITY_SELECT_PANEL_DATA,
AliasesEntitySelectPanelComponent, AliasesEntitySelectPanelComponent,
AliasesEntitySelectPanelData AliasesEntitySelectPanelData
} from './aliases-entity-select-panel.component'; } from './aliases-entity-select-panel.component';
import { deepClone } from '@core/utils';
// @dynamic
@Component({ @Component({
selector: 'tb-aliases-entity-select', selector: 'tb-aliases-entity-select',
templateUrl: './aliases-entity-select.component.html', templateUrl: './aliases-entity-select.component.html',
@ -38,8 +36,17 @@ import {
}) })
export class AliasesEntitySelectComponent implements OnInit, OnDestroy { export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
aliasControllerValue: IAliasController;
@Input() @Input()
aliasController: IAliasController; set aliasController(aliasController: IAliasController) {
this.aliasControllerValue = aliasController;
this.setupAliasController(this.aliasControllerValue);
}
get aliasController(): IAliasController {
return this.aliasControllerValue;
}
@Input() @Input()
tooltipPosition: TooltipPosition = 'above'; tooltipPosition: TooltipPosition = 'above';
@ -49,32 +56,43 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
@ViewChild('aliasEntitySelectPanelOrigin') aliasEntitySelectPanelOrigin: CdkOverlayOrigin; @ViewChild('aliasEntitySelectPanelOrigin') aliasEntitySelectPanelOrigin: CdkOverlayOrigin;
displayValue: string; displayValue: string;
entityAliasesInfo: {[aliasId: string]: AliasInfo} = {};
hasSelectableAliasEntities = false;
private rxSubscriptions = new Array<Subscription>(); private rxSubscriptions = new Array<Subscription>();
constructor(private translate: TranslateService, constructor(private translate: TranslateService,
private overlay: Overlay, private overlay: Overlay,
private breakpointObserver: BreakpointObserver, private breakpointObserver: BreakpointObserver,
private viewContainerRef: ViewContainerRef, private viewContainerRef: ViewContainerRef) {
@Inject(DOCUMENT) private document: Document, }
@Inject(WINDOW) private window: Window) {
private setupAliasController(aliasController: IAliasController) {
this.rxSubscriptions.forEach((subscription) => {
subscription.unsubscribe();
});
this.rxSubscriptions.length = 0;
if (aliasController) {
this.rxSubscriptions.push(aliasController.entityAliasesChanged.subscribe(
() => {
setTimeout(() => {
this.updateDisplayValue();
this.updateEntityAliasesInfo();
}, 0);
}
));
this.rxSubscriptions.push(aliasController.entityAliasResolved.subscribe(
() => {
setTimeout(() => {
this.updateDisplayValue();
this.updateEntityAliasesInfo();
}, 0);
}
));
}
} }
ngOnInit(): void { ngOnInit(): void {
this.rxSubscriptions.push(this.aliasController.entityAliasesChanged.subscribe(
() => {
setTimeout(() => {
this.updateDisplayValue();
}, 0);
}
));
this.rxSubscriptions.push(this.aliasController.entityAliasResolved.subscribe(
() => {
setTimeout(() => {
this.updateDisplayValue();
}, 0);
}
));
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@ -85,48 +103,20 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
} }
openEditMode() { openEditMode() {
if (this.disabled) { if (this.disabled || !this.hasSelectableAliasEntities) {
return; return;
} }
const panelHeight = this.breakpointObserver.isMatched('min-height: 350px') ? 250 : 150;
const panelWidth = 300;
const position = this.overlay.position(); const position = this.overlay.position();
const config = new OverlayConfig({ const config = new OverlayConfig({
panelClass: 'tb-aliases-entity-select-panel', panelClass: 'tb-aliases-entity-select-panel',
backdropClass: 'cdk-overlay-transparent-backdrop', backdropClass: 'cdk-overlay-transparent-backdrop',
hasBackdrop: true, hasBackdrop: true,
}); });
const el = this.aliasEntitySelectPanelOrigin.elementRef.nativeElement;
const offset = el.getBoundingClientRect();
const scrollTop = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0;
const scrollLeft = this.window.pageXOffset || this.document.documentElement.scrollLeft || this.document.body.scrollLeft || 0;
const bottomY = offset.bottom - scrollTop;
const leftX = offset.left - scrollLeft;
let originX;
let originY;
let overlayX;
let overlayY;
const wHeight = this.document.documentElement.clientHeight;
const wWidth = this.document.documentElement.clientWidth;
if (bottomY + panelHeight > wHeight) {
originY = 'top';
overlayY = 'bottom';
} else {
originY = 'bottom';
overlayY = 'top';
}
if (leftX + panelWidth > wWidth) {
originX = 'end';
overlayX = 'end';
} else {
originX = 'start';
overlayX = 'start';
}
const connectedPosition: ConnectedPosition = { const connectedPosition: ConnectedPosition = {
originX, originX: 'start',
originY, originY: 'bottom',
overlayX, overlayX: 'start',
overlayY overlayY: 'top'
}; };
config.positionStrategy = position.flexibleConnectedTo(this.aliasEntitySelectPanelOrigin.elementRef) config.positionStrategy = position.flexibleConnectedTo(this.aliasEntitySelectPanelOrigin.elementRef)
.withPositions([connectedPosition]); .withPositions([connectedPosition]);
@ -138,7 +128,8 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
const injector = this._createAliasesEntitySelectPanelInjector( const injector = this._createAliasesEntitySelectPanelInjector(
overlayRef, overlayRef,
{ {
aliasController: this.aliasController aliasController: this.aliasController,
entityAliasesInfo: this.entityAliasesInfo
} }
); );
overlayRef.attach(new ComponentPortal(AliasesEntitySelectPanelComponent, this.viewContainerRef, injector)); overlayRef.attach(new ComponentPortal(AliasesEntitySelectPanelComponent, this.viewContainerRef, injector));
@ -180,4 +171,19 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
this.displayValue = displayValue; this.displayValue = displayValue;
} }
private updateEntityAliasesInfo() {
const allEntityAliases = this.aliasController.getEntityAliases();
this.entityAliasesInfo = {};
this.hasSelectableAliasEntities = false;
for (const aliasId of Object.keys(allEntityAliases)) {
const aliasInfo = this.aliasController.getInstantAliasInfo(aliasId);
if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity
&& aliasInfo.resolvedEntities.length > 1) {
this.entityAliasesInfo[aliasId] = deepClone(aliasInfo);
this.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;
this.hasSelectableAliasEntities = true;
}
}
}
} }

View File

@ -18,7 +18,7 @@
<div fxFlex fxLayout="column" class="tb-progress-cover" fxLayoutAlign="center center" <div fxFlex fxLayout="column" class="tb-progress-cover" fxLayoutAlign="center center"
[ngStyle]="dashboardStyle" [ngStyle]="dashboardStyle"
[style.backgroundImage]="backgroundImage" [style.backgroundImage]="backgroundImage"
[fxShow]="(((isLoading$ | async) && !this.ignoreLoading) || this.dashboardLoading) && !isEdit"> [fxShow]="(isLoading$ | async) && !ignoreLoading && !isEdit">
<mat-spinner color="warn" mode="indeterminate" diameter="100"> <mat-spinner color="warn" mode="indeterminate" diameter="100">
</mat-spinner> </mat-spinner>
</div> </div>

View File

@ -122,7 +122,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
dashboardClass: string; dashboardClass: string;
@Input() @Input()
ignoreLoading: boolean; ignoreLoading = true;
@Input() @Input()
dashboardTimewindow: Timewindow; dashboardTimewindow: Timewindow;
@ -154,8 +154,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
widgetContextMenuEvent: MouseEvent; widgetContextMenuEvent: MouseEvent;
dashboardLoading = true;
dashboardWidgets = new DashboardWidgets(this, dashboardWidgets = new DashboardWidgets(this,
this.differs.find([]).create<Widget>((index, item) => { this.differs.find([]).create<Widget>((index, item) => {
return item; return item;
@ -282,7 +280,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
private updateWidgets() { private updateWidgets() {
this.dashboardWidgets.setWidgets(this.widgets, this.widgetLayouts); this.dashboardWidgets.setWidgets(this.widgets, this.widgetLayouts);
this.dashboardWidgets.doCheck(); this.dashboardWidgets.doCheck();
this.dashboardLoading = false;
} }
private updateWidgetLayouts() { private updateWidgetLayouts() {

View File

@ -159,7 +159,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
widgets: null, widgets: null,
widgetLayouts: {}, widgetLayouts: {},
gridSettings: {}, gridSettings: {},
ignoreLoading: false, ignoreLoading: true,
ctrl: null, ctrl: null,
dashboardCtrl: this dashboardCtrl: this
} }
@ -171,7 +171,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
widgets: null, widgets: null,
widgetLayouts: {}, widgetLayouts: {},
gridSettings: {}, gridSettings: {},
ignoreLoading: false, ignoreLoading: true,
ctrl: null, ctrl: null,
dashboardCtrl: this dashboardCtrl: this
} }

View File

@ -193,8 +193,11 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
public getStateName(index: number): string { public getStateName(index: number): string {
let result = ''; let result = '';
if (this.stateObject[index]) { const state = this.stateObject[index];
let stateName = this.states[this.stateObject[index].id].name; if (state) {
const dashboardState = this.states[state.id];
if (dashboardState) {
let stateName = dashboardState.name;
stateName = this.utils.customTranslation(stateName, stateName); stateName = this.utils.customTranslation(stateName, stateName);
const params = this.stateObject[index].params; const params = this.stateObject[index].params;
const targetParams = params && params.targetEntityParamName ? params[params.targetEntityParamName] : params; const targetParams = params && params.targetEntityParamName ? params[params.targetEntityParamName] : params;
@ -211,6 +214,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
} }
} }
} }
}
return result; return result;
} }