Commit 0ebbee02db9a981715bc774f2d99b7aa10be4470
1 parent
f1193c1d
UI: Added new timewindow type - realtime interval
Showing
8 changed files
with
230 additions
and
85 deletions
@@ -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 { |