Commit 534db078ff12b8a0603f9a0d8ceb3877bd2da687

Authored by Igor Kulikov
1 parent 969c0363

Dashboard page fixes and improvements

@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 --> 17 -->
18 <div fxLayout="column" class="mat-content mat-padding"> 18 <div fxLayout="column" class="mat-content mat-padding">
19 <div fxLayout="row" *ngFor="let alias of entityAliasesInfo | keyvalue"> 19 <div fxLayout="row" *ngFor="let alias of entityAliasesInfo | keyvalue">
20 - <mat-form-field> 20 + <mat-form-field fxFlex>
21 <mat-label>{{alias.value.alias}}</mat-label> 21 <mat-label>{{alias.value.alias}}</mat-label>
22 <mat-select [(ngModel)]="alias.value.selectedId" 22 <mat-select [(ngModel)]="alias.value.selectedId"
23 (ngModelChange)="currentAliasEntityChanged(alias.key, alias.value.selectedId)"> 23 (ngModelChange)="currentAliasEntityChanged(alias.key, alias.value.selectedId)">
@@ -22,6 +22,7 @@ export const ALIASES_ENTITY_SELECT_PANEL_DATA = new InjectionToken<any>('Aliases @@ -22,6 +22,7 @@ export const ALIASES_ENTITY_SELECT_PANEL_DATA = new InjectionToken<any>('Aliases
22 22
23 export interface AliasesEntitySelectPanelData { 23 export interface AliasesEntitySelectPanelData {
24 aliasController: IAliasController; 24 aliasController: IAliasController;
  25 + entityAliasesInfo: {[aliasId: string]: AliasInfo};
25 } 26 }
26 27
27 @Component({ 28 @Component({
@@ -31,18 +32,10 @@ export interface AliasesEntitySelectPanelData { @@ -31,18 +32,10 @@ export interface AliasesEntitySelectPanelData {
31 }) 32 })
32 export class AliasesEntitySelectPanelComponent { 33 export class AliasesEntitySelectPanelComponent {
33 34
34 - entityAliasesInfo: {[aliasId: string]: AliasInfo} = {}; 35 + entityAliasesInfo: {[aliasId: string]: AliasInfo};
35 36
36 constructor(@Inject(ALIASES_ENTITY_SELECT_PANEL_DATA) public data: AliasesEntitySelectPanelData) { 37 constructor(@Inject(ALIASES_ENTITY_SELECT_PANEL_DATA) public data: AliasesEntitySelectPanelData) {
37 - const allEntityAliases = this.data.aliasController.getEntityAliases();  
38 - for (const aliasId of Object.keys(allEntityAliases)) {  
39 - const aliasInfo = this.data.aliasController.getInstantAliasInfo(aliasId);  
40 - if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity  
41 - && aliasInfo.resolvedEntities.length > 1) {  
42 - this.entityAliasesInfo[aliasId] = deepClone(aliasInfo);  
43 - this.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;  
44 - }  
45 - } 38 + this.entityAliasesInfo = this.data.entityAliasesInfo;
46 } 39 }
47 40
48 public currentAliasEntityChanged(aliasId: string, selectedId: string) { 41 public currentAliasEntityChanged(aliasId: string, selectedId: string) {
@@ -19,13 +19,13 @@ @@ -19,13 +19,13 @@
19 <button mat-icon-button 19 <button mat-icon-button
20 cdkOverlayOrigin #aliasEntitySelectPanelOrigin="cdkOverlayOrigin" 20 cdkOverlayOrigin #aliasEntitySelectPanelOrigin="cdkOverlayOrigin"
21 (click)="openEditMode()" 21 (click)="openEditMode()"
22 - matTooltip="{{ 'entity.select-entities' | translate }}" 22 + matTooltip="{{ hasSelectableAliasEntities ? ('entity.select-entities' | translate) : '' }}"
23 [matTooltipPosition]="tooltipPosition"> 23 [matTooltipPosition]="tooltipPosition">
24 <mat-icon class="material-icons">devices_other</mat-icon> 24 <mat-icon class="material-icons">devices_other</mat-icon>
25 </button> 25 </button>
26 <span fxHide.lt-lg 26 <span fxHide.lt-lg
27 (click)="openEditMode()" 27 (click)="openEditMode()"
28 - matTooltip="{{ 'entity.select-entities' | translate }}" 28 + matTooltip="{{ hasSelectableAliasEntities ? ('entity.select-entities' | translate) : '' }}"
29 [matTooltipPosition]="tooltipPosition"> 29 [matTooltipPosition]="tooltipPosition">
30 {{displayValue}} 30 {{displayValue}}
31 </span> 31 </span>
@@ -14,23 +14,21 @@ @@ -14,23 +14,21 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; 17 +import { Component, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
18 import { TooltipPosition } from '@angular/material/tooltip'; 18 import { TooltipPosition } from '@angular/material/tooltip';
19 -import { IAliasController } from '@core/api/widget-api.models'; 19 +import { AliasInfo, IAliasController } from '@core/api/widget-api.models';
20 import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; 20 import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
21 import { TranslateService } from '@ngx-translate/core'; 21 import { TranslateService } from '@ngx-translate/core';
22 import { Subscription } from 'rxjs'; 22 import { Subscription } from 'rxjs';
23 import { BreakpointObserver } from '@angular/cdk/layout'; 23 import { BreakpointObserver } from '@angular/cdk/layout';
24 -import { DOCUMENT } from '@angular/common';  
25 -import { WINDOW } from '@core/services/window.service';  
26 import { ComponentPortal, PortalInjector } from '@angular/cdk/portal'; 24 import { ComponentPortal, PortalInjector } from '@angular/cdk/portal';
27 import { 25 import {
28 ALIASES_ENTITY_SELECT_PANEL_DATA, 26 ALIASES_ENTITY_SELECT_PANEL_DATA,
29 AliasesEntitySelectPanelComponent, 27 AliasesEntitySelectPanelComponent,
30 AliasesEntitySelectPanelData 28 AliasesEntitySelectPanelData
31 } from './aliases-entity-select-panel.component'; 29 } from './aliases-entity-select-panel.component';
  30 +import { deepClone } from '@core/utils';
32 31
33 -// @dynamic  
34 @Component({ 32 @Component({
35 selector: 'tb-aliases-entity-select', 33 selector: 'tb-aliases-entity-select',
36 templateUrl: './aliases-entity-select.component.html', 34 templateUrl: './aliases-entity-select.component.html',
@@ -38,8 +36,17 @@ import { @@ -38,8 +36,17 @@ import {
38 }) 36 })
39 export class AliasesEntitySelectComponent implements OnInit, OnDestroy { 37 export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
40 38
  39 + aliasControllerValue: IAliasController;
  40 +
41 @Input() 41 @Input()
42 - aliasController: IAliasController; 42 + set aliasController(aliasController: IAliasController) {
  43 + this.aliasControllerValue = aliasController;
  44 + this.setupAliasController(this.aliasControllerValue);
  45 + }
  46 +
  47 + get aliasController(): IAliasController {
  48 + return this.aliasControllerValue;
  49 + }
43 50
44 @Input() 51 @Input()
45 tooltipPosition: TooltipPosition = 'above'; 52 tooltipPosition: TooltipPosition = 'above';
@@ -49,32 +56,43 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy { @@ -49,32 +56,43 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
49 @ViewChild('aliasEntitySelectPanelOrigin') aliasEntitySelectPanelOrigin: CdkOverlayOrigin; 56 @ViewChild('aliasEntitySelectPanelOrigin') aliasEntitySelectPanelOrigin: CdkOverlayOrigin;
50 57
51 displayValue: string; 58 displayValue: string;
  59 + entityAliasesInfo: {[aliasId: string]: AliasInfo} = {};
  60 + hasSelectableAliasEntities = false;
52 61
53 private rxSubscriptions = new Array<Subscription>(); 62 private rxSubscriptions = new Array<Subscription>();
54 63
55 constructor(private translate: TranslateService, 64 constructor(private translate: TranslateService,
56 private overlay: Overlay, 65 private overlay: Overlay,
57 private breakpointObserver: BreakpointObserver, 66 private breakpointObserver: BreakpointObserver,
58 - private viewContainerRef: ViewContainerRef,  
59 - @Inject(DOCUMENT) private document: Document,  
60 - @Inject(WINDOW) private window: Window) { 67 + private viewContainerRef: ViewContainerRef) {
  68 + }
  69 +
  70 + private setupAliasController(aliasController: IAliasController) {
  71 + this.rxSubscriptions.forEach((subscription) => {
  72 + subscription.unsubscribe();
  73 + });
  74 + this.rxSubscriptions.length = 0;
  75 + if (aliasController) {
  76 + this.rxSubscriptions.push(aliasController.entityAliasesChanged.subscribe(
  77 + () => {
  78 + setTimeout(() => {
  79 + this.updateDisplayValue();
  80 + this.updateEntityAliasesInfo();
  81 + }, 0);
  82 + }
  83 + ));
  84 + this.rxSubscriptions.push(aliasController.entityAliasResolved.subscribe(
  85 + () => {
  86 + setTimeout(() => {
  87 + this.updateDisplayValue();
  88 + this.updateEntityAliasesInfo();
  89 + }, 0);
  90 + }
  91 + ));
  92 + }
61 } 93 }
62 94
63 ngOnInit(): void { 95 ngOnInit(): void {
64 - this.rxSubscriptions.push(this.aliasController.entityAliasesChanged.subscribe(  
65 - () => {  
66 - setTimeout(() => {  
67 - this.updateDisplayValue();  
68 - }, 0);  
69 - }  
70 - ));  
71 - this.rxSubscriptions.push(this.aliasController.entityAliasResolved.subscribe(  
72 - () => {  
73 - setTimeout(() => {  
74 - this.updateDisplayValue();  
75 - }, 0);  
76 - }  
77 - ));  
78 } 96 }
79 97
80 ngOnDestroy(): void { 98 ngOnDestroy(): void {
@@ -85,48 +103,20 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy { @@ -85,48 +103,20 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
85 } 103 }
86 104
87 openEditMode() { 105 openEditMode() {
88 - if (this.disabled) { 106 + if (this.disabled || !this.hasSelectableAliasEntities) {
89 return; 107 return;
90 } 108 }
91 - const panelHeight = this.breakpointObserver.isMatched('min-height: 350px') ? 250 : 150;  
92 - const panelWidth = 300;  
93 const position = this.overlay.position(); 109 const position = this.overlay.position();
94 const config = new OverlayConfig({ 110 const config = new OverlayConfig({
95 panelClass: 'tb-aliases-entity-select-panel', 111 panelClass: 'tb-aliases-entity-select-panel',
96 backdropClass: 'cdk-overlay-transparent-backdrop', 112 backdropClass: 'cdk-overlay-transparent-backdrop',
97 hasBackdrop: true, 113 hasBackdrop: true,
98 }); 114 });
99 - const el = this.aliasEntitySelectPanelOrigin.elementRef.nativeElement;  
100 - const offset = el.getBoundingClientRect();  
101 - const scrollTop = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0;  
102 - const scrollLeft = this.window.pageXOffset || this.document.documentElement.scrollLeft || this.document.body.scrollLeft || 0;  
103 - const bottomY = offset.bottom - scrollTop;  
104 - const leftX = offset.left - scrollLeft;  
105 - let originX;  
106 - let originY;  
107 - let overlayX;  
108 - let overlayY;  
109 - const wHeight = this.document.documentElement.clientHeight;  
110 - const wWidth = this.document.documentElement.clientWidth;  
111 - if (bottomY + panelHeight > wHeight) {  
112 - originY = 'top';  
113 - overlayY = 'bottom';  
114 - } else {  
115 - originY = 'bottom';  
116 - overlayY = 'top';  
117 - }  
118 - if (leftX + panelWidth > wWidth) {  
119 - originX = 'end';  
120 - overlayX = 'end';  
121 - } else {  
122 - originX = 'start';  
123 - overlayX = 'start';  
124 - }  
125 const connectedPosition: ConnectedPosition = { 115 const connectedPosition: ConnectedPosition = {
126 - originX,  
127 - originY,  
128 - overlayX,  
129 - overlayY 116 + originX: 'start',
  117 + originY: 'bottom',
  118 + overlayX: 'start',
  119 + overlayY: 'top'
130 }; 120 };
131 config.positionStrategy = position.flexibleConnectedTo(this.aliasEntitySelectPanelOrigin.elementRef) 121 config.positionStrategy = position.flexibleConnectedTo(this.aliasEntitySelectPanelOrigin.elementRef)
132 .withPositions([connectedPosition]); 122 .withPositions([connectedPosition]);
@@ -138,7 +128,8 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy { @@ -138,7 +128,8 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
138 const injector = this._createAliasesEntitySelectPanelInjector( 128 const injector = this._createAliasesEntitySelectPanelInjector(
139 overlayRef, 129 overlayRef,
140 { 130 {
141 - aliasController: this.aliasController 131 + aliasController: this.aliasController,
  132 + entityAliasesInfo: this.entityAliasesInfo
142 } 133 }
143 ); 134 );
144 overlayRef.attach(new ComponentPortal(AliasesEntitySelectPanelComponent, this.viewContainerRef, injector)); 135 overlayRef.attach(new ComponentPortal(AliasesEntitySelectPanelComponent, this.viewContainerRef, injector));
@@ -180,4 +171,19 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy { @@ -180,4 +171,19 @@ export class AliasesEntitySelectComponent implements OnInit, OnDestroy {
180 this.displayValue = displayValue; 171 this.displayValue = displayValue;
181 } 172 }
182 173
  174 + private updateEntityAliasesInfo() {
  175 + const allEntityAliases = this.aliasController.getEntityAliases();
  176 + this.entityAliasesInfo = {};
  177 + this.hasSelectableAliasEntities = false;
  178 + for (const aliasId of Object.keys(allEntityAliases)) {
  179 + const aliasInfo = this.aliasController.getInstantAliasInfo(aliasId);
  180 + if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity
  181 + && aliasInfo.resolvedEntities.length > 1) {
  182 + this.entityAliasesInfo[aliasId] = deepClone(aliasInfo);
  183 + this.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;
  184 + this.hasSelectableAliasEntities = true;
  185 + }
  186 + }
  187 + }
  188 +
183 } 189 }
@@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
18 <div fxFlex fxLayout="column" class="tb-progress-cover" fxLayoutAlign="center center" 18 <div fxFlex fxLayout="column" class="tb-progress-cover" fxLayoutAlign="center center"
19 [ngStyle]="dashboardStyle" 19 [ngStyle]="dashboardStyle"
20 [style.backgroundImage]="backgroundImage" 20 [style.backgroundImage]="backgroundImage"
21 - [fxShow]="(((isLoading$ | async) && !this.ignoreLoading) || this.dashboardLoading) && !isEdit"> 21 + [fxShow]="(isLoading$ | async) && !ignoreLoading && !isEdit">
22 <mat-spinner color="warn" mode="indeterminate" diameter="100"> 22 <mat-spinner color="warn" mode="indeterminate" diameter="100">
23 </mat-spinner> 23 </mat-spinner>
24 </div> 24 </div>
@@ -122,7 +122,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo @@ -122,7 +122,7 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
122 dashboardClass: string; 122 dashboardClass: string;
123 123
124 @Input() 124 @Input()
125 - ignoreLoading: boolean; 125 + ignoreLoading = true;
126 126
127 @Input() 127 @Input()
128 dashboardTimewindow: Timewindow; 128 dashboardTimewindow: Timewindow;
@@ -154,8 +154,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo @@ -154,8 +154,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
154 154
155 widgetContextMenuEvent: MouseEvent; 155 widgetContextMenuEvent: MouseEvent;
156 156
157 - dashboardLoading = true;  
158 -  
159 dashboardWidgets = new DashboardWidgets(this, 157 dashboardWidgets = new DashboardWidgets(this,
160 this.differs.find([]).create<Widget>((index, item) => { 158 this.differs.find([]).create<Widget>((index, item) => {
161 return item; 159 return item;
@@ -282,7 +280,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo @@ -282,7 +280,6 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
282 private updateWidgets() { 280 private updateWidgets() {
283 this.dashboardWidgets.setWidgets(this.widgets, this.widgetLayouts); 281 this.dashboardWidgets.setWidgets(this.widgets, this.widgetLayouts);
284 this.dashboardWidgets.doCheck(); 282 this.dashboardWidgets.doCheck();
285 - this.dashboardLoading = false;  
286 } 283 }
287 284
288 private updateWidgetLayouts() { 285 private updateWidgetLayouts() {
@@ -159,7 +159,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC @@ -159,7 +159,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
159 widgets: null, 159 widgets: null,
160 widgetLayouts: {}, 160 widgetLayouts: {},
161 gridSettings: {}, 161 gridSettings: {},
162 - ignoreLoading: false, 162 + ignoreLoading: true,
163 ctrl: null, 163 ctrl: null,
164 dashboardCtrl: this 164 dashboardCtrl: this
165 } 165 }
@@ -171,7 +171,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC @@ -171,7 +171,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
171 widgets: null, 171 widgets: null,
172 widgetLayouts: {}, 172 widgetLayouts: {},
173 gridSettings: {}, 173 gridSettings: {},
174 - ignoreLoading: false, 174 + ignoreLoading: true,
175 ctrl: null, 175 ctrl: null,
176 dashboardCtrl: this 176 dashboardCtrl: this
177 } 177 }
@@ -193,21 +193,25 @@ export class EntityStateControllerComponent extends StateControllerComponent imp @@ -193,21 +193,25 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
193 193
194 public getStateName(index: number): string { 194 public getStateName(index: number): string {
195 let result = ''; 195 let result = '';
196 - if (this.stateObject[index]) {  
197 - let stateName = this.states[this.stateObject[index].id].name;  
198 - stateName = this.utils.customTranslation(stateName, stateName);  
199 - const params = this.stateObject[index].params;  
200 - const targetParams = params && params.targetEntityParamName ? params[params.targetEntityParamName] : params;  
201 - const entityName = targetParams && targetParams.entityName ? targetParams.entityName : '';  
202 - const entityLabel = targetParams && targetParams.entityLabel ? targetParams.entityLabel : '';  
203 - result = this.utils.insertVariable(stateName, 'entityName', entityName);  
204 - result = this.utils.insertVariable(result, 'entityLabel', entityLabel);  
205 - for (const prop of Object.keys(params)) {  
206 - if (params[prop] && params[prop].entityName) {  
207 - result = this.utils.insertVariable(result, prop + ':entityName', params[prop].entityName);  
208 - }  
209 - if (params[prop] && params[prop].entityLabel) {  
210 - result = this.utils.insertVariable(result, prop + ':entityLabel', params[prop].entityLabel); 196 + const state = this.stateObject[index];
  197 + if (state) {
  198 + const dashboardState = this.states[state.id];
  199 + if (dashboardState) {
  200 + let stateName = dashboardState.name;
  201 + stateName = this.utils.customTranslation(stateName, stateName);
  202 + const params = this.stateObject[index].params;
  203 + const targetParams = params && params.targetEntityParamName ? params[params.targetEntityParamName] : params;
  204 + const entityName = targetParams && targetParams.entityName ? targetParams.entityName : '';
  205 + const entityLabel = targetParams && targetParams.entityLabel ? targetParams.entityLabel : '';
  206 + result = this.utils.insertVariable(stateName, 'entityName', entityName);
  207 + result = this.utils.insertVariable(result, 'entityLabel', entityLabel);
  208 + for (const prop of Object.keys(params)) {
  209 + if (params[prop] && params[prop].entityName) {
  210 + result = this.utils.insertVariable(result, prop + ':entityName', params[prop].entityName);
  211 + }
  212 + if (params[prop] && params[prop].entityLabel) {
  213 + result = this.utils.insertVariable(result, prop + ':entityLabel', params[prop].entityLabel);
  214 + }
211 } 215 }
212 } 216 }
213 } 217 }