Commit d184d8db7298d2f224cb5d6a315eab29c6e39211
Merge branch 'feature/timeWindow/quick-interval' of https://github.com/vvlladd28…
…/thingsboard into vvlladd28-feature/timeWindow/quick-interval
Showing
12 changed files
with
517 additions
and
42 deletions
... | ... | @@ -15,7 +15,12 @@ |
15 | 15 | /// |
16 | 16 | |
17 | 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 | 24 | import { UtilsService } from '@core/services/utils.service'; |
20 | 25 | import { deepClone } from '@core/utils'; |
21 | 26 | import Timeout = NodeJS.Timeout; |
... | ... | @@ -92,7 +97,8 @@ export class DataAggregator { |
92 | 97 | private interval: number, |
93 | 98 | private stateData: boolean, |
94 | 99 | private utils: UtilsService, |
95 | - private ignoreDataUpdateOnIntervalTick: boolean) { | |
100 | + private ignoreDataUpdateOnIntervalTick: boolean, | |
101 | + private quickInterval: QuickTimeInterval) { | |
96 | 102 | this.tsKeyNames.forEach((key) => { |
97 | 103 | this.dataBuffer[key] = []; |
98 | 104 | }); |
... | ... | @@ -138,7 +144,8 @@ export class DataAggregator { |
138 | 144 | this.startTs = startTs; |
139 | 145 | this.timeWindow = timeWindow; |
140 | 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 | 149 | this.elapsed = 0; |
143 | 150 | this.aggregationTimeout = Math.max(this.interval, 1000); |
144 | 151 | this.resetPending = true; |
... | ... | @@ -161,7 +168,8 @@ export class DataAggregator { |
161 | 168 | if (!this.dataReceived) { |
162 | 169 | this.elapsed = 0; |
163 | 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 | 174 | if (this.resetPending) { |
167 | 175 | this.resetPending = false; |
... | ... | @@ -197,8 +205,11 @@ export class DataAggregator { |
197 | 205 | if (!history) { |
198 | 206 | const delta = Math.floor(this.elapsed / this.interval); |
199 | 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 | 213 | this.data = this.updateData(); |
203 | 214 | this.elapsed = this.elapsed - delta * this.interval; |
204 | 215 | } | ... | ... |
... | ... | @@ -752,7 +752,8 @@ export class EntityDataSubscription { |
752 | 752 | subsTw.aggregation.interval, |
753 | 753 | subsTw.aggregation.stateData, |
754 | 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 | 37 | } from '@app/shared/models/widget.models'; |
38 | 38 | import { HttpErrorResponse } from '@angular/common/http'; |
39 | 39 | import { |
40 | + calculateIntervalEndTime, | |
41 | + calculateIntervalStartTime, | |
40 | 42 | createSubscriptionTimewindow, |
41 | 43 | createTimewindowForComparison, |
42 | 44 | SubscriptionTimewindow, |
... | ... | @@ -1081,8 +1083,10 @@ export class WidgetSubscription implements IWidgetSubscription { |
1081 | 1083 | private updateTimewindow() { |
1082 | 1084 | this.timeWindow.interval = this.subscriptionTimewindow.aggregation.interval || 1000; |
1083 | 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 | 1090 | } else if (this.subscriptionTimewindow.fixedWindow) { |
1087 | 1091 | this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs; |
1088 | 1092 | this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs; |
... | ... | @@ -1105,7 +1109,7 @@ export class WidgetSubscription implements IWidgetSubscription { |
1105 | 1109 | this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000; |
1106 | 1110 | if (this.timewindowForComparison.realtimeWindowMs) { |
1107 | 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 | 1113 | } else if (this.timewindowForComparison.fixedWindow) { |
1110 | 1114 | this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs; |
1111 | 1115 | this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs; | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<section class="interval-section" fxLayout="row" fxFlex> | |
19 | + <mat-form-field fxFlex> | |
20 | + <mat-label translate>timewindow.interval</mat-label> | |
21 | + <mat-select [disabled]="disabled" [(ngModel)]="modelValue" (ngModelChange)="onIntervalChange()"> | |
22 | + <mat-option *ngFor="let interval of intervals" [value]="interval"> | |
23 | + {{ timeIntervalTranslationMap.get(interval) | translate}} | |
24 | + </mat-option> | |
25 | + </mat-select> | |
26 | + </mat-form-field> | |
27 | +</section> | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +:host { | |
18 | + min-width: 364px; | |
19 | +} | ... | ... |
1 | +/// | |
2 | +/// Copyright © 2016-2021 The Thingsboard Authors | |
3 | +/// | |
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +/// you may not use this file except in compliance with the License. | |
6 | +/// You may obtain a copy of the License at | |
7 | +/// | |
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +/// | |
10 | +/// Unless required by applicable law or agreed to in writing, software | |
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +/// See the License for the specific language governing permissions and | |
14 | +/// limitations under the License. | |
15 | +/// | |
16 | + | |
17 | +import { Component, forwardRef, Input, OnInit } from '@angular/core'; | |
18 | +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | |
19 | +import { QuickTimeInterval, QuickTimeIntervalTranslationMap } from '@shared/models/time/time.models'; | |
20 | + | |
21 | +@Component({ | |
22 | + selector: 'tb-quick-time-interval', | |
23 | + templateUrl: './quick-time-interval.component.html', | |
24 | + styleUrls: ['./quick-time-interval.component.scss'], | |
25 | + providers: [ | |
26 | + { | |
27 | + provide: NG_VALUE_ACCESSOR, | |
28 | + useExisting: forwardRef(() => QuickTimeIntervalComponent), | |
29 | + multi: true | |
30 | + } | |
31 | + ] | |
32 | +}) | |
33 | +export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor { | |
34 | + | |
35 | + private allIntervals = Object.values(QuickTimeInterval); | |
36 | + | |
37 | + modelValue: QuickTimeInterval; | |
38 | + timeIntervalTranslationMap = QuickTimeIntervalTranslationMap; | |
39 | + | |
40 | + rendered = false; | |
41 | + | |
42 | + @Input() disabled: boolean; | |
43 | + | |
44 | + @Input() onlyCurrentInterval = false; | |
45 | + | |
46 | + private propagateChange = (_: any) => {}; | |
47 | + | |
48 | + constructor() { | |
49 | + } | |
50 | + | |
51 | + get intervals() { | |
52 | + if (this.onlyCurrentInterval) { | |
53 | + return this.allIntervals.filter(interval => interval.startsWith('CURRENT_')); | |
54 | + } | |
55 | + return this.allIntervals; | |
56 | + } | |
57 | + | |
58 | + ngOnInit(): void { | |
59 | + } | |
60 | + | |
61 | + registerOnChange(fn: any): void { | |
62 | + this.propagateChange = fn; | |
63 | + } | |
64 | + | |
65 | + registerOnTouched(fn: any): void { | |
66 | + } | |
67 | + | |
68 | + setDisabledState(isDisabled: boolean): void { | |
69 | + this.disabled = isDisabled; | |
70 | + } | |
71 | + | |
72 | + writeValue(interval: QuickTimeInterval): void { | |
73 | + this.modelValue = interval; | |
74 | + } | |
75 | + | |
76 | + onIntervalChange() { | |
77 | + this.propagateChange(this.modelValue); | |
78 | + } | |
79 | +} | ... | ... |
... | ... | @@ -21,16 +21,43 @@ |
21 | 21 | <mat-tab-group dynamicHeight [ngClass]="{'tb-headless': historyOnly}" |
22 | 22 | (selectedIndexChange)="timewindowForm.markAsDirty()" [(selectedIndex)]="timewindow.selectedTab"> |
23 | 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 | 61 | </mat-tab> |
35 | 62 | <mat-tab label="{{ 'timewindow.history' | translate }}"> |
36 | 63 | <section fxLayout="row"> |
... | ... | @@ -65,6 +92,17 @@ |
65 | 92 | style="padding-top: 8px;"></tb-datetime-period> |
66 | 93 | </section> |
67 | 94 | </mat-radio-button> |
95 | + <mat-radio-button [value]="historyTypes.INTERVAL" color="primary"> | |
96 | + <section fxLayout="column"> | |
97 | + <span translate>timewindow.interval</span> | |
98 | + <tb-quick-time-interval | |
99 | + formControlName="quickInterval" | |
100 | + [fxShow]="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL" | |
101 | + [required]="timewindow.selectedTab === timewindowTypes.HISTORY && | |
102 | + timewindowForm.get('history.historyType').value === historyTypes.INTERVAL" | |
103 | + style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval> | |
104 | + </section> | |
105 | + </mat-radio-button> | |
68 | 106 | </mat-radio-group> |
69 | 107 | </div> |
70 | 108 | </section> | ... | ... |
... | ... | @@ -20,6 +20,8 @@ import { |
20 | 20 | AggregationType, |
21 | 21 | DAY, |
22 | 22 | HistoryWindowType, |
23 | + quickTimeIntervalPeriod, | |
24 | + RealtimeWindowType, | |
23 | 25 | Timewindow, |
24 | 26 | TimewindowType |
25 | 27 | } from '@shared/models/time/time.models'; |
... | ... | @@ -60,6 +62,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
60 | 62 | |
61 | 63 | historyTypes = HistoryWindowType; |
62 | 64 | |
65 | + realtimeTypes = RealtimeWindowType; | |
66 | + | |
63 | 67 | timewindowTypes = TimewindowType; |
64 | 68 | |
65 | 69 | aggregationTypes = AggregationType; |
... | ... | @@ -89,6 +93,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
89 | 93 | this.timewindowForm = this.fb.group({ |
90 | 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 | 101 | timewindowMs: [ |
93 | 102 | this.timewindow.realtime && typeof this.timewindow.realtime.timewindowMs !== 'undefined' |
94 | 103 | ? this.timewindow.realtime.timewindowMs : null |
... | ... | @@ -96,7 +105,12 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
96 | 105 | interval: [ |
97 | 106 | this.timewindow.realtime && typeof this.timewindow.realtime.interval !== 'undefined' |
98 | 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 | 116 | history: this.fb.group( |
... | ... | @@ -119,6 +133,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
119 | 133 | value: this.timewindow.history && typeof this.timewindow.history.fixedTimewindow !== 'undefined' |
120 | 134 | ? this.timewindow.history.fixedTimewindow : null, |
121 | 135 | disabled: hideInterval |
136 | + }), | |
137 | + quickInterval: this.fb.control({ | |
138 | + value: this.timewindow.history && typeof this.timewindow.history.quickInterval !== 'undefined' | |
139 | + ? this.timewindow.history.quickInterval : null, | |
140 | + disabled: hideInterval | |
122 | 141 | }) |
123 | 142 | } |
124 | 143 | ), |
... | ... | @@ -142,14 +161,17 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
142 | 161 | update() { |
143 | 162 | const timewindowFormValue = this.timewindowForm.getRawValue(); |
144 | 163 | this.timewindow.realtime = { |
164 | + realtimeType: timewindowFormValue.realtime.realtimeType, | |
145 | 165 | timewindowMs: timewindowFormValue.realtime.timewindowMs, |
166 | + quickInterval: timewindowFormValue.realtime.quickInterval, | |
146 | 167 | interval: timewindowFormValue.realtime.interval |
147 | 168 | }; |
148 | 169 | this.timewindow.history = { |
149 | 170 | historyType: timewindowFormValue.history.historyType, |
150 | 171 | timewindowMs: timewindowFormValue.history.timewindowMs, |
151 | 172 | interval: timewindowFormValue.history.interval, |
152 | - fixedTimewindow: timewindowFormValue.history.fixedTimewindow | |
173 | + fixedTimewindow: timewindowFormValue.history.fixedTimewindow, | |
174 | + quickInterval: timewindowFormValue.history.quickInterval | |
153 | 175 | }; |
154 | 176 | if (this.aggregation) { |
155 | 177 | this.timewindow.aggregation = { |
... | ... | @@ -174,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
174 | 196 | } |
175 | 197 | |
176 | 198 | minRealtimeAggInterval() { |
177 | - return this.timeService.minIntervalLimit(this.timewindowForm.get('realtime.timewindowMs').value); | |
199 | + return this.timeService.minIntervalLimit(this.currentRealtimeTimewindow()); | |
178 | 200 | } |
179 | 201 | |
180 | 202 | maxRealtimeAggInterval() { |
181 | - 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 | + } | |
182 | 216 | } |
183 | 217 | |
184 | 218 | minHistoryAggInterval() { |
... | ... | @@ -193,6 +227,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
193 | 227 | const timewindowFormValue = this.timewindowForm.getRawValue(); |
194 | 228 | if (timewindowFormValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
195 | 229 | return timewindowFormValue.history.timewindowMs; |
230 | + } else if (timewindowFormValue.history.historyType === HistoryWindowType.INTERVAL) { | |
231 | + return quickTimeIntervalPeriod(timewindowFormValue.history.quickInterval); | |
196 | 232 | } else if (timewindowFormValue.history.fixedTimewindow) { |
197 | 233 | return timewindowFormValue.history.fixedTimewindow.endTimeMs - |
198 | 234 | timewindowFormValue.history.fixedTimewindow.startTimeMs; |
... | ... | @@ -206,10 +242,18 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { |
206 | 242 | this.timewindowForm.get('history.historyType').disable({emitEvent: false}); |
207 | 243 | this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false}); |
208 | 244 | this.timewindowForm.get('history.fixedTimewindow').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}); | |
209 | 249 | } else { |
210 | 250 | this.timewindowForm.get('history.historyType').enable({emitEvent: false}); |
211 | 251 | this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false}); |
212 | 252 | this.timewindowForm.get('history.fixedTimewindow').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}); | |
213 | 257 | } |
214 | 258 | this.timewindowForm.markAsDirty(); |
215 | 259 | } | ... | ... |
... | ... | @@ -33,6 +33,8 @@ import { |
33 | 33 | cloneSelectedTimewindow, |
34 | 34 | HistoryWindowType, |
35 | 35 | initModelFromDefaultTimewindow, |
36 | + QuickTimeIntervalTranslationMap, | |
37 | + RealtimeWindowType, | |
36 | 38 | Timewindow, |
37 | 39 | TimewindowType |
38 | 40 | } from '@shared/models/time/time.models'; |
... | ... | @@ -272,14 +274,20 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces |
272 | 274 | |
273 | 275 | updateDisplayValue() { |
274 | 276 | if (this.innerValue.selectedTab === TimewindowType.REALTIME && !this.historyOnly) { |
275 | - this.innerValue.displayValue = this.translate.instant('timewindow.realtime') + ' - ' + | |
276 | - this.translate.instant('timewindow.last-prefix') + ' ' + | |
277 | - 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 | + } | |
278 | 284 | } else { |
279 | 285 | this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : ''; |
280 | 286 | if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
281 | 287 | this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' + |
282 | 288 | this.millisecondsToTimeStringPipe.transform(this.innerValue.history.timewindowMs); |
289 | + } else if (this.innerValue.history.historyType === HistoryWindowType.INTERVAL) { | |
290 | + this.innerValue.displayValue += this.translate.instant(QuickTimeIntervalTranslationMap.get(this.innerValue.history.quickInterval)); | |
283 | 291 | } else { |
284 | 292 | const startString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.startTimeMs, 'yyyy-MM-dd HH:mm:ss'); |
285 | 293 | const endString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.endTimeMs, 'yyyy-MM-dd HH:mm:ss'); | ... | ... |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | /// |
16 | 16 | |
17 | 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 | 19 | import * as moment_ from 'moment'; |
20 | 20 | import { Observable } from 'rxjs/internal/Observable'; |
21 | 21 | import { from, of } from 'rxjs'; |
... | ... | @@ -27,6 +27,7 @@ export const SECOND = 1000; |
27 | 27 | export const MINUTE = 60 * SECOND; |
28 | 28 | export const HOUR = 60 * MINUTE; |
29 | 29 | export const DAY = 24 * HOUR; |
30 | +export const WEEK = 7 * DAY; | |
30 | 31 | export const YEAR = DAY * 365; |
31 | 32 | |
32 | 33 | export enum TimewindowType { |
... | ... | @@ -34,14 +35,25 @@ export enum TimewindowType { |
34 | 35 | HISTORY |
35 | 36 | } |
36 | 37 | |
38 | +export enum RealtimeWindowType { | |
39 | + LAST_INTERVAL, | |
40 | + INTERVAL | |
41 | +} | |
42 | + | |
37 | 43 | export enum HistoryWindowType { |
38 | 44 | LAST_INTERVAL, |
39 | - FIXED | |
45 | + FIXED, | |
46 | + INTERVAL | |
40 | 47 | } |
41 | 48 | |
42 | 49 | export interface IntervalWindow { |
43 | 50 | interval?: number; |
44 | 51 | timewindowMs?: number; |
52 | + quickInterval?: QuickTimeInterval; | |
53 | +} | |
54 | + | |
55 | +export interface RealtimeWindow extends IntervalWindow{ | |
56 | + realtimeType?: RealtimeWindowType; | |
45 | 57 | } |
46 | 58 | |
47 | 59 | export interface FixedWindow { |
... | ... | @@ -86,7 +98,7 @@ export interface Timewindow { |
86 | 98 | hideAggregation?: boolean; |
87 | 99 | hideAggInterval?: boolean; |
88 | 100 | selectedTab?: TimewindowType; |
89 | - realtime?: IntervalWindow; | |
101 | + realtime?: RealtimeWindow; | |
90 | 102 | history?: HistoryWindow; |
91 | 103 | aggregation?: Aggregation; |
92 | 104 | } |
... | ... | @@ -99,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation { |
99 | 111 | |
100 | 112 | export interface SubscriptionTimewindow { |
101 | 113 | startTs?: number; |
114 | + quickInterval?: QuickTimeInterval; | |
102 | 115 | realtimeWindowMs?: number; |
103 | 116 | fixedWindow?: FixedWindow; |
104 | 117 | aggregation?: SubscriptionAggregation; |
... | ... | @@ -111,6 +124,42 @@ export interface WidgetTimewindow { |
111 | 124 | stDiff?: number; |
112 | 125 | } |
113 | 126 | |
127 | +export enum QuickTimeInterval { | |
128 | + YESTERDAY = 'YESTERDAY', | |
129 | + DAY_BEFORE_YESTERDAY = 'DAY_BEFORE_YESTERDAY', | |
130 | + THIS_DAY_LAST_WEEK = 'THIS_DAY_LAST_WEEK', | |
131 | + PREVIOUS_WEEK = 'PREVIOUS_WEEK', | |
132 | + PREVIOUS_MONTH = 'PREVIOUS_MONTH', | |
133 | + PREVIOUS_YEAR = 'PREVIOUS_YEAR', | |
134 | + CURRENT_HOUR = 'CURRENT_HOUR', | |
135 | + CURRENT_DAY = 'CURRENT_DAY', | |
136 | + CURRENT_DAY_SO_FAR = 'CURRENT_DAY_SO_FAR', | |
137 | + CURRENT_WEEK = 'CURRENT_WEEK', | |
138 | + CURRENT_WEEK_SO_FAR = 'CURRENT_WEEK_SO_WAR', | |
139 | + CURRENT_MONTH = 'CURRENT_MONTH', | |
140 | + CURRENT_MONTH_SO_FAR = 'CURRENT_MONTH_SO_FAR', | |
141 | + CURRENT_YEAR = 'CURRENT_YEAR', | |
142 | + CURRENT_YEAR_SO_FAR = 'CURRENT_YEAR_SO_FAR' | |
143 | +} | |
144 | + | |
145 | +export const QuickTimeIntervalTranslationMap = new Map<QuickTimeInterval, string>([ | |
146 | + [QuickTimeInterval.YESTERDAY, 'timeinterval.predefined.yesterday'], | |
147 | + [QuickTimeInterval.DAY_BEFORE_YESTERDAY, 'timeinterval.predefined.day-before-yesterday'], | |
148 | + [QuickTimeInterval.THIS_DAY_LAST_WEEK, 'timeinterval.predefined.this-day-last-week'], | |
149 | + [QuickTimeInterval.PREVIOUS_WEEK, 'timeinterval.predefined.previous-week'], | |
150 | + [QuickTimeInterval.PREVIOUS_MONTH, 'timeinterval.predefined.previous-month'], | |
151 | + [QuickTimeInterval.PREVIOUS_YEAR, 'timeinterval.predefined.previous-year'], | |
152 | + [QuickTimeInterval.CURRENT_HOUR, 'timeinterval.predefined.current-hour'], | |
153 | + [QuickTimeInterval.CURRENT_DAY, 'timeinterval.predefined.current-day'], | |
154 | + [QuickTimeInterval.CURRENT_DAY_SO_FAR, 'timeinterval.predefined.current-day-so-far'], | |
155 | + [QuickTimeInterval.CURRENT_WEEK, 'timeinterval.predefined.current-week'], | |
156 | + [QuickTimeInterval.CURRENT_WEEK_SO_FAR, 'timeinterval.predefined.current-week-so-far'], | |
157 | + [QuickTimeInterval.CURRENT_MONTH, 'timeinterval.predefined.current-month'], | |
158 | + [QuickTimeInterval.CURRENT_MONTH_SO_FAR, 'timeinterval.predefined.current-month-so-far'], | |
159 | + [QuickTimeInterval.CURRENT_YEAR, 'timeinterval.predefined.current-year'], | |
160 | + [QuickTimeInterval.CURRENT_YEAR_SO_FAR, 'timeinterval.predefined.current-year-so-far'] | |
161 | +]); | |
162 | + | |
114 | 163 | export function historyInterval(timewindowMs: number): Timewindow { |
115 | 164 | const timewindow: Timewindow = { |
116 | 165 | selectedTab: TimewindowType.HISTORY, |
... | ... | @@ -131,8 +180,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { |
131 | 180 | hideAggInterval: false, |
132 | 181 | selectedTab: TimewindowType.REALTIME, |
133 | 182 | realtime: { |
183 | + realtimeType: RealtimeWindowType.LAST_INTERVAL, | |
134 | 184 | interval: SECOND, |
135 | - timewindowMs: MINUTE | |
185 | + timewindowMs: MINUTE, | |
186 | + quickInterval: QuickTimeInterval.CURRENT_DAY | |
136 | 187 | }, |
137 | 188 | history: { |
138 | 189 | historyType: HistoryWindowType.LAST_INTERVAL, |
... | ... | @@ -141,7 +192,8 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { |
141 | 192 | fixedTimewindow: { |
142 | 193 | startTimeMs: currentTime - DAY, |
143 | 194 | endTimeMs: currentTime |
144 | - } | |
195 | + }, | |
196 | + quickInterval: QuickTimeInterval.CURRENT_DAY | |
145 | 197 | }, |
146 | 198 | aggregation: { |
147 | 199 | type: AggregationType.AVG, |
... | ... | @@ -170,7 +222,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T |
170 | 222 | if (isDefined(value.realtime.interval)) { |
171 | 223 | model.realtime.interval = value.realtime.interval; |
172 | 224 | } |
173 | - model.realtime.timewindowMs = value.realtime.timewindowMs; | |
225 | + if (isUndefined(value.realtime.realtimeType)) { | |
226 | + if (isDefined(value.realtime.quickInterval)) { | |
227 | + model.realtime.realtimeType = RealtimeWindowType.INTERVAL; | |
228 | + } else { | |
229 | + model.realtime.realtimeType = RealtimeWindowType.LAST_INTERVAL; | |
230 | + } | |
231 | + } else { | |
232 | + model.realtime.realtimeType = value.realtime.realtimeType; | |
233 | + } | |
234 | + if (model.realtime.realtimeType === RealtimeWindowType.INTERVAL) { | |
235 | + model.realtime.quickInterval = value.realtime.quickInterval; | |
236 | + } else { | |
237 | + model.realtime.timewindowMs = value.realtime.timewindowMs; | |
238 | + } | |
174 | 239 | } else { |
175 | 240 | if (isDefined(value.history.interval)) { |
176 | 241 | model.history.interval = value.history.interval; |
... | ... | @@ -178,6 +243,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T |
178 | 243 | if (isUndefined(value.history.historyType)) { |
179 | 244 | if (isDefined(value.history.timewindowMs)) { |
180 | 245 | model.history.historyType = HistoryWindowType.LAST_INTERVAL; |
246 | + } else if (isDefined(value.history.quickInterval)) { | |
247 | + model.history.historyType = HistoryWindowType.INTERVAL; | |
181 | 248 | } else { |
182 | 249 | model.history.historyType = HistoryWindowType.FIXED; |
183 | 250 | } |
... | ... | @@ -186,6 +253,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T |
186 | 253 | } |
187 | 254 | if (model.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
188 | 255 | model.history.timewindowMs = value.history.timewindowMs; |
256 | + } else if (model.history.historyType === HistoryWindowType.INTERVAL) { | |
257 | + model.history.quickInterval = value.history.quickInterval; | |
189 | 258 | } else { |
190 | 259 | model.history.fixedTimewindow.startTimeMs = value.history.fixedTimewindow.startTimeMs; |
191 | 260 | model.history.fixedTimewindow.endTimeMs = value.history.fixedTimewindow.endTimeMs; |
... | ... | @@ -267,21 +336,40 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num |
267 | 336 | selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY; |
268 | 337 | } |
269 | 338 | if (selectedTab === TimewindowType.REALTIME) { |
270 | - subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs; | |
339 | + let realtimeType = timewindow.realtime.realtimeType; | |
340 | + if (isUndefined(realtimeType)) { | |
341 | + if (isDefined(timewindow.realtime.quickInterval)) { | |
342 | + realtimeType = RealtimeWindowType.INTERVAL; | |
343 | + } else { | |
344 | + realtimeType = RealtimeWindowType.LAST_INTERVAL; | |
345 | + } | |
346 | + } | |
347 | + if (realtimeType === RealtimeWindowType.INTERVAL) { | |
348 | + subscriptionTimewindow.realtimeWindowMs = getSubscriptionRealtimeWindowFromTimeInterval(timewindow.realtime.quickInterval); | |
349 | + subscriptionTimewindow.quickInterval = timewindow.realtime.quickInterval; | |
350 | + } else { | |
351 | + subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs; | |
352 | + } | |
271 | 353 | subscriptionTimewindow.aggregation.interval = |
272 | 354 | timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval, |
273 | 355 | subscriptionTimewindow.aggregation.type); |
274 | 356 | subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs; |
275 | 357 | const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval; |
276 | 358 | aggTimewindow = subscriptionTimewindow.realtimeWindowMs; |
277 | - if (startDiff) { | |
359 | + if (startDiff && realtimeType !== RealtimeWindowType.INTERVAL) { | |
278 | 360 | subscriptionTimewindow.startTs -= startDiff; |
279 | 361 | aggTimewindow += subscriptionTimewindow.aggregation.interval; |
280 | 362 | } |
281 | 363 | } else { |
282 | 364 | let historyType = timewindow.history.historyType; |
283 | 365 | if (isUndefined(historyType)) { |
284 | - historyType = isDefined(timewindow.history.timewindowMs) ? HistoryWindowType.LAST_INTERVAL : HistoryWindowType.FIXED; | |
366 | + if (isDefined(timewindow.history.timewindowMs)) { | |
367 | + historyType = HistoryWindowType.LAST_INTERVAL; | |
368 | + } else if (isDefined(timewindow.history.quickInterval)) { | |
369 | + historyType = HistoryWindowType.INTERVAL; | |
370 | + } else { | |
371 | + historyType = HistoryWindowType.FIXED; | |
372 | + } | |
285 | 373 | } |
286 | 374 | if (historyType === HistoryWindowType.LAST_INTERVAL) { |
287 | 375 | const currentTime = Date.now(); |
... | ... | @@ -290,6 +378,13 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num |
290 | 378 | endTimeMs: currentTime |
291 | 379 | }; |
292 | 380 | aggTimewindow = timewindow.history.timewindowMs; |
381 | + } else if (historyType === HistoryWindowType.INTERVAL) { | |
382 | + const currentDate = moment(); | |
383 | + subscriptionTimewindow.fixedWindow = { | |
384 | + startTimeMs: calculateIntervalStartTime(timewindow.history.quickInterval, null, currentDate), | |
385 | + endTimeMs: calculateIntervalEndTime(timewindow.history.quickInterval, null, currentDate) | |
386 | + }; | |
387 | + aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; | |
293 | 388 | } else { |
294 | 389 | subscriptionTimewindow.fixedWindow = { |
295 | 390 | startTimeMs: timewindow.history.fixedTimewindow.startTimeMs, |
... | ... | @@ -309,6 +404,132 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num |
309 | 404 | return subscriptionTimewindow; |
310 | 405 | } |
311 | 406 | |
407 | +function getSubscriptionRealtimeWindowFromTimeInterval(interval: QuickTimeInterval): number { | |
408 | + const currentDate = moment(); | |
409 | + switch (interval) { | |
410 | + case QuickTimeInterval.CURRENT_HOUR: | |
411 | + return currentDate.diff(currentDate.clone().startOf('hour')) | |
412 | + case QuickTimeInterval.CURRENT_DAY: | |
413 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | |
414 | + return currentDate.diff(currentDate.clone().startOf('day')); | |
415 | + case QuickTimeInterval.CURRENT_WEEK: | |
416 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | |
417 | + return currentDate.diff(currentDate.clone().startOf('week')); | |
418 | + case QuickTimeInterval.CURRENT_MONTH: | |
419 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | |
420 | + return currentDate.diff(currentDate.clone().startOf('month')); | |
421 | + case QuickTimeInterval.CURRENT_YEAR: | |
422 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | |
423 | + return currentDate.diff(currentDate.clone().startOf('year')); | |
424 | + } | |
425 | +} | |
426 | + | |
427 | +export function calculateIntervalEndTime(interval: QuickTimeInterval, endTs = 0, nowDate?: moment_.Moment): number { | |
428 | + const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment(); | |
429 | + switch (interval) { | |
430 | + case QuickTimeInterval.YESTERDAY: | |
431 | + currentDate.subtract(1, 'days'); | |
432 | + return currentDate.endOf('day').valueOf(); | |
433 | + case QuickTimeInterval.DAY_BEFORE_YESTERDAY: | |
434 | + currentDate.subtract(2, 'days'); | |
435 | + return currentDate.endOf('day').valueOf(); | |
436 | + case QuickTimeInterval.THIS_DAY_LAST_WEEK: | |
437 | + currentDate.subtract(1, 'weeks'); | |
438 | + return currentDate.endOf('day').valueOf(); | |
439 | + case QuickTimeInterval.PREVIOUS_WEEK: | |
440 | + currentDate.subtract(1, 'weeks'); | |
441 | + return currentDate.endOf('week').valueOf(); | |
442 | + case QuickTimeInterval.PREVIOUS_MONTH: | |
443 | + currentDate.subtract(1, 'months'); | |
444 | + return currentDate.endOf('month').valueOf(); | |
445 | + case QuickTimeInterval.PREVIOUS_YEAR: | |
446 | + currentDate.subtract(1, 'years'); | |
447 | + return currentDate.endOf('year').valueOf(); | |
448 | + case QuickTimeInterval.CURRENT_HOUR: | |
449 | + return currentDate.endOf('hour').valueOf(); | |
450 | + case QuickTimeInterval.CURRENT_DAY: | |
451 | + return currentDate.endOf('day').valueOf(); | |
452 | + case QuickTimeInterval.CURRENT_WEEK: | |
453 | + return currentDate.endOf('week').valueOf(); | |
454 | + case QuickTimeInterval.CURRENT_MONTH: | |
455 | + return currentDate.endOf('month').valueOf(); | |
456 | + case QuickTimeInterval.CURRENT_YEAR: | |
457 | + return currentDate.endOf('year').valueOf(); | |
458 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | |
459 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | |
460 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | |
461 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | |
462 | + return currentDate.valueOf(); | |
463 | + default: | |
464 | + return endTs; | |
465 | + } | |
466 | +} | |
467 | + | |
468 | +export function calculateIntervalStartTime(interval: QuickTimeInterval, startTS = 0, nowDate?: moment_.Moment): number { | |
469 | + const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment(); | |
470 | + switch (interval) { | |
471 | + case QuickTimeInterval.YESTERDAY: | |
472 | + currentDate.subtract(1, 'days'); | |
473 | + return currentDate.startOf('day').valueOf(); | |
474 | + case QuickTimeInterval.DAY_BEFORE_YESTERDAY: | |
475 | + currentDate.subtract(2, 'days'); | |
476 | + return currentDate.startOf('day').valueOf(); | |
477 | + case QuickTimeInterval.THIS_DAY_LAST_WEEK: | |
478 | + currentDate.subtract(1, 'weeks'); | |
479 | + return currentDate.startOf('day').valueOf(); | |
480 | + case QuickTimeInterval.PREVIOUS_WEEK: | |
481 | + currentDate.subtract(1, 'weeks'); | |
482 | + return currentDate.startOf('week').valueOf(); | |
483 | + case QuickTimeInterval.PREVIOUS_MONTH: | |
484 | + currentDate.subtract(1, 'months'); | |
485 | + return currentDate.startOf('month').valueOf(); | |
486 | + case QuickTimeInterval.PREVIOUS_YEAR: | |
487 | + currentDate.subtract(1, 'years'); | |
488 | + return currentDate.startOf('year').valueOf(); | |
489 | + case QuickTimeInterval.CURRENT_HOUR: | |
490 | + return currentDate.startOf('hour').valueOf(); | |
491 | + case QuickTimeInterval.CURRENT_DAY: | |
492 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | |
493 | + return currentDate.startOf('day').valueOf(); | |
494 | + case QuickTimeInterval.CURRENT_WEEK: | |
495 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | |
496 | + return currentDate.startOf('week').valueOf(); | |
497 | + case QuickTimeInterval.CURRENT_MONTH: | |
498 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | |
499 | + return currentDate.startOf('month').valueOf(); | |
500 | + case QuickTimeInterval.CURRENT_YEAR: | |
501 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | |
502 | + return currentDate.startOf('year').valueOf(); | |
503 | + default: | |
504 | + return startTS; | |
505 | + } | |
506 | +} | |
507 | + | |
508 | +export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number { | |
509 | + switch (interval) { | |
510 | + case QuickTimeInterval.CURRENT_HOUR: | |
511 | + return HOUR; | |
512 | + case QuickTimeInterval.YESTERDAY: | |
513 | + case QuickTimeInterval.DAY_BEFORE_YESTERDAY: | |
514 | + case QuickTimeInterval.THIS_DAY_LAST_WEEK: | |
515 | + case QuickTimeInterval.CURRENT_DAY: | |
516 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | |
517 | + return DAY; | |
518 | + case QuickTimeInterval.PREVIOUS_WEEK: | |
519 | + case QuickTimeInterval.CURRENT_WEEK: | |
520 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | |
521 | + return WEEK; | |
522 | + case QuickTimeInterval.PREVIOUS_MONTH: | |
523 | + case QuickTimeInterval.CURRENT_MONTH: | |
524 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | |
525 | + return DAY * 30; | |
526 | + case QuickTimeInterval.PREVIOUS_YEAR: | |
527 | + case QuickTimeInterval.CURRENT_YEAR: | |
528 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | |
529 | + return YEAR; | |
530 | + } | |
531 | +} | |
532 | + | |
312 | 533 | export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, |
313 | 534 | timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow { |
314 | 535 | const timewindowForComparison: SubscriptionTimewindow = { |
... | ... | @@ -358,6 +579,8 @@ export function cloneSelectedHistoryTimewindow(historyWindow: HistoryWindow): Hi |
358 | 579 | cloned.interval = historyWindow.interval; |
359 | 580 | if (historyWindow.historyType === HistoryWindowType.LAST_INTERVAL) { |
360 | 581 | cloned.timewindowMs = historyWindow.timewindowMs; |
582 | + } else if (historyWindow.historyType === HistoryWindowType.INTERVAL) { | |
583 | + cloned.quickInterval = historyWindow.quickInterval; | |
361 | 584 | } else if (historyWindow.historyType === HistoryWindowType.FIXED) { |
362 | 585 | cloned.fixedTimewindow = deepClone(historyWindow.fixedTimewindow); |
363 | 586 | } |
... | ... | @@ -375,7 +598,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( |
375 | 598 | { |
376 | 599 | name: 'timeinterval.seconds-interval', |
377 | 600 | translateParams: {seconds: 1}, |
378 | - value: 1 * SECOND | |
601 | + value: SECOND | |
379 | 602 | }, |
380 | 603 | { |
381 | 604 | name: 'timeinterval.seconds-interval', |
... | ... | @@ -400,7 +623,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( |
400 | 623 | { |
401 | 624 | name: 'timeinterval.minutes-interval', |
402 | 625 | translateParams: {minutes: 1}, |
403 | - value: 1 * MINUTE | |
626 | + value: MINUTE | |
404 | 627 | }, |
405 | 628 | { |
406 | 629 | name: 'timeinterval.minutes-interval', |
... | ... | @@ -430,7 +653,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( |
430 | 653 | { |
431 | 654 | name: 'timeinterval.hours-interval', |
432 | 655 | translateParams: {hours: 1}, |
433 | - value: 1 * HOUR | |
656 | + value: HOUR | |
434 | 657 | }, |
435 | 658 | { |
436 | 659 | name: 'timeinterval.hours-interval', |
... | ... | @@ -455,7 +678,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( |
455 | 678 | { |
456 | 679 | name: 'timeinterval.days-interval', |
457 | 680 | translateParams: {days: 1}, |
458 | - value: 1 * DAY | |
681 | + value: DAY | |
459 | 682 | }, |
460 | 683 | { |
461 | 684 | name: 'timeinterval.days-interval', | ... | ... |
... | ... | @@ -140,6 +140,7 @@ import { TimezoneSelectComponent } from '@shared/components/time/timezone-select |
140 | 140 | import { FileSizePipe } from '@shared/pipe/file-size.pipe'; |
141 | 141 | import { WidgetsBundleSearchComponent } from '@shared/components/widgets-bundle-search.component'; |
142 | 142 | import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; |
143 | +import { QuickTimeIntervalComponent } from '@shared/components/time/quick-time-interval.component'; | |
143 | 144 | |
144 | 145 | @NgModule({ |
145 | 146 | providers: [ |
... | ... | @@ -175,6 +176,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; |
175 | 176 | TimewindowComponent, |
176 | 177 | TimewindowPanelComponent, |
177 | 178 | TimeintervalComponent, |
179 | + QuickTimeIntervalComponent, | |
178 | 180 | DashboardSelectComponent, |
179 | 181 | DashboardSelectPanelComponent, |
180 | 182 | DatetimePeriodComponent, |
... | ... | @@ -302,6 +304,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; |
302 | 304 | TimewindowComponent, |
303 | 305 | TimewindowPanelComponent, |
304 | 306 | TimeintervalComponent, |
307 | + QuickTimeIntervalComponent, | |
305 | 308 | DashboardSelectComponent, |
306 | 309 | DatetimePeriodComponent, |
307 | 310 | DatetimeComponent, | ... | ... |
... | ... | @@ -2118,7 +2118,24 @@ |
2118 | 2118 | "hours": "Hours", |
2119 | 2119 | "minutes": "Minutes", |
2120 | 2120 | "seconds": "Seconds", |
2121 | - "advanced": "Advanced" | |
2121 | + "advanced": "Advanced", | |
2122 | + "predefined": { | |
2123 | + "yesterday": "Yesterday", | |
2124 | + "day-before-yesterday": "Day before yesterday", | |
2125 | + "this-day-last-week": "This day last week", | |
2126 | + "previous-week": "Previous week", | |
2127 | + "previous-month": "Previous month", | |
2128 | + "previous-year": "Previous year", | |
2129 | + "current-hour": "Current hour", | |
2130 | + "current-day": "Current day", | |
2131 | + "current-day-so-far": "Current day so far", | |
2132 | + "current-week": "Current week", | |
2133 | + "current-week-so-far": "Current week so far", | |
2134 | + "current-month": "Current month", | |
2135 | + "current-month-so-far": "Current month so far", | |
2136 | + "current-year": "Current year", | |
2137 | + "current-year-so-far": "Current year so far" | |
2138 | + } | |
2122 | 2139 | }, |
2123 | 2140 | "timeunit": { |
2124 | 2141 | "seconds": "Seconds", |
... | ... | @@ -2139,7 +2156,8 @@ |
2139 | 2156 | "date-range": "Date range", |
2140 | 2157 | "last": "Last", |
2141 | 2158 | "time-period": "Time period", |
2142 | - "hide": "Hide" | |
2159 | + "hide": "Hide", | |
2160 | + "interval": "Interval" | |
2143 | 2161 | }, |
2144 | 2162 | "user": { |
2145 | 2163 | "user": "User", | ... | ... |