UI: Improved timewindow position and clear code in alarm filter config
This commit is contained in:
parent
bff3297c56
commit
f0fbc784b4
@ -17,7 +17,7 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||||
/// <reference path="../../../../src/typings/rawloader.typings.d.ts" />
|
/// <reference path="../../../../src/typings/rawloader.typings.d.ts" />
|
||||||
|
|
||||||
import { ElementRef, Inject, Injectable, NgZone } from '@angular/core';
|
import { Inject, Injectable, NgZone } from '@angular/core';
|
||||||
import { WINDOW } from '@core/services/window.service';
|
import { WINDOW } from '@core/services/window.service';
|
||||||
import { ExceptionData } from '@app/shared/models/error.models';
|
import { ExceptionData } from '@app/shared/models/error.models';
|
||||||
import {
|
import {
|
||||||
@ -45,7 +45,7 @@ import { alarmFields, alarmSeverityTranslations, alarmStatusTranslations } from
|
|||||||
import { materialColors } from '@app/shared/models/material.models';
|
import { materialColors } from '@app/shared/models/material.models';
|
||||||
import { WidgetInfo } from '@home/models/widget-component.models';
|
import { WidgetInfo } from '@home/models/widget-component.models';
|
||||||
import jsonSchemaDefaults from 'json-schema-defaults';
|
import jsonSchemaDefaults from 'json-schema-defaults';
|
||||||
import { fromEvent, Observable, Subscription } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { publishReplay, refCount } from 'rxjs/operators';
|
import { publishReplay, refCount } from 'rxjs/operators';
|
||||||
import { WidgetContext } from '@app/modules/home/models/widget-component.models';
|
import { WidgetContext } from '@app/modules/home/models/widget-component.models';
|
||||||
import {
|
import {
|
||||||
@ -57,8 +57,6 @@ import {
|
|||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { entityTypeTranslations } from '@shared/models/entity-type.models';
|
import { entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||||
import { OverlayRef } from '@angular/cdk/overlay';
|
|
||||||
import { ResizeObserver } from '@juggle/resize-observer';
|
|
||||||
|
|
||||||
const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g');
|
const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g');
|
||||||
|
|
||||||
@ -530,24 +528,4 @@ export class UtilsService {
|
|||||||
return base64toObj(b64Encoded);
|
return base64toObj(b64Encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateOverlayMaxHeigth(overlay: OverlayRef, observeElementRef?: ElementRef): Subscription {
|
|
||||||
const observeElement = observeElementRef ? observeElementRef.nativeElement : overlay.overlayElement.children[0];
|
|
||||||
|
|
||||||
const setMaxHeigthOverlay = () => {
|
|
||||||
const top = observeElement.getBoundingClientRect().top;
|
|
||||||
const viewport = window.innerHeight;
|
|
||||||
overlay.updateSize({
|
|
||||||
maxHeight: viewport - top
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const observer = new ResizeObserver(() => {
|
|
||||||
setMaxHeigthOverlay();
|
|
||||||
observer.unobserve(observeElement);
|
|
||||||
});
|
|
||||||
observer.observe(observeElement);
|
|
||||||
|
|
||||||
return fromEvent(window, 'resize').subscribe(() => setMaxHeigthOverlay());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import {
|
|||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||||
import { AlarmFilterConfig, alarmFilterConfigEquals } from '@shared/models/query/query.models';
|
import { AlarmFilterConfig, alarmFilterConfigEquals } from '@shared/models/query/query.models';
|
||||||
import { coerceBoolean } from '@shared/decorators/coercion';
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
||||||
import { TemplatePortal } from '@angular/cdk/portal';
|
import { TemplatePortal } from '@angular/cdk/portal';
|
||||||
import {
|
import {
|
||||||
AlarmAssigneeOption,
|
AlarmAssigneeOption,
|
||||||
@ -44,8 +44,8 @@ import { MatChipInputEvent } from '@angular/material/chips';
|
|||||||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
|
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { deepClone } from '@core/utils';
|
import { deepClone } from '@core/utils';
|
||||||
import { Subscription } from 'rxjs';
|
import { fromEvent, Subscription } from 'rxjs';
|
||||||
import { UtilsService } from '@core/services/utils.service';
|
import { POSITION_MAP } from '@shared/components/popover.models';
|
||||||
|
|
||||||
export const ALARM_FILTER_CONFIG_DATA = new InjectionToken<any>('AlarmFilterConfigData');
|
export const ALARM_FILTER_CONFIG_DATA = new InjectionToken<any>('AlarmFilterConfigData');
|
||||||
|
|
||||||
@ -128,7 +128,6 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal
|
|||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private overlay: Overlay,
|
private overlay: Overlay,
|
||||||
private nativeElement: ElementRef,
|
private nativeElement: ElementRef,
|
||||||
private utils: UtilsService,
|
|
||||||
private viewContainerRef: ViewContainerRef) {
|
private viewContainerRef: ViewContainerRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,14 +201,9 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal
|
|||||||
minWidth: ''
|
minWidth: ''
|
||||||
});
|
});
|
||||||
config.hasBackdrop = true;
|
config.hasBackdrop = true;
|
||||||
const connectedPosition: ConnectedPosition = {
|
config.positionStrategy = this.overlay.position()
|
||||||
originX: 'start',
|
.flexibleConnectedTo(this.nativeElement)
|
||||||
originY: 'bottom',
|
.withPositions([POSITION_MAP.bottomLeft]);
|
||||||
overlayX: 'start',
|
|
||||||
overlayY: 'top'
|
|
||||||
};
|
|
||||||
config.positionStrategy = this.overlay.position().flexibleConnectedTo(this.nativeElement)
|
|
||||||
.withPositions([connectedPosition]);
|
|
||||||
|
|
||||||
this.alarmFilterOverlayRef = this.overlay.create(config);
|
this.alarmFilterOverlayRef = this.overlay.create(config);
|
||||||
this.alarmFilterOverlayRef.backdropClick().subscribe(() => {
|
this.alarmFilterOverlayRef.backdropClick().subscribe(() => {
|
||||||
@ -217,7 +211,9 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal
|
|||||||
});
|
});
|
||||||
this.alarmFilterOverlayRef.attach(new TemplatePortal(this.alarmFilterPanel,
|
this.alarmFilterOverlayRef.attach(new TemplatePortal(this.alarmFilterPanel,
|
||||||
this.viewContainerRef));
|
this.viewContainerRef));
|
||||||
this.resizeWindows = this.utils.updateOverlayMaxHeigth(this.alarmFilterOverlayRef);
|
this.resizeWindows = fromEvent(window, 'resize').subscribe(() => {
|
||||||
|
this.alarmFilterOverlayRef.updatePosition();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ import cssjs from '@core/css/css';
|
|||||||
import { sortItems } from '@shared/models/page/page-link';
|
import { sortItems } from '@shared/models/page/page-link';
|
||||||
import { Direction } from '@shared/models/page/sort-order';
|
import { Direction } from '@shared/models/page/sort-order';
|
||||||
import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections';
|
import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections';
|
||||||
import { BehaviorSubject, forkJoin, merge, Observable, Subject, Subscription } from 'rxjs';
|
import { BehaviorSubject, forkJoin, fromEvent, merge, Observable, Subject, Subscription } from 'rxjs';
|
||||||
import { emptyPageData, PageData } from '@shared/models/page/page-data';
|
import { emptyPageData, PageData } from '@shared/models/page/page-data';
|
||||||
import { debounceTime, distinctUntilChanged, map, take, takeUntil, tap } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged, map, take, takeUntil, tap } from 'rxjs/operators';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
@ -123,6 +123,7 @@ import {
|
|||||||
} from '@home/components/alarm/alarm-filter-config.component';
|
} from '@home/components/alarm/alarm-filter-config.component';
|
||||||
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
|
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
import { DEFAULT_OVERLAY_POSITIONS } from '@shared/components/popover.models';
|
||||||
|
|
||||||
interface AlarmsTableWidgetSettings extends TableWidgetSettings {
|
interface AlarmsTableWidgetSettings extends TableWidgetSettings {
|
||||||
alarmsTitle: string;
|
alarmsTitle: string;
|
||||||
@ -572,14 +573,9 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
|
|||||||
height: 'fit-content',
|
height: 'fit-content',
|
||||||
maxHeight: '75vh'
|
maxHeight: '75vh'
|
||||||
});
|
});
|
||||||
const connectedPosition: ConnectedPosition = {
|
config.positionStrategy = this.overlay.position()
|
||||||
originX: 'end',
|
.flexibleConnectedTo(target as HTMLElement)
|
||||||
originY: 'bottom',
|
.withPositions(DEFAULT_OVERLAY_POSITIONS);
|
||||||
overlayX: 'end',
|
|
||||||
overlayY: 'top'
|
|
||||||
};
|
|
||||||
config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement)
|
|
||||||
.withPositions([connectedPosition]);
|
|
||||||
|
|
||||||
const overlayRef = this.overlay.create(config);
|
const overlayRef = this.overlay.create(config);
|
||||||
overlayRef.backdropClick().subscribe(() => {
|
overlayRef.backdropClick().subscribe(() => {
|
||||||
@ -614,10 +610,12 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
|
|||||||
const componentRef = overlayRef.attach(new ComponentPortal(AlarmFilterConfigComponent,
|
const componentRef = overlayRef.attach(new ComponentPortal(AlarmFilterConfigComponent,
|
||||||
this.viewContainerRef, injector));
|
this.viewContainerRef, injector));
|
||||||
|
|
||||||
const resizeWindows = this.utils.updateOverlayMaxHeigth(overlayRef, componentRef.location);
|
const resizeWindows$ = fromEvent(window, 'resize').subscribe(() => {
|
||||||
|
overlayRef.updatePosition();
|
||||||
|
});
|
||||||
|
|
||||||
componentRef.onDestroy(() => {
|
componentRef.onDestroy(() => {
|
||||||
resizeWindows.unsubscribe();
|
resizeWindows$.unsubscribe();
|
||||||
if (componentRef.instance.panelResult) {
|
if (componentRef.instance.panelResult) {
|
||||||
const result = componentRef.instance.panelResult;
|
const result = componentRef.instance.panelResult;
|
||||||
const alarmFilter = this.entityService.resolveAlarmFilter(result, false);
|
const alarmFilter = this.entityService.resolveAlarmFilter(result, false);
|
||||||
|
|||||||
@ -71,6 +71,9 @@ export const POSITION_MAP: { [key: string]: ConnectionPositionPair } = {
|
|||||||
|
|
||||||
export const DEFAULT_POPOVER_POSITIONS = [POSITION_MAP.top, POSITION_MAP.right, POSITION_MAP.bottom, POSITION_MAP.left];
|
export const DEFAULT_POPOVER_POSITIONS = [POSITION_MAP.top, POSITION_MAP.right, POSITION_MAP.bottom, POSITION_MAP.left];
|
||||||
|
|
||||||
|
export const DEFAULT_OVERLAY_POSITIONS = [POSITION_MAP.bottomLeft, POSITION_MAP.bottomRight, POSITION_MAP.topLeft,
|
||||||
|
POSITION_MAP.topRight, POSITION_MAP.left, POSITION_MAP.right];
|
||||||
|
|
||||||
export function getPlacementName(position: ConnectedOverlayPositionChange): PopoverPlacement | undefined {
|
export function getPlacementName(position: ConnectedOverlayPositionChange): PopoverPlacement | undefined {
|
||||||
for (const placement in POSITION_MAP) {
|
for (const placement in POSITION_MAP) {
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
:host {
|
:host {
|
||||||
min-width: 355px;
|
min-width: 355px;
|
||||||
|
display: block;
|
||||||
|
|
||||||
@media #{$mat-xs} {
|
@media #{$mat-xs} {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@ -18,9 +18,13 @@ import {
|
|||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
forwardRef, HostBinding,
|
forwardRef,
|
||||||
|
HostBinding,
|
||||||
Injector,
|
Injector,
|
||||||
Input, OnChanges, OnInit, SimpleChanges,
|
Input,
|
||||||
|
OnChanges,
|
||||||
|
OnInit,
|
||||||
|
SimpleChanges,
|
||||||
StaticProvider,
|
StaticProvider,
|
||||||
ViewContainerRef
|
ViewContainerRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
@ -47,15 +51,18 @@ import { TimeService } from '@core/services/time.service';
|
|||||||
import { TooltipPosition } from '@angular/material/tooltip';
|
import { TooltipPosition } from '@angular/material/tooltip';
|
||||||
import { deepClone, isDefinedAndNotNull } from '@core/utils';
|
import { deepClone, isDefinedAndNotNull } from '@core/utils';
|
||||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
||||||
import { ComponentPortal } from '@angular/cdk/portal';
|
import { ComponentPortal } from '@angular/cdk/portal';
|
||||||
import { coerceBoolean } from '@shared/decorators/coercion';
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
import {
|
import {
|
||||||
ComponentStyle,
|
ComponentStyle,
|
||||||
defaultTimewindowStyle, iconStyle,
|
defaultTimewindowStyle,
|
||||||
|
iconStyle,
|
||||||
textStyle,
|
textStyle,
|
||||||
TimewindowStyle
|
TimewindowStyle
|
||||||
} from '@shared/models/widget-settings.models';
|
} from '@shared/models/widget-settings.models';
|
||||||
|
import { DEFAULT_OVERLAY_POSITIONS } from '@shared/components/popover.models';
|
||||||
|
import { fromEvent } from 'rxjs';
|
||||||
|
|
||||||
// @dynamic
|
// @dynamic
|
||||||
@Component({
|
@Component({
|
||||||
@ -223,14 +230,10 @@ export class TimewindowComponent implements ControlValueAccessor, OnInit, OnChan
|
|||||||
maxHeight: '80vh',
|
maxHeight: '80vh',
|
||||||
height: 'min-content'
|
height: 'min-content'
|
||||||
});
|
});
|
||||||
const connectedPosition: ConnectedPosition = {
|
|
||||||
originX: 'start',
|
config.positionStrategy = this.overlay.position()
|
||||||
originY: 'bottom',
|
.flexibleConnectedTo(this.nativeElement)
|
||||||
overlayX: 'start',
|
.withPositions(DEFAULT_OVERLAY_POSITIONS);
|
||||||
overlayY: 'top'
|
|
||||||
};
|
|
||||||
config.positionStrategy = this.overlay.position().flexibleConnectedTo(this.nativeElement)
|
|
||||||
.withPositions([connectedPosition]);
|
|
||||||
|
|
||||||
const overlayRef = this.overlay.create(config);
|
const overlayRef = this.overlay.create(config);
|
||||||
overlayRef.backdropClick().subscribe(() => {
|
overlayRef.backdropClick().subscribe(() => {
|
||||||
@ -257,7 +260,11 @@ export class TimewindowComponent implements ControlValueAccessor, OnInit, OnChan
|
|||||||
const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
|
const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
|
||||||
const componentRef = overlayRef.attach(new ComponentPortal(TimewindowPanelComponent,
|
const componentRef = overlayRef.attach(new ComponentPortal(TimewindowPanelComponent,
|
||||||
this.viewContainerRef, injector));
|
this.viewContainerRef, injector));
|
||||||
|
const resizeWindows$ = fromEvent(window, 'resize').subscribe(() => {
|
||||||
|
overlayRef.updatePosition();
|
||||||
|
});
|
||||||
componentRef.onDestroy(() => {
|
componentRef.onDestroy(() => {
|
||||||
|
resizeWindows$.unsubscribe();
|
||||||
if (componentRef.instance.result) {
|
if (componentRef.instance.result) {
|
||||||
this.innerValue = componentRef.instance.result;
|
this.innerValue = componentRef.instance.result;
|
||||||
this.timewindowDisabled = this.isTimewindowDisabled();
|
this.timewindowDisabled = this.isTimewindowDisabled();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user