Commit 0ebbee02db9a981715bc774f2d99b7aa10be4470

Authored by Vladyslav_Prykhodko
1 parent f1193c1d

UI: Added new timewindow type - realtime interval

@@ -15,7 +15,12 @@ @@ -15,7 +15,12 @@
15 /// 15 ///
16 16
17 import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models'; 17 import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models';
18 -import { AggregationType } from '@shared/models/time/time.models'; 18 +import {
  19 + AggregationType,
  20 + calculateIntervalEndTime,
  21 + calculateIntervalStartTime,
  22 + QuickTimeInterval
  23 +} from '@shared/models/time/time.models';
19 import { UtilsService } from '@core/services/utils.service'; 24 import { UtilsService } from '@core/services/utils.service';
20 import { deepClone } from '@core/utils'; 25 import { deepClone } from '@core/utils';
21 import Timeout = NodeJS.Timeout; 26 import Timeout = NodeJS.Timeout;
@@ -92,7 +97,8 @@ export class DataAggregator { @@ -92,7 +97,8 @@ export class DataAggregator {
92 private interval: number, 97 private interval: number,
93 private stateData: boolean, 98 private stateData: boolean,
94 private utils: UtilsService, 99 private utils: UtilsService,
95 - private ignoreDataUpdateOnIntervalTick: boolean) { 100 + private ignoreDataUpdateOnIntervalTick: boolean,
  101 + private quickInterval: QuickTimeInterval) {
96 this.tsKeyNames.forEach((key) => { 102 this.tsKeyNames.forEach((key) => {
97 this.dataBuffer[key] = []; 103 this.dataBuffer[key] = [];
98 }); 104 });
@@ -138,7 +144,8 @@ export class DataAggregator { @@ -138,7 +144,8 @@ export class DataAggregator {
138 this.startTs = startTs; 144 this.startTs = startTs;
139 this.timeWindow = timeWindow; 145 this.timeWindow = timeWindow;
140 this.interval = interval; 146 this.interval = interval;
141 - this.endTs = this.startTs + this.timeWindow; 147 + const endTs = this.startTs + this.timeWindow;
  148 + this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
142 this.elapsed = 0; 149 this.elapsed = 0;
143 this.aggregationTimeout = Math.max(this.interval, 1000); 150 this.aggregationTimeout = Math.max(this.interval, 1000);
144 this.resetPending = true; 151 this.resetPending = true;
@@ -161,7 +168,8 @@ export class DataAggregator { @@ -161,7 +168,8 @@ export class DataAggregator {
161 if (!this.dataReceived) { 168 if (!this.dataReceived) {
162 this.elapsed = 0; 169 this.elapsed = 0;
163 this.dataReceived = true; 170 this.dataReceived = true;
164 - this.endTs = this.startTs + this.timeWindow; 171 + const endTs = this.startTs + this.timeWindow;
  172 + this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
165 } 173 }
166 if (this.resetPending) { 174 if (this.resetPending) {
167 this.resetPending = false; 175 this.resetPending = false;
@@ -197,8 +205,11 @@ export class DataAggregator { @@ -197,8 +205,11 @@ export class DataAggregator {
197 if (!history) { 205 if (!history) {
198 const delta = Math.floor(this.elapsed / this.interval); 206 const delta = Math.floor(this.elapsed / this.interval);
199 if (delta || !this.data) { 207 if (delta || !this.data) {
200 - this.startTs += delta * this.interval;  
201 - this.endTs += delta * this.interval; 208 + const tickTs = delta * this.interval;
  209 + const startTS = this.startTs + tickTs;
  210 + this.startTs = calculateIntervalStartTime(this.quickInterval, startTS);
  211 + const endTs = this.endTs + tickTs;
  212 + this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
202 this.data = this.updateData(); 213 this.data = this.updateData();
203 this.elapsed = this.elapsed - delta * this.interval; 214 this.elapsed = this.elapsed - delta * this.interval;
204 } 215 }
@@ -752,7 +752,8 @@ export class EntityDataSubscription { @@ -752,7 +752,8 @@ export class EntityDataSubscription {
752 subsTw.aggregation.interval, 752 subsTw.aggregation.interval,
753 subsTw.aggregation.stateData, 753 subsTw.aggregation.stateData,
754 this.utils, 754 this.utils,
755 - this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick 755 + this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick,
  756 + subsTw.quickInterval
756 ); 757 );
757 } 758 }
758 759
@@ -37,6 +37,8 @@ import { @@ -37,6 +37,8 @@ import {
37 } from '@app/shared/models/widget.models'; 37 } from '@app/shared/models/widget.models';
38 import { HttpErrorResponse } from '@angular/common/http'; 38 import { HttpErrorResponse } from '@angular/common/http';
39 import { 39 import {
  40 + calculateIntervalEndTime,
  41 + calculateIntervalStartTime,
40 createSubscriptionTimewindow, 42 createSubscriptionTimewindow,
41 createTimewindowForComparison, 43 createTimewindowForComparison,
42 SubscriptionTimewindow, 44 SubscriptionTimewindow,
@@ -1081,8 +1083,10 @@ export class WidgetSubscription implements IWidgetSubscription { @@ -1081,8 +1083,10 @@ export class WidgetSubscription implements IWidgetSubscription {
1081 private updateTimewindow() { 1083 private updateTimewindow() {
1082 this.timeWindow.interval = this.subscriptionTimewindow.aggregation.interval || 1000; 1084 this.timeWindow.interval = this.subscriptionTimewindow.aggregation.interval || 1000;
1083 if (this.subscriptionTimewindow.realtimeWindowMs) { 1085 if (this.subscriptionTimewindow.realtimeWindowMs) {
1084 - this.timeWindow.maxTime = moment().valueOf() + this.timeWindow.stDiff;  
1085 - this.timeWindow.minTime = this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs; 1086 + this.timeWindow.maxTime = calculateIntervalEndTime(
  1087 + this.subscriptionTimewindow.quickInterval, moment().valueOf() + this.timeWindow.stDiff);
  1088 + this.timeWindow.minTime = calculateIntervalStartTime(
  1089 + this.subscriptionTimewindow.quickInterval, this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs);
1086 } else if (this.subscriptionTimewindow.fixedWindow) { 1090 } else if (this.subscriptionTimewindow.fixedWindow) {
1087 this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs; 1091 this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs;
1088 this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs; 1092 this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs;
@@ -1105,7 +1109,7 @@ export class WidgetSubscription implements IWidgetSubscription { @@ -1105,7 +1109,7 @@ export class WidgetSubscription implements IWidgetSubscription {
1105 this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000; 1109 this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000;
1106 if (this.timewindowForComparison.realtimeWindowMs) { 1110 if (this.timewindowForComparison.realtimeWindowMs) {
1107 this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf(); 1111 this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf();
1108 - this.comparisonTimeWindow.minTime = this.comparisonTimeWindow.maxTime - this.timewindowForComparison.realtimeWindowMs; 1112 + this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf();
1109 } else if (this.timewindowForComparison.fixedWindow) { 1113 } else if (this.timewindowForComparison.fixedWindow) {
1110 this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs; 1114 this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs;
1111 this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs; 1115 this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs;
@@ -50,7 +50,7 @@ export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor @@ -50,7 +50,7 @@ export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor
50 50
51 get intervals() { 51 get intervals() {
52 if (this.onlyCurrentInterval) { 52 if (this.onlyCurrentInterval) {
53 - return this.allIntervals.filter(interval => interval.startsWith('TODAY_') || interval.startsWith('CURRENT_')); 53 + return this.allIntervals.filter(interval => interval.startsWith('TODAY') || interval.startsWith('CURRENT_'));
54 } 54 }
55 return this.allIntervals; 55 return this.allIntervals;
56 } 56 }
@@ -71,7 +71,6 @@ export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor @@ -71,7 +71,6 @@ export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor
71 71
72 writeValue(interval: QuickTimeInterval): void { 72 writeValue(interval: QuickTimeInterval): void {
73 this.modelValue = interval; 73 this.modelValue = interval;
74 - this.rendered = true;  
75 } 74 }
76 75
77 onIntervalChange() { 76 onIntervalChange() {
@@ -21,16 +21,43 @@ @@ -21,16 +21,43 @@
21 <mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}" 21 <mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}"
22 (selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab"> 22 (selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab">
23 <mat-tab label="{{ 'timewindow.realtime' | translate }}"> 23 <mat-tab label="{{ 'timewindow.realtime' | translate }}">
24 - <div formGroupName="realtime" class="mat-content mat-padding" fxLayout="column">  
25 - <tb-timeinterval  
26 - [(hideFlag)]="timewindow.hideInterval"  
27 - (hideFlagChange)="onHideIntervalChanged()"  
28 - [isEdit]="isEdit"  
29 - formControlName="timewindowMs"  
30 - predefinedName="timewindow.last"  
31 - [required]="timewindow.selectedTab === timewindowTypes.REALTIME"  
32 - style="padding-top: 8px;"></tb-timeinterval>  
33 - </div> 24 + <section fxLayout="row">
  25 + <section *ngIf="isEdit" fxLayout="column" style="padding-top: 8px; padding-left: 16px;">
  26 + <label class="tb-small hide-label" translate>timewindow.hide</label>
  27 + <mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideInterval"
  28 + (ngModelChange)="onHideIntervalChanged()"></mat-checkbox>
  29 + </section>
  30 + <section fxLayout="column" fxFlex [fxShow]="isEdit || !timewindow.hideInterval">
  31 + <div formGroupName="realtime" class="mat-content mat-padding" style="padding-top: 8px;">
  32 + <mat-radio-group formControlName="realtimeType">
  33 + <mat-radio-button [value]="realtimeTypes.LAST_INTERVAL" color="primary">
  34 + <section fxLayout="column">
  35 + <span translate>timewindow.last</span>
  36 + <tb-timeinterval
  37 + formControlName="timewindowMs"
  38 + predefinedName="timewindow.last"
  39 + [fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
  40 + [required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
  41 + timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
  42 + style="padding-top: 8px;"></tb-timeinterval>
  43 + </section>
  44 + </mat-radio-button>
  45 + <mat-radio-button [value]="realtimeTypes.INTERVAL" color="primary">
  46 + <section fxLayout="column">
  47 + <span translate>timewindow.interval</span>
  48 + <tb-quick-time-interval
  49 + formControlName="quickInterval"
  50 + onlyCurrentInterval="true"
  51 + [fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
  52 + [required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
  53 + timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
  54 + style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval>
  55 + </section>
  56 + </mat-radio-button>
  57 + </mat-radio-group>
  58 + </div>
  59 + </section>
  60 + </section>
34 </mat-tab> 61 </mat-tab>
35 <mat-tab label="{{ 'timewindow.history' | translate }}"> 62 <mat-tab label="{{ 'timewindow.history' | translate }}">
36 <section fxLayout="row"> 63 <section fxLayout="row">
@@ -19,7 +19,9 @@ import { @@ -19,7 +19,9 @@ import {
19 aggregationTranslations, 19 aggregationTranslations,
20 AggregationType, 20 AggregationType,
21 DAY, 21 DAY,
22 - HistoryWindowType, quickTimeIntervalPeriod, 22 + HistoryWindowType,
  23 + quickTimeIntervalPeriod,
  24 + RealtimeWindowType,
23 Timewindow, 25 Timewindow,
24 TimewindowType 26 TimewindowType
25 } from '@shared/models/time/time.models'; 27 } from '@shared/models/time/time.models';
@@ -60,6 +62,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -60,6 +62,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
60 62
61 historyTypes = HistoryWindowType; 63 historyTypes = HistoryWindowType;
62 64
  65 + realtimeTypes = RealtimeWindowType;
  66 +
63 timewindowTypes = TimewindowType; 67 timewindowTypes = TimewindowType;
64 68
65 aggregationTypes = AggregationType; 69 aggregationTypes = AggregationType;
@@ -89,6 +93,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -89,6 +93,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
89 this.timewindowForm = this.fb.group({ 93 this.timewindowForm = this.fb.group({
90 realtime: this.fb.group( 94 realtime: this.fb.group(
91 { 95 {
  96 + realtimeType: this.fb.control({
  97 + value: this.timewindow.realtime && typeof this.timewindow.realtime.realtimeType !== 'undefined'
  98 + ? this.timewindow.realtime.realtimeType : RealtimeWindowType.LAST_INTERVAL,
  99 + disabled: hideInterval
  100 + }),
92 timewindowMs: [ 101 timewindowMs: [
93 this.timewindow.realtime && typeof this.timewindow.realtime.timewindowMs !== 'undefined' 102 this.timewindow.realtime && typeof this.timewindow.realtime.timewindowMs !== 'undefined'
94 ? this.timewindow.realtime.timewindowMs : null 103 ? this.timewindow.realtime.timewindowMs : null
@@ -96,7 +105,12 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -96,7 +105,12 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
96 interval: [ 105 interval: [
97 this.timewindow.realtime && typeof this.timewindow.realtime.interval !== 'undefined' 106 this.timewindow.realtime && typeof this.timewindow.realtime.interval !== 'undefined'
98 ? this.timewindow.realtime.interval : null 107 ? this.timewindow.realtime.interval : null
99 - ] 108 + ],
  109 + quickInterval: this.fb.control({
  110 + value: this.timewindow.realtime && typeof this.timewindow.realtime.quickInterval !== 'undefined'
  111 + ? this.timewindow.realtime.quickInterval : null,
  112 + disabled: hideInterval
  113 + })
100 } 114 }
101 ), 115 ),
102 history: this.fb.group( 116 history: this.fb.group(
@@ -124,7 +138,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -124,7 +138,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
124 value: this.timewindow.history && typeof this.timewindow.history.quickInterval !== 'undefined' 138 value: this.timewindow.history && typeof this.timewindow.history.quickInterval !== 'undefined'
125 ? this.timewindow.history.quickInterval : null, 139 ? this.timewindow.history.quickInterval : null,
126 disabled: hideInterval 140 disabled: hideInterval
127 - }), 141 + })
128 } 142 }
129 ), 143 ),
130 aggregation: this.fb.group( 144 aggregation: this.fb.group(
@@ -147,7 +161,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -147,7 +161,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
147 update() { 161 update() {
148 const timewindowFormValue = this.timewindowForm.getRawValue(); 162 const timewindowFormValue = this.timewindowForm.getRawValue();
149 this.timewindow.realtime = { 163 this.timewindow.realtime = {
  164 + realtimeType: timewindowFormValue.realtime.realtimeType,
150 timewindowMs: timewindowFormValue.realtime.timewindowMs, 165 timewindowMs: timewindowFormValue.realtime.timewindowMs,
  166 + quickInterval: timewindowFormValue.realtime.quickInterval,
151 interval: timewindowFormValue.realtime.interval 167 interval: timewindowFormValue.realtime.interval
152 }; 168 };
153 this.timewindow.history = { 169 this.timewindow.history = {
@@ -180,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -180,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
180 } 196 }
181 197
182 minRealtimeAggInterval() { 198 minRealtimeAggInterval() {
183 - return this.timeService.minIntervalLimit(this.timewindowForm.get('realtime.timewindowMs').value); 199 + return this.timeService.minIntervalLimit(this.currentRealtimeTimewindow());
184 } 200 }
185 201
186 maxRealtimeAggInterval() { 202 maxRealtimeAggInterval() {
187 - return this.timeService.maxIntervalLimit(this.timewindowForm.get('realtime.timewindowMs').value); 203 + return this.timeService.maxIntervalLimit(this.currentRealtimeTimewindow());
  204 + }
  205 +
  206 + currentRealtimeTimewindow(): number {
  207 + const timeWindowFormValue = this.timewindowForm.getRawValue();
  208 + switch (timeWindowFormValue.realtime.realtimeType) {
  209 + case RealtimeWindowType.LAST_INTERVAL:
  210 + return timeWindowFormValue.realtime.timewindowMs;
  211 + case RealtimeWindowType.INTERVAL:
  212 + return quickTimeIntervalPeriod(timeWindowFormValue.realtime.quickInterval);
  213 + default:
  214 + return DAY;
  215 + }
188 } 216 }
189 217
190 minHistoryAggInterval() { 218 minHistoryAggInterval() {
@@ -215,11 +243,17 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { @@ -215,11 +243,17 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
215 this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false}); 243 this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false});
216 this.timewindowForm.get('history.fixedTimewindow').disable({emitEvent: false}); 244 this.timewindowForm.get('history.fixedTimewindow').disable({emitEvent: false});
217 this.timewindowForm.get('history.quickInterval').disable({emitEvent: false}); 245 this.timewindowForm.get('history.quickInterval').disable({emitEvent: false});
  246 + this.timewindowForm.get('realtime.realtimeType').disable({emitEvent: false});
  247 + this.timewindowForm.get('realtime.timewindowMs').disable({emitEvent: false});
  248 + this.timewindowForm.get('realtime.quickInterval').disable({emitEvent: false});
218 } else { 249 } else {
219 this.timewindowForm.get('history.historyType').enable({emitEvent: false}); 250 this.timewindowForm.get('history.historyType').enable({emitEvent: false});
220 this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false}); 251 this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false});
221 this.timewindowForm.get('history.fixedTimewindow').enable({emitEvent: false}); 252 this.timewindowForm.get('history.fixedTimewindow').enable({emitEvent: false});
222 this.timewindowForm.get('history.quickInterval').enable({emitEvent: false}); 253 this.timewindowForm.get('history.quickInterval').enable({emitEvent: false});
  254 + this.timewindowForm.get('realtime.realtimeType').enable({emitEvent: false});
  255 + this.timewindowForm.get('realtime.timewindowMs').enable({emitEvent: false});
  256 + this.timewindowForm.get('realtime.quickInterval').enable({emitEvent: false});
223 } 257 }
224 this.timewindowForm.markAsDirty(); 258 this.timewindowForm.markAsDirty();
225 } 259 }
@@ -34,6 +34,7 @@ import { @@ -34,6 +34,7 @@ import {
34 HistoryWindowType, 34 HistoryWindowType,
35 initModelFromDefaultTimewindow, 35 initModelFromDefaultTimewindow,
36 QuickTimeIntervalTranslationMap, 36 QuickTimeIntervalTranslationMap,
  37 + RealtimeWindowType,
37 Timewindow, 38 Timewindow,
38 TimewindowType 39 TimewindowType
39 } from '@shared/models/time/time.models'; 40 } from '@shared/models/time/time.models';
@@ -273,9 +274,13 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces @@ -273,9 +274,13 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
273 274
274 updateDisplayValue() { 275 updateDisplayValue() {
275 if (this.innerValue.selectedTab === TimewindowType.REALTIME && !this.historyOnly) { 276 if (this.innerValue.selectedTab === TimewindowType.REALTIME && !this.historyOnly) {
276 - this.innerValue.displayValue = this.translate.instant('timewindow.realtime') + ' - ' +  
277 - this.translate.instant('timewindow.last-prefix') + ' ' +  
278 - this.millisecondsToTimeStringPipe.transform(this.innerValue.realtime.timewindowMs); 277 + this.innerValue.displayValue = this.translate.instant('timewindow.realtime') + ' - ';
  278 + if (this.innerValue.realtime.realtimeType === RealtimeWindowType.INTERVAL) {
  279 + this.innerValue.displayValue += this.translate.instant(QuickTimeIntervalTranslationMap.get(this.innerValue.realtime.quickInterval));
  280 + } else {
  281 + this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' +
  282 + this.millisecondsToTimeStringPipe.transform(this.innerValue.realtime.timewindowMs);
  283 + }
279 } else { 284 } else {
280 this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : ''; 285 this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : '';
281 if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { 286 if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) {
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 /// 15 ///
16 16
17 import { TimeService } from '@core/services/time.service'; 17 import { TimeService } from '@core/services/time.service';
18 -import { deepClone, isDefined, isUndefined } from '@app/core/utils'; 18 +import { deepClone, isDefined, isDefinedAndNotNull, isUndefined } from '@app/core/utils';
19 import * as moment_ from 'moment'; 19 import * as moment_ from 'moment';
20 import { Observable } from 'rxjs/internal/Observable'; 20 import { Observable } from 'rxjs/internal/Observable';
21 import { from, of } from 'rxjs'; 21 import { from, of } from 'rxjs';
@@ -35,6 +35,11 @@ export enum TimewindowType { @@ -35,6 +35,11 @@ export enum TimewindowType {
35 HISTORY 35 HISTORY
36 } 36 }
37 37
  38 +export enum RealtimeWindowType {
  39 + LAST_INTERVAL,
  40 + INTERVAL
  41 +}
  42 +
38 export enum HistoryWindowType { 43 export enum HistoryWindowType {
39 LAST_INTERVAL, 44 LAST_INTERVAL,
40 FIXED, 45 FIXED,
@@ -47,6 +52,10 @@ export interface IntervalWindow { @@ -47,6 +52,10 @@ export interface IntervalWindow {
47 quickInterval?: QuickTimeInterval; 52 quickInterval?: QuickTimeInterval;
48 } 53 }
49 54
  55 +export interface RealtimeWindow extends IntervalWindow{
  56 + realtimeType?: RealtimeWindowType;
  57 +}
  58 +
50 export interface FixedWindow { 59 export interface FixedWindow {
51 startTimeMs: number; 60 startTimeMs: number;
52 endTimeMs: number; 61 endTimeMs: number;
@@ -89,7 +98,7 @@ export interface Timewindow { @@ -89,7 +98,7 @@ export interface Timewindow {
89 hideAggregation?: boolean; 98 hideAggregation?: boolean;
90 hideAggInterval?: boolean; 99 hideAggInterval?: boolean;
91 selectedTab?: TimewindowType; 100 selectedTab?: TimewindowType;
92 - realtime?: IntervalWindow; 101 + realtime?: RealtimeWindow;
93 history?: HistoryWindow; 102 history?: HistoryWindow;
94 aggregation?: Aggregation; 103 aggregation?: Aggregation;
95 } 104 }
@@ -102,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation { @@ -102,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation {
102 111
103 export interface SubscriptionTimewindow { 112 export interface SubscriptionTimewindow {
104 startTs?: number; 113 startTs?: number;
  114 + quickInterval?: QuickTimeInterval;
105 realtimeWindowMs?: number; 115 realtimeWindowMs?: number;
106 fixedWindow?: FixedWindow; 116 fixedWindow?: FixedWindow;
107 aggregation?: SubscriptionAggregation; 117 aggregation?: SubscriptionAggregation;
@@ -168,8 +178,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { @@ -168,8 +178,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow {
168 hideAggInterval: false, 178 hideAggInterval: false,
169 selectedTab: TimewindowType.REALTIME, 179 selectedTab: TimewindowType.REALTIME,
170 realtime: { 180 realtime: {
  181 + realtimeType: RealtimeWindowType.LAST_INTERVAL,
171 interval: SECOND, 182 interval: SECOND,
172 - timewindowMs: MINUTE 183 + timewindowMs: MINUTE,
  184 + quickInterval: QuickTimeInterval.TODAY
173 }, 185 },
174 history: { 186 history: {
175 historyType: HistoryWindowType.LAST_INTERVAL, 187 historyType: HistoryWindowType.LAST_INTERVAL,
@@ -208,7 +220,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T @@ -208,7 +220,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
208 if (isDefined(value.realtime.interval)) { 220 if (isDefined(value.realtime.interval)) {
209 model.realtime.interval = value.realtime.interval; 221 model.realtime.interval = value.realtime.interval;
210 } 222 }
211 - model.realtime.timewindowMs = value.realtime.timewindowMs; 223 + if (isUndefined(value.realtime.realtimeType)) {
  224 + if (isDefined(value.realtime.quickInterval)) {
  225 + model.realtime.realtimeType = RealtimeWindowType.INTERVAL;
  226 + } else {
  227 + model.realtime.realtimeType = RealtimeWindowType.LAST_INTERVAL;
  228 + }
  229 + } else {
  230 + model.realtime.realtimeType = value.realtime.realtimeType;
  231 + }
  232 + if (model.realtime.realtimeType === RealtimeWindowType.INTERVAL) {
  233 + model.realtime.quickInterval = value.realtime.quickInterval;
  234 + } else {
  235 + model.realtime.timewindowMs = value.realtime.timewindowMs;
  236 + }
212 } else { 237 } else {
213 if (isDefined(value.history.interval)) { 238 if (isDefined(value.history.interval)) {
214 model.history.interval = value.history.interval; 239 model.history.interval = value.history.interval;
@@ -309,14 +334,27 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num @@ -309,14 +334,27 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
309 selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY; 334 selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY;
310 } 335 }
311 if (selectedTab === TimewindowType.REALTIME) { 336 if (selectedTab === TimewindowType.REALTIME) {
312 - subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs; 337 + let realtimeType = timewindow.realtime.realtimeType;
  338 + if (isUndefined(realtimeType)) {
  339 + if (isDefined(timewindow.realtime.quickInterval)) {
  340 + realtimeType = RealtimeWindowType.INTERVAL;
  341 + } else {
  342 + realtimeType = RealtimeWindowType.LAST_INTERVAL;
  343 + }
  344 + }
  345 + if (realtimeType === RealtimeWindowType.INTERVAL) {
  346 + subscriptionTimewindow.realtimeWindowMs = getSubscriptionRealtimeWindowFromTimeInterval(timewindow.realtime.quickInterval);
  347 + subscriptionTimewindow.quickInterval = timewindow.realtime.quickInterval;
  348 + } else {
  349 + subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs;
  350 + }
313 subscriptionTimewindow.aggregation.interval = 351 subscriptionTimewindow.aggregation.interval =
314 timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval, 352 timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval,
315 subscriptionTimewindow.aggregation.type); 353 subscriptionTimewindow.aggregation.type);
316 subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs; 354 subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs;
317 const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval; 355 const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval;
318 aggTimewindow = subscriptionTimewindow.realtimeWindowMs; 356 aggTimewindow = subscriptionTimewindow.realtimeWindowMs;
319 - if (startDiff) { 357 + if (startDiff && realtimeType !== RealtimeWindowType.INTERVAL) {
320 subscriptionTimewindow.startTs -= startDiff; 358 subscriptionTimewindow.startTs -= startDiff;
321 aggTimewindow += subscriptionTimewindow.aggregation.interval; 359 aggTimewindow += subscriptionTimewindow.aggregation.interval;
322 } 360 }
@@ -339,7 +377,11 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num @@ -339,7 +377,11 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
339 }; 377 };
340 aggTimewindow = timewindow.history.timewindowMs; 378 aggTimewindow = timewindow.history.timewindowMs;
341 } else if (historyType === HistoryWindowType.INTERVAL) { 379 } else if (historyType === HistoryWindowType.INTERVAL) {
342 - subscriptionTimewindow.fixedWindow = createSubscriptionTimeWindowFromQuickKTimeInterval(timewindow.history.quickInterval); 380 + const currentDate = moment();
  381 + subscriptionTimewindow.fixedWindow = {
  382 + startTimeMs: calculateIntervalStartTime(timewindow.history.quickInterval, null, currentDate),
  383 + endTimeMs: calculateIntervalEndTime(timewindow.history.quickInterval, null, currentDate)
  384 + };
343 aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; 385 aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
344 } else { 386 } else {
345 subscriptionTimewindow.fixedWindow = { 387 subscriptionTimewindow.fixedWindow = {
@@ -360,77 +402,99 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num @@ -360,77 +402,99 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
360 return subscriptionTimewindow; 402 return subscriptionTimewindow;
361 } 403 }
362 404
363 -export function createSubscriptionTimeWindowFromQuickKTimeInterval(interval: QuickTimeInterval): FixedWindow { 405 +function getSubscriptionRealtimeWindowFromTimeInterval(interval: QuickTimeInterval): number {
364 const currentDate = moment(); 406 const currentDate = moment();
365 - const timeWindow = {  
366 - startTimeMs: 0,  
367 - endTimeMs: 0  
368 - }; 407 + switch (interval) {
  408 + case QuickTimeInterval.TODAY:
  409 + case QuickTimeInterval.TODAY_SO_FAR:
  410 + return currentDate.diff(currentDate.clone().startOf('day'));
  411 + case QuickTimeInterval.CURRENT_WEEK:
  412 + case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
  413 + return currentDate.diff(currentDate.clone().startOf('week'));
  414 + case QuickTimeInterval.CURRENT_MONTH:
  415 + case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
  416 + return currentDate.diff(currentDate.clone().startOf('month'));
  417 + case QuickTimeInterval.CURRENT_YEAR:
  418 + case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
  419 + return currentDate.diff(currentDate.clone().startOf('year'));
  420 + }
  421 +}
  422 +
  423 +export function calculateIntervalEndTime(interval: QuickTimeInterval, endTs = 0, nowDate?: moment_.Moment): number {
  424 + const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
  425 + switch (interval) {
  426 + case QuickTimeInterval.YESTERDAY:
  427 + currentDate.subtract(1, 'days');
  428 + return currentDate.endOf('day').valueOf();
  429 + case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
  430 + currentDate.subtract(2, 'days');
  431 + return currentDate.endOf('day').valueOf();
  432 + case QuickTimeInterval.THIS_DAY_LAST_WEEK:
  433 + currentDate.subtract(1, 'weeks');
  434 + return currentDate.endOf('day').valueOf();
  435 + case QuickTimeInterval.PREVIOUS_WEEK:
  436 + currentDate.subtract(1, 'weeks');
  437 + return currentDate.endOf('week').valueOf();
  438 + case QuickTimeInterval.PREVIOUS_MONTH:
  439 + currentDate.subtract(1, 'months');
  440 + return currentDate.endOf('month').valueOf();
  441 + case QuickTimeInterval.PREVIOUS_YEAR:
  442 + currentDate.subtract(1, 'years');
  443 + return currentDate.endOf('year').valueOf();
  444 + case QuickTimeInterval.TODAY:
  445 + return currentDate.endOf('day').valueOf();
  446 + case QuickTimeInterval.CURRENT_WEEK:
  447 + return currentDate.endOf('week').valueOf();
  448 + case QuickTimeInterval.CURRENT_MONTH:
  449 + return currentDate.endOf('month').valueOf();
  450 + case QuickTimeInterval.CURRENT_YEAR:
  451 + return currentDate.endOf('year').valueOf();
  452 + case QuickTimeInterval.TODAY_SO_FAR:
  453 + case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
  454 + case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
  455 + case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
  456 + return currentDate.valueOf();
  457 + default:
  458 + return endTs;
  459 + }
  460 +}
  461 +
  462 +export function calculateIntervalStartTime(interval: QuickTimeInterval, startTS = 0, nowDate?: moment_.Moment): number {
  463 + const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
369 switch (interval) { 464 switch (interval) {
370 case QuickTimeInterval.YESTERDAY: 465 case QuickTimeInterval.YESTERDAY:
371 currentDate.subtract(1, 'days'); 466 currentDate.subtract(1, 'days');
372 - timeWindow.startTimeMs = currentDate.startOf('day').valueOf();  
373 - timeWindow.endTimeMs = currentDate.endOf('day').valueOf();  
374 - break; 467 + return currentDate.startOf('day').valueOf();
375 case QuickTimeInterval.DAY_BEFORE_YESTERDAY: 468 case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
376 currentDate.subtract(2, 'days'); 469 currentDate.subtract(2, 'days');
377 - timeWindow.startTimeMs = currentDate.startOf('day').valueOf();  
378 - timeWindow.endTimeMs = currentDate.endOf('day').valueOf();  
379 - break; 470 + return currentDate.startOf('day').valueOf();
380 case QuickTimeInterval.THIS_DAY_LAST_WEEK: 471 case QuickTimeInterval.THIS_DAY_LAST_WEEK:
381 currentDate.subtract(1, 'weeks'); 472 currentDate.subtract(1, 'weeks');
382 - timeWindow.startTimeMs = currentDate.startOf('day').valueOf();  
383 - timeWindow.endTimeMs = currentDate.endOf('day').valueOf();  
384 - break; 473 + return currentDate.startOf('day').valueOf();
385 case QuickTimeInterval.PREVIOUS_WEEK: 474 case QuickTimeInterval.PREVIOUS_WEEK:
386 currentDate.subtract(1, 'weeks'); 475 currentDate.subtract(1, 'weeks');
387 - timeWindow.startTimeMs = currentDate.startOf('week').valueOf();  
388 - timeWindow.endTimeMs = currentDate.endOf('week').valueOf();  
389 - break; 476 + return currentDate.startOf('week').valueOf();
390 case QuickTimeInterval.PREVIOUS_MONTH: 477 case QuickTimeInterval.PREVIOUS_MONTH:
391 currentDate.subtract(1, 'months'); 478 currentDate.subtract(1, 'months');
392 - timeWindow.startTimeMs = currentDate.startOf('month').valueOf();  
393 - timeWindow.endTimeMs = currentDate.endOf('month').valueOf();  
394 - break; 479 + return currentDate.startOf('month').valueOf();
395 case QuickTimeInterval.PREVIOUS_YEAR: 480 case QuickTimeInterval.PREVIOUS_YEAR:
396 currentDate.subtract(1, 'years'); 481 currentDate.subtract(1, 'years');
397 - timeWindow.startTimeMs = currentDate.startOf('year').valueOf();  
398 - timeWindow.endTimeMs = currentDate.endOf('year').valueOf();  
399 - break; 482 + return currentDate.startOf('year').valueOf();
400 case QuickTimeInterval.TODAY: 483 case QuickTimeInterval.TODAY:
401 - timeWindow.startTimeMs = currentDate.startOf('day').valueOf();  
402 - timeWindow.endTimeMs = currentDate.endOf('day').valueOf();  
403 - break;  
404 case QuickTimeInterval.TODAY_SO_FAR: 484 case QuickTimeInterval.TODAY_SO_FAR:
405 - timeWindow.endTimeMs = currentDate.valueOf();  
406 - timeWindow.startTimeMs = currentDate.startOf('day').valueOf();  
407 - break; 485 + return currentDate.startOf('day').valueOf();
408 case QuickTimeInterval.CURRENT_WEEK: 486 case QuickTimeInterval.CURRENT_WEEK:
409 - timeWindow.startTimeMs = currentDate.startOf('week').valueOf();  
410 - timeWindow.endTimeMs = currentDate.endOf('week').valueOf();  
411 - break;  
412 case QuickTimeInterval.CURRENT_WEEK_SO_FAR: 487 case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
413 - timeWindow.endTimeMs = currentDate.valueOf();  
414 - timeWindow.startTimeMs = currentDate.startOf('week').valueOf();  
415 - break; 488 + return currentDate.startOf('week').valueOf();
416 case QuickTimeInterval.CURRENT_MONTH: 489 case QuickTimeInterval.CURRENT_MONTH:
417 - timeWindow.startTimeMs = currentDate.startOf('month').valueOf();  
418 - timeWindow.endTimeMs = currentDate.endOf('month').valueOf();  
419 - break;  
420 case QuickTimeInterval.CURRENT_MONTH_SO_FAR: 490 case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
421 - timeWindow.endTimeMs = currentDate.valueOf();  
422 - timeWindow.startTimeMs = currentDate.startOf('month').valueOf();  
423 - break; 491 + return currentDate.startOf('month').valueOf();
424 case QuickTimeInterval.CURRENT_YEAR: 492 case QuickTimeInterval.CURRENT_YEAR:
425 - timeWindow.startTimeMs = currentDate.startOf('year').valueOf();  
426 - timeWindow.endTimeMs = currentDate.endOf('year').valueOf();  
427 - break;  
428 case QuickTimeInterval.CURRENT_YEAR_SO_FAR: 493 case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
429 - timeWindow.endTimeMs = currentDate.valueOf();  
430 - timeWindow.startTimeMs = currentDate.startOf('year').valueOf();  
431 - break; 494 + return currentDate.startOf('year').valueOf();
  495 + default:
  496 + return startTS;
432 } 497 }
433 - return timeWindow;  
434 } 498 }
435 499
436 export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number { 500 export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number {