diff --git a/ui-ngx/src/app/core/http/client-session.service.ts b/ui-ngx/src/app/core/http/client-session.service.ts index 6dd963e96..d6ab4659f 100644 --- a/ui-ngx/src/app/core/http/client-session.service.ts +++ b/ui-ngx/src/app/core/http/client-session.service.ts @@ -78,8 +78,8 @@ export class ClientSessionService { return this.http.get(`/api/client-session/details?clientId=${encodeURIComponent(clientId)}`, defaultHttpOptionsFromConfig(config)); } - public getSessionMetrics(clientId: string, config?: RequestConfig): Observable> { - return this.statsService.getLatestTimeseries(clientId, SessionMetricsList, true, config).pipe( + public getSessionMetrics(clientId: string): Observable> { + return this.statsService.getLatestTimeseries(clientId, SessionMetricsList, true).pipe( map((metrics) => { const data = []; for (const [key, value] of Object.entries(metrics)) { diff --git a/ui-ngx/src/app/core/http/stats.service.ts b/ui-ngx/src/app/core/http/stats.service.ts index 90f2371d3..2b914308a 100644 --- a/ui-ngx/src/app/core/http/stats.service.ts +++ b/ui-ngx/src/app/core/http/stats.service.ts @@ -19,9 +19,9 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { isDefinedAndNotNull } from '@core/utils'; -import { AggregationType } from '@shared/models/time/time.models'; +import { AggregationType, Interval } from '@shared/models/time/time.models'; import { Direction } from '@shared/models/page/sort-order'; -import { CHART_ALL, TimeseriesData, timeseriesDataLimit } from '@shared/models/chart.model'; +import { CHART_ALL, TimeseriesData, MAX_DATAPOINTS_LIMIT } from '@shared/models/chart.model'; @Injectable({ providedIn: 'root' @@ -32,8 +32,8 @@ export class StatsService { } public getEntityTimeseries(entityId: string, startTs: number, endTs: number, keys: Array = CHART_ALL, - limit: number = timeseriesDataLimit, agg: AggregationType = AggregationType.NONE, interval?: number, - orderBy: Direction = Direction.DESC, useStrictDataTypes: boolean = false): Observable { + limit: number = MAX_DATAPOINTS_LIMIT, agg: AggregationType = AggregationType.NONE, interval?: Interval, + orderBy: Direction = Direction.DESC, useStrictDataTypes: boolean = true): Observable { let url = `/api/timeseries/${encodeURIComponent(entityId)}/values?keys=${keys.join(',')}&startTs=${startTs}&endTs=${endTs}`; if (isDefinedAndNotNull(limit)) { url += `&limit=${limit}`; @@ -58,7 +58,7 @@ export class StatsService { } public getLatestTimeseries(entityId: string, keys: Array = CHART_ALL, - useStrictDataTypes: boolean = false, config?: RequestConfig): Observable { + useStrictDataTypes: boolean = true): Observable { let url = `/api/timeseries/latest?entityId=${encodeURIComponent(entityId)}&keys=${keys.join(',')}`; if (isDefinedAndNotNull(useStrictDataTypes)) { url += `&useStrictDataTypes=${useStrictDataTypes}`; diff --git a/ui-ngx/src/app/core/services/time.service.ts b/ui-ngx/src/app/core/services/time.service.ts index 0b93b7fda..7c98ffd12 100644 --- a/ui-ngx/src/app/core/services/time.service.ts +++ b/ui-ngx/src/app/core/services/time.service.ts @@ -19,28 +19,19 @@ import { AggregationType, DAY, defaultTimeIntervals, - defaultTimewindow, HOUR, MINUTE, - SECOND, + defaultTimewindow, + Interval, + IntervalMath, + MINUTE, + TimeInterval, Timewindow } from '@shared/models/time/time.models'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { defaultHttpOptions } from '@core/http/http-utils'; -import { map } from 'rxjs/operators'; import { isDefined } from '@core/utils'; - -export interface TimeInterval { - name: string; - translateParams: { [key: string]: any }; - value: number; -} +import { MAX_DATAPOINTS_LIMIT } from '@app/shared/models/chart.model'; const MIN_INTERVAL = MINUTE; const MAX_INTERVAL = 365 * 20 * DAY; - -const MIN_LIMIT = 7; - -const MAX_DATAPOINTS_LIMIT = 500; +const MIN_LIMIT = 1; @Injectable({ providedIn: 'root' @@ -49,32 +40,18 @@ export class TimeService { private maxDatapointsLimit = MAX_DATAPOINTS_LIMIT; - constructor( - private http: HttpClient - ) {} - - public loadMaxDatapointsLimit(): Observable { - return this.http.get('/api/dashboard/maxDatapointsLimit', - defaultHttpOptions(true)).pipe( - map((limit) => { - this.maxDatapointsLimit = limit; - if (!this.maxDatapointsLimit || this.maxDatapointsLimit <= MIN_LIMIT) { - this.maxDatapointsLimit = MIN_LIMIT + 1; - } - return this.maxDatapointsLimit; - }) - ); - } + constructor() {} - public matchesExistingInterval(min: number, max: number, intervalMs: number): boolean { - const intervals = this.getIntervals(min, max); - return intervals.findIndex(interval => interval.value === intervalMs) > -1; + public matchesExistingInterval(min: number, max: number, interval: Interval, useCalendarIntervals = false): boolean { + const intervals = this.getIntervals(min, max, useCalendarIntervals); + return intervals.findIndex(timeInterval => timeInterval.value === interval) > -1; } - public getIntervals(min: number, max: number): Array { + public getIntervals(min: number, max: number, useCalendarIntervals = false): Array { min = this.boundMinInterval(min); max = this.boundMaxInterval(max); - return defaultTimeIntervals.filter((interval) => interval.value >= min && interval.value <= max); + return defaultTimeIntervals.filter((interval) => (useCalendarIntervals || typeof interval.value === 'number') && + IntervalMath.numberValue(interval.value) >= min && IntervalMath.numberValue(interval.value) <= max); } public boundMinInterval(min: number): number { @@ -91,35 +68,26 @@ export class TimeService { return this.toBound(max, MIN_INTERVAL, MAX_INTERVAL, MAX_INTERVAL); } - public boundToPredefinedInterval(min: number, max: number, intervalMs: number): number { - const intervals = this.getIntervals(min, max); + public boundToPredefinedInterval(min: number, max: number, interval: Interval, useCalendarIntervals = false): Interval { + const intervals = this.getIntervals(min, max, useCalendarIntervals); let minDelta = MAX_INTERVAL; - const boundedInterval = intervalMs || min; + const boundedInterval = interval || min; if (!intervals.length) { return boundedInterval; } - let matchedInterval: TimeInterval = intervals[0]; - intervals.forEach((interval) => { - const delta = Math.abs(interval.value - boundedInterval); - if (delta < minDelta) { - matchedInterval = interval; - minDelta = delta; - } - }); - return matchedInterval.value; - } - - public boundIntervalToTimewindow(timewindow: number, intervalMs: number, aggType: AggregationType): number { - if (aggType === AggregationType.NONE) { - return HOUR; + const found = intervals.find(timeInterval => timeInterval.value === boundedInterval); + if (found) { + return found.value; } else { - const min = this.minIntervalLimit(timewindow); - const max = this.maxIntervalLimit(timewindow); - if (intervalMs) { - return this.toBound(intervalMs, min, max, intervalMs); - } else { - return this.boundToPredefinedInterval(min, max, this.avgInterval(timewindow)); - } + let matchedInterval: TimeInterval = intervals[0]; + intervals.forEach((timeInterval) => { + const delta = Math.abs(IntervalMath.numberValue(timeInterval.value) - IntervalMath.numberValue(boundedInterval)); + if (delta <= minDelta) { + matchedInterval = timeInterval; + minDelta = delta; + } + }); + return matchedInterval.value; } } @@ -131,11 +99,6 @@ export class TimeService { return MIN_LIMIT; } - public avgInterval(timewindow: number): number { - const avg = timewindow / 200; - return this.boundMinInterval(avg); - } - public minIntervalLimit(timewindowMs: number): number { const min = timewindowMs / 500; return this.boundMinInterval(min); @@ -150,6 +113,18 @@ export class TimeService { return defaultTimewindow(this); } + public timewindowGroupingInterval(timewindow: Timewindow): Interval { + if (timewindow.aggregation.type === AggregationType.NONE) { + return 0; + } + if (isDefined(timewindow.realtime)) { + return timewindow.realtime.interval; + } + if (isDefined(timewindow.history)) { + return timewindow.history.interval; + } + } + private toBound(value: number, min: number, max: number, defValue: number): number { if (isDefined(value)) { value = Math.max(value, min); @@ -159,5 +134,4 @@ export class TimeService { return defValue; } } - } diff --git a/ui-ngx/src/app/modules/home/components/getting-started/getting-started-home.component.ts b/ui-ngx/src/app/modules/home/components/getting-started/getting-started-home.component.ts index 16fcc0f54..d50910f92 100644 --- a/ui-ngx/src/app/modules/home/components/getting-started/getting-started-home.component.ts +++ b/ui-ngx/src/app/modules/home/components/getting-started/getting-started-home.component.ts @@ -14,8 +14,6 @@ /// limitations under the License. /// -// @ts-nocheck - import { Component, OnInit } from '@angular/core'; import { Observable, of } from 'rxjs'; import { InstructionsService } from '@core/http/instructions.service'; diff --git a/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.html b/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.html index 95d42c749..7daacabef 100644 --- a/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.html +++ b/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.html @@ -22,8 +22,7 @@ asButton flatButton tooltipPosition="left" - aggregation="false" - timezone="false"> + aggregation="true">
diff --git a/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.ts b/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.ts index ffa4fdec9..a01d93f32 100644 --- a/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.ts +++ b/ui-ngx/src/app/modules/home/pages/monitoring/monitoring.component.ts @@ -14,35 +14,40 @@ /// limitations under the License. /// -// @ts-nocheck - import { AfterViewInit, ChangeDetectorRef, Component, + ElementRef, OnDestroy, OnInit, + QueryList, ViewChildren } from '@angular/core'; -import { calculateFixedWindowTimeMs, FixedWindow, Timewindow, TimewindowType } from '@shared/models/time/time.models'; +import { + calculateFixedWindowTimeMs, + FixedWindow, + Timewindow, + TimewindowType +} from '@shared/models/time/time.models'; import { forkJoin, Observable, Subject, timer } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; import { TimeService } from '@core/services/time.service'; import { StatsService } from '@core/http/stats.service'; import { share, switchMap, takeUntil } from 'rxjs/operators'; import { - CHART_TOTAL_ONLY, CHART_ALL, + CHART_TOTAL_ONLY, chartJsParams, ChartPage, ChartTooltipTranslationMap, getColor, LegendConfig, LegendKey, + MAX_DATAPOINTS_LIMIT, StatsChartType, StatsChartTypeTranslationMap, TimeseriesData, - timeseriesDataLimit, TOTAL_KEY } from '@shared/models/chart.model'; import { PageComponent } from '@shared/components/page.component'; @@ -63,7 +68,7 @@ import { calculateTotal, convertDataSizeUnits } from '@core/utils'; -import { ChartDataSets } from 'chart.js'; +import { ChartConfiguration, ChartDataset } from 'chart.js'; Chart.register([Zoom]); @@ -105,8 +110,8 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV private fixedWindowTimeMs: FixedWindow; private brokerIds: string[]; - private stopPolling$ = new Subject(); - private destroy$ = new Subject(); + private stopPolling$ = new Subject(); + private destroy$ = new Subject(); chartTooltip = (chartType: string) => this.translate.instant(ChartTooltipTranslationMap.get(chartType)); @@ -153,7 +158,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - onFullScreen(chartType: string) { + onFullScreen(chartType?: string) { this.isFullscreen = !this.isFullscreen; if (this.isFullscreen) { this.fullscreenChart = chartType; @@ -214,8 +219,8 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - totalOnly(chartType: StatsChartType): boolean { - return CHART_TOTAL_ONLY.includes(chartType); + totalOnly(chartType: string): boolean { + return CHART_TOTAL_ONLY.includes(chartType as StatsChartType); } private initData() { @@ -229,7 +234,17 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV private fetchEntityTimeseries(initCharts = false) { const $getEntityTimeseriesTasks: Observable[] = []; for (const brokerId of this.brokerIds) { - $getEntityTimeseriesTasks.push(this.statsService.getEntityTimeseries(brokerId, this.fixedWindowTimeMs.startTimeMs, this.fixedWindowTimeMs.endTimeMs, CHART_ALL)); + $getEntityTimeseriesTasks.push( + this.statsService.getEntityTimeseries( + brokerId, + this.fixedWindowTimeMs.startTimeMs, + this.fixedWindowTimeMs.endTimeMs, + CHART_ALL, + MAX_DATAPOINTS_LIMIT, + this.timewindow.aggregation.type, + this.timeService.timewindowGroupingInterval(this.timewindow) + ) + ); } forkJoin($getEntityTimeseriesTasks) .pipe(takeUntil(this.stopPolling$)) @@ -276,7 +291,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } const params = {...chartJsParams(this.chartPage), ...datasets}; - this.charts[chartType] = new Chart(ctx, params); + this.charts[chartType] = new Chart(ctx, params as ChartConfiguration); if (chartType === StatsChartType.processedBytes) { this.charts[chartType].options.plugins.tooltip.callbacks.label = (context) => { const value = Number.isInteger(context.parsed.y) ? context.parsed.y : context.parsed.y.toFixed(2); @@ -291,7 +306,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - private getDataset(dataset, chartType, i, brokerId): ChartDataSets { + private getDataset(dataset, chartType, i, brokerId): ChartDataset { const color = getColor(chartType, i); return { label: brokerId, @@ -333,10 +348,11 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV this.fixedWindowTimeMs.endTimeMs += POLLING_INTERVAL; } - private prepareData(chartType: StatsChartType, data: TimeseriesData[]) { + private prepareData(chartType: string, data: TimeseriesData[]) { if (chartType === StatsChartType.processedBytes) { const tsValue = data[0][StatsChartType.processedBytes][0]; data[0][StatsChartType.processedBytes][0] = { + // @ts-ignore value: convertDataSizeUnits(tsValue.value, DataSizeUnitType.BYTE, this.currentDataSizeUnitType), ts: tsValue.ts } @@ -391,7 +407,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV for (const brokerData of data) { for (const key in brokerData) { const dataLength = brokerData[key].length; - if (dataLength === timeseriesDataLimit) { + if (dataLength === MAX_DATAPOINTS_LIMIT) { showWarning = true; break; } @@ -410,17 +426,17 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - private resetLegendKeys(chartType: StatsChartType) { + private resetLegendKeys(chartType: string) { this.legendKeys[chartType] = {}; this.legendKeys[chartType].keys = []; } - private resetLegendData(chartType: StatsChartType) { + private resetLegendData(chartType: string) { this.legendData[chartType] = {}; this.legendData[chartType].data = []; } - private updateLegendKeys(chartType: StatsChartType) { + private updateLegendKeys(chartType: string) { for (let i = 0; i < this.brokerIds.length; i++) { const color = getColor(chartType, i); const brokerId = this.brokerIds[i]; @@ -434,7 +450,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - private updateLegendData(data: any[], chartType: StatsChartType) { + private updateLegendData(data: any[], chartType: string) { if (data?.length) { this.legendData[chartType].data.push({ min: Math.floor(calculateMin(data)), @@ -454,7 +470,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV } } - private addLegendKey(chartType: StatsChartType, index: number, brokerId: string, color: string) { + private addLegendKey(chartType: string, index: number, brokerId: string, color: string) { this.legendKeys[chartType].keys.push({ dataKey: { label: brokerId, @@ -465,7 +481,7 @@ export class MonitoringComponent extends PageComponent implements OnInit, AfterV }); } - private updateLegend(chartType: StatsChartType) { + private updateLegend(chartType: string) { this.resetLegendData(chartType); for (let i = 0; i < this.brokerIds.length; i++) { const brokerId = this.brokerIds[i]; diff --git a/ui-ngx/src/app/shared/components/time/datetime-period.component.html b/ui-ngx/src/app/shared/components/time/datetime-period.component.html index 0a798c3dd..fd6c1cf85 100644 --- a/ui-ngx/src/app/shared/components/time/datetime-period.component.html +++ b/ui-ngx/src/app/shared/components/time/datetime-period.component.html @@ -19,13 +19,13 @@
- datetime.date-from + datetime.date-from - datetime.time-from + datetime.time-from @@ -34,13 +34,13 @@
- datetime.date-to + datetime.date-to - datetime.time-to + datetime.time-to diff --git a/ui-ngx/src/app/shared/components/time/datetime-period.component.scss b/ui-ngx/src/app/shared/components/time/datetime-period.component.scss index 1177b0bbe..c074b5c1d 100644 --- a/ui-ngx/src/app/shared/components/time/datetime-period.component.scss +++ b/ui-ngx/src/app/shared/components/time/datetime-period.component.scss @@ -16,14 +16,8 @@ @import 'constants'; :host ::ng-deep { - .mat-form-field-wrapper { - padding-bottom: 8px; - } - .mat-form-field-underline { - bottom: 8px; - } - .mat-form-field-infix { - width: 150px; + .mat-mdc-form-field-infix { + width: 100px; @media #{$mat-xs} { width: 100%; diff --git a/ui-ngx/src/app/shared/components/time/datetime.component.scss b/ui-ngx/src/app/shared/components/time/datetime.component.scss deleted file mode 100644 index 017d2fb28..000000000 --- a/ui-ngx/src/app/shared/components/time/datetime.component.scss +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright © 2016-2024 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -:host ::ng-deep { - .mat-form-field-wrapper { - padding-bottom: 8px; - } - .mat-form-field-underline { - bottom: 8px; - } - .mat-form-field-infix { - width: auto; - min-width: 100px; - } - mat-form-field { - &.no-label { - .mat-form-field-infix { - border-top-width: 0.2em; - } - } - } -} diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.html b/ui-ngx/src/app/shared/components/time/timeinterval.component.html index f740efb96..04292b4d9 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.html +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.html @@ -15,13 +15,12 @@ limitations under the License. --> -
-
+
+
-
timeinterval.days @@ -41,18 +40,18 @@
-
- - {{ predefinedName }} - +
+ + {{ predefinedName }} + {{ interval.name | translate:interval.translateParams }}
- +
diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.scss b/ui-ngx/src/app/shared/components/time/timeinterval.component.scss index 6eb24d1ef..69e6344e8 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.scss +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.scss @@ -47,8 +47,8 @@ :host ::ng-deep { .number-input { - .mat-form-field-infix { - width: 70px; + .mat-mdc-form-field-infix { + width: 50px; } } } diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts index e2ca42276..8ed6fb203 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts @@ -16,8 +16,12 @@ import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { TimeInterval, TimeService } from '@core/services/time.service'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { TimeService } from '@core/services/time.service'; +import { coerceNumberProperty } from '@angular/cdk/coercion'; +import { SubscriptSizing } from '@angular/material/form-field'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { Interval, IntervalMath, TimeInterval } from '@shared/models/time/time.models'; +import { isDefined } from '@core/utils'; @Component({ selector: 'tb-timeinterval', @@ -38,8 +42,9 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { @Input() set min(min: number) { - if (typeof min !== 'undefined' && min !== this.minValue) { - this.minValue = min; + const minValueData = coerceNumberProperty(min); + if (typeof minValueData !== 'undefined' && minValueData !== this.minValue) { + this.minValue = minValueData; this.maxValue = Math.max(this.maxValue, this.minValue); this.updateView(); } @@ -47,55 +52,56 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { @Input() set max(max: number) { - if (typeof max !== 'undefined' && max !== this.maxValue) { - this.maxValue = max; + const maxValueData = coerceNumberProperty(max); + if (typeof maxValueData !== 'undefined' && maxValueData !== this.maxValue) { + this.maxValue = maxValueData; this.minValue = Math.min(this.minValue, this.maxValue); - this.updateView(); + this.updateView(true); } } @Input() predefinedName: string; - isEditValue = false; - @Input() - set isEdit(val) { - this.isEditValue = coerceBooleanProperty(val); - } - - get isEdit() { - return this.isEditValue; - } + @coerceBoolean() + isEdit = false; - hideFlagValue = false; + @Input() + @coerceBoolean() + hideFlag = false; @Input() - get hideFlag() { - return this.hideFlagValue; - } + @coerceBoolean() + disabledAdvanced = false; - set hideFlag(val) { - this.hideFlagValue = val; - } + @Input() + @coerceBoolean() + useCalendarIntervals = false; @Output() hideFlagChange = new EventEmitter(); @Input() disabled: boolean; + @Input() + subscriptSizing: SubscriptSizing = 'fixed'; + days = 0; hours = 0; mins = 1; secs = 0; - intervalMs = 0; - modelValue: number; + interval: Interval = 0; + intervals: Array; advanced = false; - rendered = false; - intervals: Array; + private modelValue: Interval; + private rendered = false; + private propagateChangeValue: any; - private propagateChange = (_: any) => {}; + private propagateChange = (value: any) => { + this.propagateChangeValue = value; + }; constructor(private timeService: TimeService) { } @@ -106,6 +112,9 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { registerOnChange(fn: any): void { this.propagateChange = fn; + if (isDefined(this.propagateChangeValue)) { + this.propagateChange(this.propagateChangeValue); + } } registerOnTouched(fn: any): void { @@ -115,101 +124,102 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { this.disabled = isDisabled; } - writeValue(intervalMs: number): void { - this.modelValue = intervalMs; + writeValue(interval: Interval): void { + this.modelValue = interval; this.rendered = true; if (typeof this.modelValue !== 'undefined') { const min = this.timeService.boundMinInterval(this.minValue); const max = this.timeService.boundMaxInterval(this.maxValue); - if (this.modelValue >= min && this.modelValue <= max) { - this.advanced = !this.timeService.matchesExistingInterval(this.minValue, this.maxValue, this.modelValue); - this.setIntervalMs(this.modelValue); + if (IntervalMath.numberValue(this.modelValue) >= min && IntervalMath.numberValue(this.modelValue) <= max) { + this.advanced = !this.timeService.matchesExistingInterval(this.minValue, this.maxValue, this.modelValue, this.useCalendarIntervals); + this.setInterval(this.modelValue); } else { this.boundInterval(); } } } - setIntervalMs(intervalMs: number) { + private setInterval(interval: Interval) { if (!this.advanced) { - this.intervalMs = intervalMs; + this.interval = interval; } - const intervalSeconds = Math.floor(intervalMs / 1000); + const intervalSeconds = Math.floor(IntervalMath.numberValue(interval) / 1000); this.days = Math.floor(intervalSeconds / 86400); this.hours = Math.floor((intervalSeconds % 86400) / 3600); this.mins = Math.floor(((intervalSeconds % 86400) % 3600) / 60); this.secs = intervalSeconds % 60; } - boundInterval() { + private boundInterval(updateToPreferred = false) { const min = this.timeService.boundMinInterval(this.minValue); const max = this.timeService.boundMaxInterval(this.maxValue); - this.intervals = this.timeService.getIntervals(this.minValue, this.maxValue); + this.intervals = this.timeService.getIntervals(this.minValue, this.maxValue, this.useCalendarIntervals); if (this.rendered) { - let newIntervalMs = this.modelValue; + let newInterval = this.modelValue; + const newIntervalMs = IntervalMath.numberValue(newInterval); if (newIntervalMs < min) { - newIntervalMs = min; - } else if (newIntervalMs > max) { - newIntervalMs = max; + newInterval = min; + } else if (newIntervalMs >= max && updateToPreferred) { + newInterval = this.timeService.boundMaxInterval(max / 7); } if (!this.advanced) { - newIntervalMs = this.timeService.boundToPredefinedInterval(min, max, newIntervalMs); + newInterval = this.timeService.boundToPredefinedInterval(min, max, newInterval, this.useCalendarIntervals); } - if (newIntervalMs !== this.modelValue) { - this.setIntervalMs(newIntervalMs); + if (newInterval !== this.modelValue) { + this.setInterval(newInterval); this.updateView(); } } } - updateView() { + private updateView(updateToPreferred = false) { if (!this.rendered) { return; } - let value = null; - let intervalMs; + let value: Interval = null; + let interval: Interval; if (!this.advanced) { - intervalMs = this.intervalMs; - if (!intervalMs || isNaN(intervalMs)) { - intervalMs = this.calculateIntervalMs(); + interval = this.interval; + if (!interval || typeof interval === 'number' && isNaN(interval)) { + interval = this.calculateIntervalMs(); } } else { - intervalMs = this.calculateIntervalMs(); + interval = this.calculateIntervalMs(); } - if (!isNaN(intervalMs) && intervalMs > 0) { - value = intervalMs; + if (typeof interval === 'string' || !isNaN(interval) && interval > 0) { + value = interval; } this.modelValue = value; this.propagateChange(this.modelValue); - this.boundInterval(); + this.boundInterval(updateToPreferred); } - calculateIntervalMs(): number { + private calculateIntervalMs(): number { return (this.days * 86400 + this.hours * 3600 + this.mins * 60 + this.secs) * 1000; } - onIntervalMsChange() { + onIntervalChange() { this.updateView(); } onAdvancedChange() { if (!this.advanced) { - this.intervalMs = this.calculateIntervalMs(); + this.interval = this.calculateIntervalMs(); } else { - let intervalMs = this.intervalMs; - if (!intervalMs || isNaN(intervalMs)) { - intervalMs = this.calculateIntervalMs(); + let interval = this.interval; + if (!interval || typeof interval === 'number' && isNaN(interval)) { + interval = this.calculateIntervalMs(); } - this.setIntervalMs(intervalMs); + this.setInterval(interval); } this.updateView(); } onHideFlagChange() { - this.hideFlagChange.emit(this.hideFlagValue); + this.hideFlagChange.emit(this.hideFlag); } onTimeInputChange(type: string) { @@ -229,7 +239,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { } } - onSecsChange() { + private onSecsChange() { if (typeof this.secs === 'undefined') { return; } @@ -249,7 +259,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { this.updateView(); } - onMinsChange() { + private onMinsChange() { if (typeof this.mins === 'undefined') { return; } @@ -269,7 +279,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { this.updateView(); } - onHoursChange() { + private onHoursChange() { if (typeof this.hours === 'undefined') { return; } @@ -289,7 +299,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor { this.updateView(); } - onDaysChange() { + private onDaysChange() { if (typeof this.days === 'undefined') { return; } 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 7ff430ee7..996bb9ecb 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 @@ -16,138 +16,207 @@ -->
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- timewindow.last - -
+ + +
+
+
+ + +
+
+ +
- - -
-
- - -
-
- timewindow.interval - -
-
-
- - - -
-
-
-
- -
-
- - -
-
-
- - -
- timewindow.for-all-time -
-
-
timewindow.last
-
- -
- timewindow.time-period - +
+
+ +
+
+ +
- -
timewindow.interval
-
- -
-
+
+ + + + +
+
+
+
+ +
+
+
+ + +
+ timewindow.for-all-time +
+
+ +
+ timewindow.last + +
+
+ +
+ timewindow.time-period + +
+
+ +
+ timewindow.interval + +
+
+
+
+
+
+ + +
+
+ +
+
+
+ +
- - -
-
+
+ + aggregation.function + + + {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }} + + + +
+
+
+
+ + +
+ +
+
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+