Browse Source

Merge branch 'feature/timeWindow/quick-interval' of https://github.com/vvlladd28/thingsboard into vvlladd28-feature/timeWindow/quick-interval

pull/4259/head
Igor Kulikov 6 years ago
parent
commit
d184d8db72
  1. 23
      ui-ngx/src/app/core/api/data-aggregator.ts
  2. 3
      ui-ngx/src/app/core/api/entity-data-subscription.ts
  3. 10
      ui-ngx/src/app/core/api/widget-subscription.ts
  4. 27
      ui-ngx/src/app/shared/components/time/quick-time-interval.component.html
  5. 19
      ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss
  6. 79
      ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts
  7. 58
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.html
  8. 52
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts
  9. 14
      ui-ngx/src/app/shared/components/time/timewindow.component.ts
  10. 249
      ui-ngx/src/app/shared/models/time/time.models.ts
  11. 3
      ui-ngx/src/app/shared/shared.module.ts
  12. 22
      ui-ngx/src/assets/locale/locale.constant-en_US.json

23
ui-ngx/src/app/core/api/data-aggregator.ts

@ -15,7 +15,12 @@
///
import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models';
import { AggregationType } from '@shared/models/time/time.models';
import {
AggregationType,
calculateIntervalEndTime,
calculateIntervalStartTime,
QuickTimeInterval
} from '@shared/models/time/time.models';
import { UtilsService } from '@core/services/utils.service';
import { deepClone } from '@core/utils';
import Timeout = NodeJS.Timeout;
@ -92,7 +97,8 @@ export class DataAggregator {
private interval: number,
private stateData: boolean,
private utils: UtilsService,
private ignoreDataUpdateOnIntervalTick: boolean) {
private ignoreDataUpdateOnIntervalTick: boolean,
private quickInterval: QuickTimeInterval) {
this.tsKeyNames.forEach((key) => {
this.dataBuffer[key] = [];
});
@ -138,7 +144,8 @@ export class DataAggregator {
this.startTs = startTs;
this.timeWindow = timeWindow;
this.interval = interval;
this.endTs = this.startTs + this.timeWindow;
const endTs = this.startTs + this.timeWindow;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
this.elapsed = 0;
this.aggregationTimeout = Math.max(this.interval, 1000);
this.resetPending = true;
@ -161,7 +168,8 @@ export class DataAggregator {
if (!this.dataReceived) {
this.elapsed = 0;
this.dataReceived = true;
this.endTs = this.startTs + this.timeWindow;
const endTs = this.startTs + this.timeWindow;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
}
if (this.resetPending) {
this.resetPending = false;
@ -197,8 +205,11 @@ export class DataAggregator {
if (!history) {
const delta = Math.floor(this.elapsed / this.interval);
if (delta || !this.data) {
this.startTs += delta * this.interval;
this.endTs += delta * this.interval;
const tickTs = delta * this.interval;
const startTS = this.startTs + tickTs;
this.startTs = calculateIntervalStartTime(this.quickInterval, startTS);
const endTs = this.endTs + tickTs;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
this.data = this.updateData();
this.elapsed = this.elapsed - delta * this.interval;
}

3
ui-ngx/src/app/core/api/entity-data-subscription.ts

@ -752,7 +752,8 @@ export class EntityDataSubscription {
subsTw.aggregation.interval,
subsTw.aggregation.stateData,
this.utils,
this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick
this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick,
subsTw.quickInterval
);
}

10
ui-ngx/src/app/core/api/widget-subscription.ts

@ -37,6 +37,8 @@ import {
} from '@app/shared/models/widget.models';
import { HttpErrorResponse } from '@angular/common/http';
import {
calculateIntervalEndTime,
calculateIntervalStartTime,
createSubscriptionTimewindow,
createTimewindowForComparison,
SubscriptionTimewindow,
@ -1081,8 +1083,10 @@ export class WidgetSubscription implements IWidgetSubscription {
private updateTimewindow() {
this.timeWindow.interval = this.subscriptionTimewindow.aggregation.interval || 1000;
if (this.subscriptionTimewindow.realtimeWindowMs) {
this.timeWindow.maxTime = moment().valueOf() + this.timeWindow.stDiff;
this.timeWindow.minTime = this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs;
this.timeWindow.maxTime = calculateIntervalEndTime(
this.subscriptionTimewindow.quickInterval, moment().valueOf() + this.timeWindow.stDiff);
this.timeWindow.minTime = calculateIntervalStartTime(
this.subscriptionTimewindow.quickInterval, this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs);
} else if (this.subscriptionTimewindow.fixedWindow) {
this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs;
this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs;
@ -1105,7 +1109,7 @@ export class WidgetSubscription implements IWidgetSubscription {
this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000;
if (this.timewindowForComparison.realtimeWindowMs) {
this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf();
this.comparisonTimeWindow.minTime = this.comparisonTimeWindow.maxTime - this.timewindowForComparison.realtimeWindowMs;
this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf();
} else if (this.timewindowForComparison.fixedWindow) {
this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs;
this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs;

27
ui-ngx/src/app/shared/components/time/quick-time-interval.component.html

@ -0,0 +1,27 @@
<!--
Copyright © 2016-2021 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.
-->
<section class="interval-section" fxLayout="row" fxFlex>
<mat-form-field fxFlex>
<mat-label translate>timewindow.interval</mat-label>
<mat-select [disabled]="disabled" [(ngModel)]="modelValue" (ngModelChange)="onIntervalChange()">
<mat-option *ngFor="let interval of intervals" [value]="interval">
{{ timeIntervalTranslationMap.get(interval) | translate}}
</mat-option>
</mat-select>
</mat-form-field>
</section>

19
ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss

@ -0,0 +1,19 @@
/**
* Copyright © 2016-2021 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 {
min-width: 364px;
}

79
ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts

@ -0,0 +1,79 @@
///
/// Copyright © 2016-2021 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.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { QuickTimeInterval, QuickTimeIntervalTranslationMap } from '@shared/models/time/time.models';
@Component({
selector: 'tb-quick-time-interval',
templateUrl: './quick-time-interval.component.html',
styleUrls: ['./quick-time-interval.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => QuickTimeIntervalComponent),
multi: true
}
]
})
export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor {
private allIntervals = Object.values(QuickTimeInterval);
modelValue: QuickTimeInterval;
timeIntervalTranslationMap = QuickTimeIntervalTranslationMap;
rendered = false;
@Input() disabled: boolean;
@Input() onlyCurrentInterval = false;
private propagateChange = (_: any) => {};
constructor() {
}
get intervals() {
if (this.onlyCurrentInterval) {
return this.allIntervals.filter(interval => interval.startsWith('CURRENT_'));
}
return this.allIntervals;
}
ngOnInit(): void {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(interval: QuickTimeInterval): void {
this.modelValue = interval;
}
onIntervalChange() {
this.propagateChange(this.modelValue);
}
}

58
ui-ngx/src/app/shared/components/time/timewindow-panel.component.html

@ -21,16 +21,43 @@
<mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}"
(selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab">
<mat-tab label="{{ 'timewindow.realtime' | translate }}">
<div formGroupName="realtime" class="mat-content mat-padding" fxLayout="column">
<tb-timeinterval
[(hideFlag)]="timewindow.hideInterval"
(hideFlagChange)="onHideIntervalChanged()"
[isEdit]="isEdit"
formControlName="timewindowMs"
predefinedName="timewindow.last"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME"
style="padding-top: 8px;"></tb-timeinterval>
</div>
<section fxLayout="row">
<section *ngIf="isEdit" fxLayout="column" style="padding-top: 8px; padding-left: 16px;">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideInterval"
(ngModelChange)="onHideIntervalChanged()"></mat-checkbox>
</section>
<section fxLayout="column" fxFlex [fxShow]="isEdit || !timewindow.hideInterval">
<div formGroupName="realtime" class="mat-content mat-padding" style="padding-top: 8px;">
<mat-radio-group formControlName="realtimeType">
<mat-radio-button [value]="realtimeTypes.LAST_INTERVAL" color="primary">
<section fxLayout="column">
<span translate>timewindow.last</span>
<tb-timeinterval
formControlName="timewindowMs"
predefinedName="timewindow.last"
[fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
style="padding-top: 8px;"></tb-timeinterval>
</section>
</mat-radio-button>
<mat-radio-button [value]="realtimeTypes.INTERVAL" color="primary">
<section fxLayout="column">
<span translate>timewindow.interval</span>
<tb-quick-time-interval
formControlName="quickInterval"
onlyCurrentInterval="true"
[fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval>
</section>
</mat-radio-button>
</mat-radio-group>
</div>
</section>
</section>
</mat-tab>
<mat-tab label="{{ 'timewindow.history' | translate }}">
<section fxLayout="row">
@ -65,6 +92,17 @@
style="padding-top: 8px;"></tb-datetime-period>
</section>
</mat-radio-button>
<mat-radio-button [value]="historyTypes.INTERVAL" color="primary">
<section fxLayout="column">
<span translate>timewindow.interval</span>
<tb-quick-time-interval
formControlName="quickInterval"
[fxShow]="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval>
</section>
</mat-radio-button>
</mat-radio-group>
</div>
</section>

52
ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts

@ -20,6 +20,8 @@ import {
AggregationType,
DAY,
HistoryWindowType,
quickTimeIntervalPeriod,
RealtimeWindowType,
Timewindow,
TimewindowType
} from '@shared/models/time/time.models';
@ -60,6 +62,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
historyTypes = HistoryWindowType;
realtimeTypes = RealtimeWindowType;
timewindowTypes = TimewindowType;
aggregationTypes = AggregationType;
@ -89,6 +93,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
this.timewindowForm = this.fb.group({
realtime: this.fb.group(
{
realtimeType: this.fb.control({
value: this.timewindow.realtime && typeof this.timewindow.realtime.realtimeType !== 'undefined'
? this.timewindow.realtime.realtimeType : RealtimeWindowType.LAST_INTERVAL,
disabled: hideInterval
}),
timewindowMs: [
this.timewindow.realtime && typeof this.timewindow.realtime.timewindowMs !== 'undefined'
? this.timewindow.realtime.timewindowMs : null
@ -96,7 +105,12 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
interval: [
this.timewindow.realtime && typeof this.timewindow.realtime.interval !== 'undefined'
? this.timewindow.realtime.interval : null
]
],
quickInterval: this.fb.control({
value: this.timewindow.realtime && typeof this.timewindow.realtime.quickInterval !== 'undefined'
? this.timewindow.realtime.quickInterval : null,
disabled: hideInterval
})
}
),
history: this.fb.group(
@ -119,6 +133,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
value: this.timewindow.history && typeof this.timewindow.history.fixedTimewindow !== 'undefined'
? this.timewindow.history.fixedTimewindow : null,
disabled: hideInterval
}),
quickInterval: this.fb.control({
value: this.timewindow.history && typeof this.timewindow.history.quickInterval !== 'undefined'
? this.timewindow.history.quickInterval : null,
disabled: hideInterval
})
}
),
@ -142,14 +161,17 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
update() {
const timewindowFormValue = this.timewindowForm.getRawValue();
this.timewindow.realtime = {
realtimeType: timewindowFormValue.realtime.realtimeType,
timewindowMs: timewindowFormValue.realtime.timewindowMs,
quickInterval: timewindowFormValue.realtime.quickInterval,
interval: timewindowFormValue.realtime.interval
};
this.timewindow.history = {
historyType: timewindowFormValue.history.historyType,
timewindowMs: timewindowFormValue.history.timewindowMs,
interval: timewindowFormValue.history.interval,
fixedTimewindow: timewindowFormValue.history.fixedTimewindow
fixedTimewindow: timewindowFormValue.history.fixedTimewindow,
quickInterval: timewindowFormValue.history.quickInterval
};
if (this.aggregation) {
this.timewindow.aggregation = {
@ -174,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
}
minRealtimeAggInterval() {
return this.timeService.minIntervalLimit(this.timewindowForm.get('realtime.timewindowMs').value);
return this.timeService.minIntervalLimit(this.currentRealtimeTimewindow());
}
maxRealtimeAggInterval() {
return this.timeService.maxIntervalLimit(this.timewindowForm.get('realtime.timewindowMs').value);
return this.timeService.maxIntervalLimit(this.currentRealtimeTimewindow());
}
currentRealtimeTimewindow(): number {
const timeWindowFormValue = this.timewindowForm.getRawValue();
switch (timeWindowFormValue.realtime.realtimeType) {
case RealtimeWindowType.LAST_INTERVAL:
return timeWindowFormValue.realtime.timewindowMs;
case RealtimeWindowType.INTERVAL:
return quickTimeIntervalPeriod(timeWindowFormValue.realtime.quickInterval);
default:
return DAY;
}
}
minHistoryAggInterval() {
@ -193,6 +227,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
const timewindowFormValue = this.timewindowForm.getRawValue();
if (timewindowFormValue.history.historyType === HistoryWindowType.LAST_INTERVAL) {
return timewindowFormValue.history.timewindowMs;
} else if (timewindowFormValue.history.historyType === HistoryWindowType.INTERVAL) {
return quickTimeIntervalPeriod(timewindowFormValue.history.quickInterval);
} else if (timewindowFormValue.history.fixedTimewindow) {
return timewindowFormValue.history.fixedTimewindow.endTimeMs -
timewindowFormValue.history.fixedTimewindow.startTimeMs;
@ -206,10 +242,18 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
this.timewindowForm.get('history.historyType').disable({emitEvent: false});
this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false});
this.timewindowForm.get('history.fixedTimewindow').disable({emitEvent: false});
this.timewindowForm.get('history.quickInterval').disable({emitEvent: false});
this.timewindowForm.get('realtime.realtimeType').disable({emitEvent: false});
this.timewindowForm.get('realtime.timewindowMs').disable({emitEvent: false});
this.timewindowForm.get('realtime.quickInterval').disable({emitEvent: false});
} else {
this.timewindowForm.get('history.historyType').enable({emitEvent: false});
this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false});
this.timewindowForm.get('history.fixedTimewindow').enable({emitEvent: false});
this.timewindowForm.get('history.quickInterval').enable({emitEvent: false});
this.timewindowForm.get('realtime.realtimeType').enable({emitEvent: false});
this.timewindowForm.get('realtime.timewindowMs').enable({emitEvent: false});
this.timewindowForm.get('realtime.quickInterval').enable({emitEvent: false});
}
this.timewindowForm.markAsDirty();
}

14
ui-ngx/src/app/shared/components/time/timewindow.component.ts

@ -33,6 +33,8 @@ import {
cloneSelectedTimewindow,
HistoryWindowType,
initModelFromDefaultTimewindow,
QuickTimeIntervalTranslationMap,
RealtimeWindowType,
Timewindow,
TimewindowType
} from '@shared/models/time/time.models';
@ -272,14 +274,20 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
updateDisplayValue() {
if (this.innerValue.selectedTab === TimewindowType.REALTIME && !this.historyOnly) {
this.innerValue.displayValue = this.translate.instant('timewindow.realtime') + ' - ' +
this.translate.instant('timewindow.last-prefix') + ' ' +
this.millisecondsToTimeStringPipe.transform(this.innerValue.realtime.timewindowMs);
this.innerValue.displayValue = this.translate.instant('timewindow.realtime') + ' - ';
if (this.innerValue.realtime.realtimeType === RealtimeWindowType.INTERVAL) {
this.innerValue.displayValue += this.translate.instant(QuickTimeIntervalTranslationMap.get(this.innerValue.realtime.quickInterval));
} else {
this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' +
this.millisecondsToTimeStringPipe.transform(this.innerValue.realtime.timewindowMs);
}
} else {
this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : '';
if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) {
this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' +
this.millisecondsToTimeStringPipe.transform(this.innerValue.history.timewindowMs);
} else if (this.innerValue.history.historyType === HistoryWindowType.INTERVAL) {
this.innerValue.displayValue += this.translate.instant(QuickTimeIntervalTranslationMap.get(this.innerValue.history.quickInterval));
} else {
const startString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.startTimeMs, 'yyyy-MM-dd HH:mm:ss');
const endString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.endTimeMs, 'yyyy-MM-dd HH:mm:ss');

249
ui-ngx/src/app/shared/models/time/time.models.ts

@ -15,7 +15,7 @@
///
import { TimeService } from '@core/services/time.service';
import { deepClone, isDefined, isUndefined } from '@app/core/utils';
import { deepClone, isDefined, isDefinedAndNotNull, isUndefined } from '@app/core/utils';
import * as moment_ from 'moment';
import { Observable } from 'rxjs/internal/Observable';
import { from, of } from 'rxjs';
@ -27,6 +27,7 @@ export const SECOND = 1000;
export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE;
export const DAY = 24 * HOUR;
export const WEEK = 7 * DAY;
export const YEAR = DAY * 365;
export enum TimewindowType {
@ -34,14 +35,25 @@ export enum TimewindowType {
HISTORY
}
export enum RealtimeWindowType {
LAST_INTERVAL,
INTERVAL
}
export enum HistoryWindowType {
LAST_INTERVAL,
FIXED
FIXED,
INTERVAL
}
export interface IntervalWindow {
interval?: number;
timewindowMs?: number;
quickInterval?: QuickTimeInterval;
}
export interface RealtimeWindow extends IntervalWindow{
realtimeType?: RealtimeWindowType;
}
export interface FixedWindow {
@ -86,7 +98,7 @@ export interface Timewindow {
hideAggregation?: boolean;
hideAggInterval?: boolean;
selectedTab?: TimewindowType;
realtime?: IntervalWindow;
realtime?: RealtimeWindow;
history?: HistoryWindow;
aggregation?: Aggregation;
}
@ -99,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation {
export interface SubscriptionTimewindow {
startTs?: number;
quickInterval?: QuickTimeInterval;
realtimeWindowMs?: number;
fixedWindow?: FixedWindow;
aggregation?: SubscriptionAggregation;
@ -111,6 +124,42 @@ export interface WidgetTimewindow {
stDiff?: number;
}
export enum QuickTimeInterval {
YESTERDAY = 'YESTERDAY',
DAY_BEFORE_YESTERDAY = 'DAY_BEFORE_YESTERDAY',
THIS_DAY_LAST_WEEK = 'THIS_DAY_LAST_WEEK',
PREVIOUS_WEEK = 'PREVIOUS_WEEK',
PREVIOUS_MONTH = 'PREVIOUS_MONTH',
PREVIOUS_YEAR = 'PREVIOUS_YEAR',
CURRENT_HOUR = 'CURRENT_HOUR',
CURRENT_DAY = 'CURRENT_DAY',
CURRENT_DAY_SO_FAR = 'CURRENT_DAY_SO_FAR',
CURRENT_WEEK = 'CURRENT_WEEK',
CURRENT_WEEK_SO_FAR = 'CURRENT_WEEK_SO_WAR',
CURRENT_MONTH = 'CURRENT_MONTH',
CURRENT_MONTH_SO_FAR = 'CURRENT_MONTH_SO_FAR',
CURRENT_YEAR = 'CURRENT_YEAR',
CURRENT_YEAR_SO_FAR = 'CURRENT_YEAR_SO_FAR'
}
export const QuickTimeIntervalTranslationMap = new Map<QuickTimeInterval, string>([
[QuickTimeInterval.YESTERDAY, 'timeinterval.predefined.yesterday'],
[QuickTimeInterval.DAY_BEFORE_YESTERDAY, 'timeinterval.predefined.day-before-yesterday'],
[QuickTimeInterval.THIS_DAY_LAST_WEEK, 'timeinterval.predefined.this-day-last-week'],
[QuickTimeInterval.PREVIOUS_WEEK, 'timeinterval.predefined.previous-week'],
[QuickTimeInterval.PREVIOUS_MONTH, 'timeinterval.predefined.previous-month'],
[QuickTimeInterval.PREVIOUS_YEAR, 'timeinterval.predefined.previous-year'],
[QuickTimeInterval.CURRENT_HOUR, 'timeinterval.predefined.current-hour'],
[QuickTimeInterval.CURRENT_DAY, 'timeinterval.predefined.current-day'],
[QuickTimeInterval.CURRENT_DAY_SO_FAR, 'timeinterval.predefined.current-day-so-far'],
[QuickTimeInterval.CURRENT_WEEK, 'timeinterval.predefined.current-week'],
[QuickTimeInterval.CURRENT_WEEK_SO_FAR, 'timeinterval.predefined.current-week-so-far'],
[QuickTimeInterval.CURRENT_MONTH, 'timeinterval.predefined.current-month'],
[QuickTimeInterval.CURRENT_MONTH_SO_FAR, 'timeinterval.predefined.current-month-so-far'],
[QuickTimeInterval.CURRENT_YEAR, 'timeinterval.predefined.current-year'],
[QuickTimeInterval.CURRENT_YEAR_SO_FAR, 'timeinterval.predefined.current-year-so-far']
]);
export function historyInterval(timewindowMs: number): Timewindow {
const timewindow: Timewindow = {
selectedTab: TimewindowType.HISTORY,
@ -131,8 +180,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow {
hideAggInterval: false,
selectedTab: TimewindowType.REALTIME,
realtime: {
realtimeType: RealtimeWindowType.LAST_INTERVAL,
interval: SECOND,
timewindowMs: MINUTE
timewindowMs: MINUTE,
quickInterval: QuickTimeInterval.CURRENT_DAY
},
history: {
historyType: HistoryWindowType.LAST_INTERVAL,
@ -141,7 +192,8 @@ export function defaultTimewindow(timeService: TimeService): Timewindow {
fixedTimewindow: {
startTimeMs: currentTime - DAY,
endTimeMs: currentTime
}
},
quickInterval: QuickTimeInterval.CURRENT_DAY
},
aggregation: {
type: AggregationType.AVG,
@ -170,7 +222,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
if (isDefined(value.realtime.interval)) {
model.realtime.interval = value.realtime.interval;
}
model.realtime.timewindowMs = value.realtime.timewindowMs;
if (isUndefined(value.realtime.realtimeType)) {
if (isDefined(value.realtime.quickInterval)) {
model.realtime.realtimeType = RealtimeWindowType.INTERVAL;
} else {
model.realtime.realtimeType = RealtimeWindowType.LAST_INTERVAL;
}
} else {
model.realtime.realtimeType = value.realtime.realtimeType;
}
if (model.realtime.realtimeType === RealtimeWindowType.INTERVAL) {
model.realtime.quickInterval = value.realtime.quickInterval;
} else {
model.realtime.timewindowMs = value.realtime.timewindowMs;
}
} else {
if (isDefined(value.history.interval)) {
model.history.interval = value.history.interval;
@ -178,6 +243,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
if (isUndefined(value.history.historyType)) {
if (isDefined(value.history.timewindowMs)) {
model.history.historyType = HistoryWindowType.LAST_INTERVAL;
} else if (isDefined(value.history.quickInterval)) {
model.history.historyType = HistoryWindowType.INTERVAL;
} else {
model.history.historyType = HistoryWindowType.FIXED;
}
@ -186,6 +253,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
}
if (model.history.historyType === HistoryWindowType.LAST_INTERVAL) {
model.history.timewindowMs = value.history.timewindowMs;
} else if (model.history.historyType === HistoryWindowType.INTERVAL) {
model.history.quickInterval = value.history.quickInterval;
} else {
model.history.fixedTimewindow.startTimeMs = value.history.fixedTimewindow.startTimeMs;
model.history.fixedTimewindow.endTimeMs = value.history.fixedTimewindow.endTimeMs;
@ -267,21 +336,40 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY;
}
if (selectedTab === TimewindowType.REALTIME) {
subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs;
let realtimeType = timewindow.realtime.realtimeType;
if (isUndefined(realtimeType)) {
if (isDefined(timewindow.realtime.quickInterval)) {
realtimeType = RealtimeWindowType.INTERVAL;
} else {
realtimeType = RealtimeWindowType.LAST_INTERVAL;
}
}
if (realtimeType === RealtimeWindowType.INTERVAL) {
subscriptionTimewindow.realtimeWindowMs = getSubscriptionRealtimeWindowFromTimeInterval(timewindow.realtime.quickInterval);
subscriptionTimewindow.quickInterval = timewindow.realtime.quickInterval;
} else {
subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs;
}
subscriptionTimewindow.aggregation.interval =
timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval,
subscriptionTimewindow.aggregation.type);
subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs;
const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval;
aggTimewindow = subscriptionTimewindow.realtimeWindowMs;
if (startDiff) {
if (startDiff && realtimeType !== RealtimeWindowType.INTERVAL) {
subscriptionTimewindow.startTs -= startDiff;
aggTimewindow += subscriptionTimewindow.aggregation.interval;
}
} else {
let historyType = timewindow.history.historyType;
if (isUndefined(historyType)) {
historyType = isDefined(timewindow.history.timewindowMs) ? HistoryWindowType.LAST_INTERVAL : HistoryWindowType.FIXED;
if (isDefined(timewindow.history.timewindowMs)) {
historyType = HistoryWindowType.LAST_INTERVAL;
} else if (isDefined(timewindow.history.quickInterval)) {
historyType = HistoryWindowType.INTERVAL;
} else {
historyType = HistoryWindowType.FIXED;
}
}
if (historyType === HistoryWindowType.LAST_INTERVAL) {
const currentTime = Date.now();
@ -290,6 +378,13 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
endTimeMs: currentTime
};
aggTimewindow = timewindow.history.timewindowMs;
} else if (historyType === HistoryWindowType.INTERVAL) {
const currentDate = moment();
subscriptionTimewindow.fixedWindow = {
startTimeMs: calculateIntervalStartTime(timewindow.history.quickInterval, null, currentDate),
endTimeMs: calculateIntervalEndTime(timewindow.history.quickInterval, null, currentDate)
};
aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
} else {
subscriptionTimewindow.fixedWindow = {
startTimeMs: timewindow.history.fixedTimewindow.startTimeMs,
@ -309,6 +404,132 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
return subscriptionTimewindow;
}
function getSubscriptionRealtimeWindowFromTimeInterval(interval: QuickTimeInterval): number {
const currentDate = moment();
switch (interval) {
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.diff(currentDate.clone().startOf('hour'))
case QuickTimeInterval.CURRENT_DAY:
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('day'));
case QuickTimeInterval.CURRENT_WEEK:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('week'));
case QuickTimeInterval.CURRENT_MONTH:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('month'));
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('year'));
}
}
export function calculateIntervalEndTime(interval: QuickTimeInterval, endTs = 0, nowDate?: moment_.Moment): number {
const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
switch (interval) {
case QuickTimeInterval.YESTERDAY:
currentDate.subtract(1, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
currentDate.subtract(2, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
currentDate.subtract(1, 'months');
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
currentDate.subtract(1, 'years');
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.endOf('hour').valueOf();
case QuickTimeInterval.CURRENT_DAY:
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.CURRENT_WEEK:
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.CURRENT_MONTH:
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.CURRENT_YEAR:
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.valueOf();
default:
return endTs;
}
}
export function calculateIntervalStartTime(interval: QuickTimeInterval, startTS = 0, nowDate?: moment_.Moment): number {
const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
switch (interval) {
case QuickTimeInterval.YESTERDAY:
currentDate.subtract(1, 'days');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
currentDate.subtract(2, 'days');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
currentDate.subtract(1, 'months');
return currentDate.startOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
currentDate.subtract(1, 'years');
return currentDate.startOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.startOf('hour').valueOf();
case QuickTimeInterval.CURRENT_DAY:
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.CURRENT_WEEK:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
return currentDate.startOf('week').valueOf();
case QuickTimeInterval.CURRENT_MONTH:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
return currentDate.startOf('month').valueOf();
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.startOf('year').valueOf();
default:
return startTS;
}
}
export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number {
switch (interval) {
case QuickTimeInterval.CURRENT_HOUR:
return HOUR;
case QuickTimeInterval.YESTERDAY:
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
case QuickTimeInterval.CURRENT_DAY:
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
return DAY;
case QuickTimeInterval.PREVIOUS_WEEK:
case QuickTimeInterval.CURRENT_WEEK:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
return WEEK;
case QuickTimeInterval.PREVIOUS_MONTH:
case QuickTimeInterval.CURRENT_MONTH:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
return DAY * 30;
case QuickTimeInterval.PREVIOUS_YEAR:
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return YEAR;
}
}
export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow,
timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow {
const timewindowForComparison: SubscriptionTimewindow = {
@ -358,6 +579,8 @@ export function cloneSelectedHistoryTimewindow(historyWindow: HistoryWindow): Hi
cloned.interval = historyWindow.interval;
if (historyWindow.historyType === HistoryWindowType.LAST_INTERVAL) {
cloned.timewindowMs = historyWindow.timewindowMs;
} else if (historyWindow.historyType === HistoryWindowType.INTERVAL) {
cloned.quickInterval = historyWindow.quickInterval;
} else if (historyWindow.historyType === HistoryWindowType.FIXED) {
cloned.fixedTimewindow = deepClone(historyWindow.fixedTimewindow);
}
@ -375,7 +598,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>(
{
name: 'timeinterval.seconds-interval',
translateParams: {seconds: 1},
value: 1 * SECOND
value: SECOND
},
{
name: 'timeinterval.seconds-interval',
@ -400,7 +623,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>(
{
name: 'timeinterval.minutes-interval',
translateParams: {minutes: 1},
value: 1 * MINUTE
value: MINUTE
},
{
name: 'timeinterval.minutes-interval',
@ -430,7 +653,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>(
{
name: 'timeinterval.hours-interval',
translateParams: {hours: 1},
value: 1 * HOUR
value: HOUR
},
{
name: 'timeinterval.hours-interval',
@ -455,7 +678,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>(
{
name: 'timeinterval.days-interval',
translateParams: {days: 1},
value: 1 * DAY
value: DAY
},
{
name: 'timeinterval.days-interval',

3
ui-ngx/src/app/shared/shared.module.ts

@ -140,6 +140,7 @@ import { TimezoneSelectComponent } from '@shared/components/time/timezone-select
import { FileSizePipe } from '@shared/pipe/file-size.pipe';
import { WidgetsBundleSearchComponent } from '@shared/components/widgets-bundle-search.component';
import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe';
import { QuickTimeIntervalComponent } from '@shared/components/time/quick-time-interval.component';
@NgModule({
providers: [
@ -175,6 +176,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe';
TimewindowComponent,
TimewindowPanelComponent,
TimeintervalComponent,
QuickTimeIntervalComponent,
DashboardSelectComponent,
DashboardSelectPanelComponent,
DatetimePeriodComponent,
@ -302,6 +304,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe';
TimewindowComponent,
TimewindowPanelComponent,
TimeintervalComponent,
QuickTimeIntervalComponent,
DashboardSelectComponent,
DatetimePeriodComponent,
DatetimeComponent,

22
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2118,7 +2118,24 @@
"hours": "Hours",
"minutes": "Minutes",
"seconds": "Seconds",
"advanced": "Advanced"
"advanced": "Advanced",
"predefined": {
"yesterday": "Yesterday",
"day-before-yesterday": "Day before yesterday",
"this-day-last-week": "This day last week",
"previous-week": "Previous week",
"previous-month": "Previous month",
"previous-year": "Previous year",
"current-hour": "Current hour",
"current-day": "Current day",
"current-day-so-far": "Current day so far",
"current-week": "Current week",
"current-week-so-far": "Current week so far",
"current-month": "Current month",
"current-month-so-far": "Current month so far",
"current-year": "Current year",
"current-year-so-far": "Current year so far"
}
},
"timeunit": {
"seconds": "Seconds",
@ -2139,7 +2156,8 @@
"date-range": "Date range",
"last": "Last",
"time-period": "Time period",
"hide": "Hide"
"hide": "Hide",
"interval": "Interval"
},
"user": {
"user": "User",

Loading…
Cancel
Save