diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index e585b2a19a..a6065dfe62 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -17,7 +17,7 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// -import { ElementRef, Inject, Injectable, NgZone } from '@angular/core'; +import { Inject, Injectable, NgZone } from '@angular/core'; import { WINDOW } from '@core/services/window.service'; import { ExceptionData } from '@app/shared/models/error.models'; import { @@ -45,7 +45,7 @@ import { alarmFields, alarmSeverityTranslations, alarmStatusTranslations } from import { materialColors } from '@app/shared/models/material.models'; import { WidgetInfo } from '@home/models/widget-component.models'; import jsonSchemaDefaults from 'json-schema-defaults'; -import { fromEvent, Observable, Subscription } from 'rxjs'; +import { Observable } from 'rxjs'; import { publishReplay, refCount } from 'rxjs/operators'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { @@ -57,8 +57,6 @@ import { import { EntityId } from '@shared/models/id/entity-id'; import { DatePipe } from '@angular/common'; 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'); @@ -530,24 +528,4 @@ export class UtilsService { 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()); - } - } diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts index adc741fcdd..5c13a71552 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts @@ -31,7 +31,7 @@ import { import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { AlarmFilterConfig, alarmFilterConfigEquals } from '@shared/models/query/query.models'; 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 { AlarmAssigneeOption, @@ -44,8 +44,8 @@ import { MatChipInputEvent } from '@angular/material/chips'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; import { TranslateService } from '@ngx-translate/core'; import { deepClone } from '@core/utils'; -import { Subscription } from 'rxjs'; -import { UtilsService } from '@core/services/utils.service'; +import { fromEvent, Subscription } from 'rxjs'; +import { POSITION_MAP } from '@shared/components/popover.models'; export const ALARM_FILTER_CONFIG_DATA = new InjectionToken('AlarmFilterConfigData'); @@ -128,7 +128,6 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal private translate: TranslateService, private overlay: Overlay, private nativeElement: ElementRef, - private utils: UtilsService, private viewContainerRef: ViewContainerRef) { } @@ -202,14 +201,9 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal minWidth: '' }); config.hasBackdrop = true; - const connectedPosition: ConnectedPosition = { - originX: 'start', - originY: 'bottom', - overlayX: 'start', - overlayY: 'top' - }; - config.positionStrategy = this.overlay.position().flexibleConnectedTo(this.nativeElement) - .withPositions([connectedPosition]); + config.positionStrategy = this.overlay.position() + .flexibleConnectedTo(this.nativeElement) + .withPositions([POSITION_MAP.bottomLeft]); this.alarmFilterOverlayRef = this.overlay.create(config); this.alarmFilterOverlayRef.backdropClick().subscribe(() => { @@ -217,7 +211,9 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal }); this.alarmFilterOverlayRef.attach(new TemplatePortal(this.alarmFilterPanel, this.viewContainerRef)); - this.resizeWindows = this.utils.updateOverlayMaxHeigth(this.alarmFilterOverlayRef); + this.resizeWindows = fromEvent(window, 'resize').subscribe(() => { + this.alarmFilterOverlayRef.updatePosition(); + }); } cancel() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index b9b8d6e65c..d005f1d9c7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -42,7 +42,7 @@ import cssjs from '@core/css/css'; import { sortItems } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; 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 { debounceTime, distinctUntilChanged, map, take, takeUntil, tap } from 'rxjs/operators'; import { MatPaginator } from '@angular/material/paginator'; @@ -123,6 +123,7 @@ import { } from '@home/components/alarm/alarm-filter-config.component'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { FormBuilder } from '@angular/forms'; +import { DEFAULT_OVERLAY_POSITIONS } from '@shared/components/popover.models'; interface AlarmsTableWidgetSettings extends TableWidgetSettings { alarmsTitle: string; @@ -572,14 +573,9 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, height: 'fit-content', maxHeight: '75vh' }); - const connectedPosition: ConnectedPosition = { - originX: 'end', - originY: 'bottom', - overlayX: 'end', - overlayY: 'top' - }; - config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement) - .withPositions([connectedPosition]); + config.positionStrategy = this.overlay.position() + .flexibleConnectedTo(target as HTMLElement) + .withPositions(DEFAULT_OVERLAY_POSITIONS); const overlayRef = this.overlay.create(config); overlayRef.backdropClick().subscribe(() => { @@ -614,10 +610,12 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, const componentRef = overlayRef.attach(new ComponentPortal(AlarmFilterConfigComponent, this.viewContainerRef, injector)); - const resizeWindows = this.utils.updateOverlayMaxHeigth(overlayRef, componentRef.location); + const resizeWindows$ = fromEvent(window, 'resize').subscribe(() => { + overlayRef.updatePosition(); + }); componentRef.onDestroy(() => { - resizeWindows.unsubscribe(); + resizeWindows$.unsubscribe(); if (componentRef.instance.panelResult) { const result = componentRef.instance.panelResult; const alarmFilter = this.entityService.resolveAlarmFilter(result, false); diff --git a/ui-ngx/src/app/shared/components/popover.models.ts b/ui-ngx/src/app/shared/components/popover.models.ts index b9ca5e9d59..5b1fd1dee3 100644 --- a/ui-ngx/src/app/shared/components/popover.models.ts +++ b/ui-ngx/src/app/shared/components/popover.models.ts @@ -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_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 { for (const placement in POSITION_MAP) { if ( diff --git a/ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss b/ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss index ff3a9c5438..74af632802 100644 --- a/ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss +++ b/ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss @@ -17,6 +17,7 @@ :host { min-width: 355px; + display: block; @media #{$mat-xs} { min-width: 0; diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index 6205667245..6482ec0dd9 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -18,9 +18,13 @@ import { ChangeDetectorRef, Component, ElementRef, - forwardRef, HostBinding, + forwardRef, + HostBinding, Injector, - Input, OnChanges, OnInit, SimpleChanges, + Input, + OnChanges, + OnInit, + SimpleChanges, StaticProvider, ViewContainerRef } from '@angular/core'; @@ -47,15 +51,18 @@ import { TimeService } from '@core/services/time.service'; import { TooltipPosition } from '@angular/material/tooltip'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; 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 { coerceBoolean } from '@shared/decorators/coercion'; import { ComponentStyle, - defaultTimewindowStyle, iconStyle, + defaultTimewindowStyle, + iconStyle, textStyle, TimewindowStyle } from '@shared/models/widget-settings.models'; +import { DEFAULT_OVERLAY_POSITIONS } from '@shared/components/popover.models'; +import { fromEvent } from 'rxjs'; // @dynamic @Component({ @@ -223,14 +230,10 @@ export class TimewindowComponent implements ControlValueAccessor, OnInit, OnChan maxHeight: '80vh', height: 'min-content' }); - const connectedPosition: ConnectedPosition = { - originX: 'start', - originY: 'bottom', - overlayX: 'start', - overlayY: 'top' - }; - config.positionStrategy = this.overlay.position().flexibleConnectedTo(this.nativeElement) - .withPositions([connectedPosition]); + + config.positionStrategy = this.overlay.position() + .flexibleConnectedTo(this.nativeElement) + .withPositions(DEFAULT_OVERLAY_POSITIONS); const overlayRef = this.overlay.create(config); overlayRef.backdropClick().subscribe(() => { @@ -257,7 +260,11 @@ export class TimewindowComponent implements ControlValueAccessor, OnInit, OnChan const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); const componentRef = overlayRef.attach(new ComponentPortal(TimewindowPanelComponent, this.viewContainerRef, injector)); + const resizeWindows$ = fromEvent(window, 'resize').subscribe(() => { + overlayRef.updatePosition(); + }); componentRef.onDestroy(() => { + resizeWindows$.unsubscribe(); if (componentRef.instance.result) { this.innerValue = componentRef.instance.result; this.timewindowDisabled = this.isTimewindowDisabled();