diff --git a/ui-ngx/src/app/core/services/time.service.ts b/ui-ngx/src/app/core/services/time.service.ts index 62d5a3507c..c60ee89222 100644 --- a/ui-ngx/src/app/core/services/time.service.ts +++ b/ui-ngx/src/app/core/services/time.service.ts @@ -19,13 +19,18 @@ import { AggregationType, DAY, defaultTimeIntervals, - defaultTimewindow, Interval, IntervalMath, + defaultTimewindow, + getDefaultTimezoneInfo, + Interval, + IntervalMath, SECOND, TimeInterval, - Timewindow + Timewindow, + TimezoneInfo } from '@shared/models/time/time.models'; import { HttpClient } from '@angular/common/http'; -import { isDefined } from '@core/utils'; +import { deepClone, isDefined } from '@core/utils'; +import { TranslateService } from '@ngx-translate/core'; const MIN_INTERVAL = SECOND; const MAX_INTERVAL = 365 * 20 * DAY; @@ -41,8 +46,11 @@ export class TimeService { private maxDatapointsLimit = MAX_DATAPOINTS_LIMIT; + private localBrowserTimezoneInfoPlaceholder: TimezoneInfo; + constructor( - private http: HttpClient + private http: HttpClient, + private translate: TranslateService ) {} public setMaxDatapointsLimit(limit: number) { @@ -161,4 +169,13 @@ export class TimeService { return defValue; } } + + public getLocalBrowserTimezoneInfoPlaceholder(): TimezoneInfo { + if (!this.localBrowserTimezoneInfoPlaceholder) { + this.localBrowserTimezoneInfoPlaceholder = deepClone(getDefaultTimezoneInfo()); + this.localBrowserTimezoneInfoPlaceholder.id = null; + this.localBrowserTimezoneInfoPlaceholder.name = this.translate.instant('timezone.browser-time'); + } + return this.localBrowserTimezoneInfoPlaceholder; + } } diff --git a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.html b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.html index 7d8546c021..39c8de97e1 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.html @@ -59,10 +59,12 @@ - +
+
{{ 'timezone.timezone' | translate }}
- +
@@ -115,10 +117,12 @@
- +
+
{{ 'timezone.timezone' | translate }}
- +
@@ -189,7 +193,10 @@ - + + diff --git a/ui-ngx/src/app/shared/components/time/timezone-panel.component.html b/ui-ngx/src/app/shared/components/time/timezone-panel.component.html index 0dae7823ec..3e4b128226 100644 --- a/ui-ngx/src/app/shared/components/time/timezone-panel.component.html +++ b/ui-ngx/src/app/shared/components/time/timezone-panel.component.html @@ -1,10 +1,11 @@
{{ 'timezone.timezone' | translate }}
- + appearance="outline" + displayLabel="false">
diff --git a/ui-ngx/src/app/shared/components/time/timezone-panel.component.scss b/ui-ngx/src/app/shared/components/time/timezone-panel.component.scss index 031d2bb5da..c25c4cdf50 100644 --- a/ui-ngx/src/app/shared/components/time/timezone-panel.component.scss +++ b/ui-ngx/src/app/shared/components/time/timezone-panel.component.scss @@ -18,13 +18,14 @@ :host { display: flex; flex-direction: column; + width: 380px; max-height: 100%; max-width: 100%; background-color: #fff; .tb-form-panel { padding: 12px; - gap: 12px; + gap: 24px; } .tb-flex { diff --git a/ui-ngx/src/app/shared/components/time/timezone-panel.component.ts b/ui-ngx/src/app/shared/components/time/timezone-panel.component.ts index 4b6eb468aa..361902f51d 100644 --- a/ui-ngx/src/app/shared/components/time/timezone-panel.component.ts +++ b/ui-ngx/src/app/shared/components/time/timezone-panel.component.ts @@ -14,22 +14,17 @@ /// limitations under the License. /// -import { Component, Inject, InjectionToken, OnInit, ViewContainerRef } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; -import { OverlayRef } from '@angular/cdk/overlay'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { TimeService } from '@core/services/time.service'; -import { TranslateService } from '@ngx-translate/core'; +import { TbPopoverComponent } from '@shared/components/popover.component'; -export interface TimezonePanelData { - timezone: string; - isEdit: boolean; +export interface TimezoneSelectionResult { + timezone: string | null; } -export const TIMEZONE_PANEL_DATA = new InjectionToken('TimezonePanelData'); - @Component({ selector: 'tb-timezone-panel', templateUrl: './timezone-panel.component.html', @@ -37,35 +32,49 @@ export const TIMEZONE_PANEL_DATA = new InjectionToken('TimezonePanelData'); }) export class TimezonePanelComponent extends PageComponent implements OnInit { - timezone: string; - result: string; + @Input() + timezone: string | null; + + @Input() + userTimezoneByDefault: boolean; + + @Input() + localBrowserTimezonePlaceholderOnEmpty: boolean; + + @Input() + defaultTimezone: string; + + @Input() + onClose: (result: TimezoneSelectionResult | null) => void; + + @Input() + popoverComponent: TbPopoverComponent; timezoneForm: FormGroup; - constructor(@Inject(TIMEZONE_PANEL_DATA) public data: TimezonePanelData, - public overlayRef: OverlayRef, - protected store: Store, - public fb: FormBuilder, - private timeService: TimeService, - private translate: TranslateService, - public viewContainerRef: ViewContainerRef) { + constructor(protected store: Store, + public fb: FormBuilder) { super(store); - this.timezone = this.data.timezone; - this.timezoneForm = this.fb.group({ - timezone: [this.timezone] - }); } ngOnInit(): void { + this.timezoneForm = this.fb.group({ + timezone: [this.timezone] + }); } update() { - this.result = this.timezoneForm.get('timezone').value; - this.overlayRef.dispose(); + if (this.onClose) { + this.onClose({ + timezone: this.timezoneForm.get('timezone').value + }); + } } cancel() { - this.overlayRef.dispose(); + if (this.onClose) { + this.onClose(null); + } } } diff --git a/ui-ngx/src/app/shared/components/time/timezone-select.component.html b/ui-ngx/src/app/shared/components/time/timezone-select.component.html index 280a58e4b8..c9a9724aaa 100644 --- a/ui-ngx/src/app/shared/components/time/timezone-select.component.html +++ b/ui-ngx/src/app/shared/components/time/timezone-select.component.html @@ -17,7 +17,7 @@ --> - timezone.timezone + timezone.timezone ; @@ -107,7 +113,8 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af constructor(private store: Store, public translate: TranslateService, private ngZone: NgZone, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private timeService: TimeService) { this.selectTimezoneFormGroup = this.fb.group({ timezone: [null] }); @@ -168,7 +175,7 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af } else { this.modelValue = null; if (this.localBrowserTimezonePlaceholderOnEmptyValue) { - this.selectTimezoneFormGroup.get('timezone').patchValue(this.getLocalBrowserTimezoneInfoPlaceholder(), {emitEvent: false}); + this.selectTimezoneFormGroup.get('timezone').patchValue(this.localBrowserTimezoneInfoPlaceholder, {emitEvent: false}); } else { this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false}); } @@ -197,7 +204,7 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af } } else if (this.localBrowserTimezonePlaceholderOnEmptyValue) { this.ngZone.run(() => { - this.selectTimezoneFormGroup.get('timezone').reset(this.getLocalBrowserTimezoneInfoPlaceholder(), {emitEvent: true}); + this.selectTimezoneFormGroup.get('timezone').reset(this.localBrowserTimezoneInfoPlaceholder, {emitEvent: true}); }); } } @@ -235,19 +242,11 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af if (!this.timezones) { this.timezones = []; if (this.localBrowserTimezonePlaceholderOnEmptyValue) { - this.timezones.push(this.getLocalBrowserTimezoneInfoPlaceholder()); + this.timezones.push(this.localBrowserTimezoneInfoPlaceholder); } this.timezones.push(...getTimezones()); } return this.timezones; } - private getLocalBrowserTimezoneInfoPlaceholder(): TimezoneInfo { - if (!this.localBrowserTimezoneInfoPlaceholder) { - this.localBrowserTimezoneInfoPlaceholder = deepClone(getDefaultTimezoneInfo()); - this.localBrowserTimezoneInfoPlaceholder.id = null; - this.localBrowserTimezoneInfoPlaceholder.name = this.translate.instant('timezone.browser-time'); - } - return this.localBrowserTimezoneInfoPlaceholder; - } } diff --git a/ui-ngx/src/app/shared/components/time/timezone.component.html b/ui-ngx/src/app/shared/components/time/timezone.component.html index 5aff9da59c..7977f24081 100644 --- a/ui-ngx/src/app/shared/components/time/timezone.component.html +++ b/ui-ngx/src/app/shared/components/time/timezone.component.html @@ -17,6 +17,8 @@ -->
{{ computedTimezoneStyle.icon }} -
- {{innerValue}} +
+ {{timezoneInfo}}
{{ computedTimezoneStyle.icon }} diff --git a/ui-ngx/src/app/shared/components/time/timezone.component.scss b/ui-ngx/src/app/shared/components/time/timezone.component.scss index 99f3d8367d..db4f492985 100644 --- a/ui-ngx/src/app/shared/components/time/timezone.component.scss +++ b/ui-ngx/src/app/shared/components/time/timezone.component.scss @@ -23,7 +23,7 @@ .mdc-button { max-width: 100%; } - section.tb-timewindow { + section.tb-timezone { padding: 0 8px; &.no-padding { padding: 0; @@ -38,7 +38,7 @@ gap: 4px; width: 100%; - .tb-timewindow-label { + .tb-timezone-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/ui-ngx/src/app/shared/components/time/timezone.component.ts b/ui-ngx/src/app/shared/components/time/timezone.component.ts index 79fe0b870f..8f0f2eee40 100644 --- a/ui-ngx/src/app/shared/components/time/timezone.component.ts +++ b/ui-ngx/src/app/shared/components/time/timezone.component.ts @@ -17,26 +17,19 @@ import { ChangeDetectorRef, Component, - ElementRef, forwardRef, HostBinding, - Injector, Input, OnChanges, - OnInit, Renderer2, + OnInit, + Renderer2, SimpleChanges, - StaticProvider, ViewContainerRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; -import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; -import { DatePipe } from '@angular/common'; -import { TimeService } from '@core/services/time.service'; import { TooltipPosition } from '@angular/material/tooltip'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal } from '@angular/cdk/portal'; import { coerceBoolean } from '@shared/decorators/coercion'; import { ComponentStyle, @@ -45,15 +38,10 @@ import { textStyle, TimezoneStyle } from '@shared/models/widget-settings.models'; -import { DEFAULT_OVERLAY_POSITIONS } from '@shared/models/overlay.models'; -import { fromEvent } from 'rxjs'; -import { - TIMEZONE_PANEL_DATA, - TimezonePanelComponent, - TimezonePanelData -} from '@shared/components/time/timezone-panel.component'; +import { TimezonePanelComponent, TimezoneSelectionResult } from '@shared/components/time/timezone-panel.component'; import { TbPopoverService } from '@shared/components/popover.service'; -import { TimewindowStylePanelComponent } from '@home/components/widget/config/timewindow-style-panel.component'; +import { getTimezoneInfo, TimezoneInfo } from '@shared/models/time/time.models'; +import { TimeService } from '@core/services/time.service'; // @dynamic @Component({ @@ -83,10 +71,6 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange @coerceBoolean() disablePanel = false; - @Input() - @coerceBoolean() - isToolbar = false; - @Input() @coerceBoolean() asButton = false; @@ -145,7 +129,8 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange @Input() set localBrowserTimezonePlaceholderOnEmpty(value: boolean) { this.localBrowserTimezonePlaceholderOnEmptyValue = coerceBooleanProperty(value); - }defaultTimezoneId: string = null; + } + defaultTimezoneId: string = null; @Input() set defaultTimezone(timezone: string) { @@ -163,7 +148,10 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange this.requiredValue = coerceBooleanProperty(value); } - innerValue: string; + modelValue: string | null; + timezoneInfo: TimezoneInfo; + + private localBrowserTimezoneInfoPlaceholder: TimezoneInfo = this.timeService.getLocalBrowserTimezoneInfoPlaceholder(); timezoneDisabled: boolean; @@ -173,16 +161,12 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange private propagateChange = (_: any) => {}; - constructor(private overlay: Overlay, - private translate: TranslateService, - private timeService: TimeService, - private millisecondsToTimeStringPipe: MillisecondsToTimeStringPipe, - private datePipe: DatePipe, + constructor(private translate: TranslateService, private cd: ChangeDetectorRef, - private nativeElement: ElementRef, public viewContainerRef: ViewContainerRef, private popoverService: TbPopoverService, - private renderer: Renderer2) { + private renderer: Renderer2, + private timeService: TimeService) { } ngOnInit() { @@ -202,82 +186,38 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange } toggleTimezone($event: Event) { - console.log($event); if ($event) { $event.stopPropagation(); } if (this.disablePanel) { return; } - // const trigger = ($event.target || $event.srcElement || $event.currentTarget) as Element; - // if (this.popoverService.hasPopover(trigger)) { - // this.popoverService.hidePopover(trigger); - // } else { - // const timezoneSelectionPopover = this.popoverService.displayPopover(trigger, this.renderer, - // this.viewContainerRef, TimewindowStylePanelComponent, 'left', true, null, - // ctx, - // {}, - // {}, {}, true); - // timewindowStylePanelPopover.tbComponentRef.instance.popover = timewindowStylePanelPopover; - // timewindowStylePanelPopover.tbComponentRef.instance.timewindowStyleApplied.subscribe((timewindowStyle) => { - // timewindowStylePanelPopover.hide(); - // this.modelValue = timewindowStyle; - // this.propagateChange(this.modelValue); - // }); - // - // // if (componentRef.instance.result) { - // // this.innerValue = componentRef.instance.result; - // // this.timezoneDisabled = this.isTimezoneDisabled(); - // // this.updateDisplayValue(); - // // this.notifyChanged(); - // // } - // } - const config = new OverlayConfig({ - panelClass: 'tb-timezone-panel', - backdropClass: 'cdk-overlay-transparent-backdrop', - hasBackdrop: true, - maxHeight: '30vh', - height: 'min-content' - }); - - config.positionStrategy = this.overlay.position() - .flexibleConnectedTo(this.nativeElement) - .withPositions(DEFAULT_OVERLAY_POSITIONS); - - // TODO: change panel to popover - const overlayRef = this.overlay.create(config); - overlayRef.backdropClick().subscribe(() => { - overlayRef.dispose(); - }); - const providers: StaticProvider[] = [ - { - provide: TIMEZONE_PANEL_DATA, - useValue: { - timezone: this.innerValue, - isEdit: this.isEdit - } as TimezonePanelData - }, - { - provide: OverlayRef, - useValue: overlayRef - } - ]; - const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); - const componentRef = overlayRef.attach(new ComponentPortal(TimezonePanelComponent, - this.viewContainerRef, injector)); - const resizeWindows$ = fromEvent(window, 'resize').subscribe(() => { - overlayRef.updatePosition(); - }); - componentRef.onDestroy(() => { - resizeWindows$.unsubscribe(); - // TODO: if value check makes impossible to select browser timezone (null) - if (componentRef.instance.result) { - this.innerValue = componentRef.instance.result; - this.timezoneDisabled = this.isTimezoneDisabled(); - this.updateDisplayValue(); - this.notifyChanged(); - } - }); + const trigger = ($event.target || $event.srcElement || $event.currentTarget) as Element; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const timezoneSelectionPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, TimezonePanelComponent, ['bottomRight', 'leftBottom'], true, null, + { + timezone: this.modelValue, + userTimezoneByDefault: this.userTimezoneByDefaultValue, + localBrowserTimezonePlaceholderOnEmpty: this.localBrowserTimezonePlaceholderOnEmptyValue, + defaultTimezone: this.defaultTimezoneId, + onClose: (result: TimezoneSelectionResult | null) => { + timezoneSelectionPopover.hide(); + if (result) { + this.modelValue = result.timezone; + this.setTimezoneInfo(); + this.timezoneDisabled = this.isTimezoneDisabled(); + this.updateDisplayValue(); + this.notifyChanged(); + } + } + }, + {}, + {}, {}, true); + timezoneSelectionPopover.tbComponentRef.instance.popoverComponent = timezoneSelectionPopover; + } this.cd.detectChanges(); } @@ -304,19 +244,23 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange this.timezoneDisabled = this.isTimezoneDisabled(); } - writeValue(value: string): void { - this.innerValue = value; + writeValue(value: string | null): void { + this.modelValue = value; + this.setTimezoneInfo(); this.timezoneDisabled = this.isTimezoneDisabled(); this.updateDisplayValue(); } notifyChanged() { - this.propagateChange(this.innerValue); + this.propagateChange(this.modelValue); } displayValue(): string { - // TODO: only offset should be displayed, timezone name shouldn't be present - return this.displayTimezoneValue ? this.innerValue : this.translate.instant('timezone.timezone'); + return this.displayTimezoneValue && this.timezoneInfo ? this.timezoneInfo.offset : this.translate.instant('timezone.timezone'); + } + + tooltipValue(): string { + return this.timezoneInfo ? `${this.timezoneInfo.name} (${this.timezoneInfo.offset})` : undefined; } updateDisplayValue() { @@ -327,4 +271,17 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit, OnChange return this.disabled; } + private setTimezoneInfo() { + const foundTimezone = getTimezoneInfo(this.modelValue, this.defaultTimezoneId, this.userTimezoneByDefaultValue); + if (foundTimezone !== null) { + this.timezoneInfo = foundTimezone; + } else { + if (this.localBrowserTimezonePlaceholderOnEmptyValue) { + this.timezoneInfo = this.localBrowserTimezoneInfoPlaceholder; + } else { + this.timezoneInfo = null; + } + } + } + } diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 08850ddbe8..4d5ae09a15 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -268,7 +268,7 @@ pre.tb-highlight { letter-spacing: normal; } -.tb-timewindow-panel, .tb-legend-config-panel, .tb-filter-panel, .tb-panel-container, tb-timezone-panel { +.tb-timewindow-panel, .tb-legend-config-panel, .tb-filter-panel, .tb-panel-container { overflow: hidden; background: #fff; border-radius: 4px;