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,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; |
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,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"> |
@@ -65,6 +92,17 @@ | @@ -65,6 +92,17 @@ | ||
65 | style="padding-top: 8px;"></tb-datetime-period> | 92 | style="padding-top: 8px;"></tb-datetime-period> |
66 | </section> | 93 | </section> |
67 | </mat-radio-button> | 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 | </mat-radio-group> | 106 | </mat-radio-group> |
69 | </div> | 107 | </div> |
70 | </section> | 108 | </section> |
@@ -20,6 +20,8 @@ import { | @@ -20,6 +20,8 @@ import { | ||
20 | AggregationType, | 20 | AggregationType, |
21 | DAY, | 21 | DAY, |
22 | HistoryWindowType, | 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( |
@@ -119,6 +133,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | @@ -119,6 +133,11 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | ||
119 | value: this.timewindow.history && typeof this.timewindow.history.fixedTimewindow !== 'undefined' | 133 | value: this.timewindow.history && typeof this.timewindow.history.fixedTimewindow !== 'undefined' |
120 | ? this.timewindow.history.fixedTimewindow : null, | 134 | ? this.timewindow.history.fixedTimewindow : null, |
121 | disabled: hideInterval | 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,14 +161,17 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | ||
142 | update() { | 161 | update() { |
143 | const timewindowFormValue = this.timewindowForm.getRawValue(); | 162 | const timewindowFormValue = this.timewindowForm.getRawValue(); |
144 | this.timewindow.realtime = { | 163 | this.timewindow.realtime = { |
164 | + realtimeType: timewindowFormValue.realtime.realtimeType, | ||
145 | timewindowMs: timewindowFormValue.realtime.timewindowMs, | 165 | timewindowMs: timewindowFormValue.realtime.timewindowMs, |
166 | + quickInterval: timewindowFormValue.realtime.quickInterval, | ||
146 | interval: timewindowFormValue.realtime.interval | 167 | interval: timewindowFormValue.realtime.interval |
147 | }; | 168 | }; |
148 | this.timewindow.history = { | 169 | this.timewindow.history = { |
149 | historyType: timewindowFormValue.history.historyType, | 170 | historyType: timewindowFormValue.history.historyType, |
150 | timewindowMs: timewindowFormValue.history.timewindowMs, | 171 | timewindowMs: timewindowFormValue.history.timewindowMs, |
151 | interval: timewindowFormValue.history.interval, | 172 | interval: timewindowFormValue.history.interval, |
152 | - fixedTimewindow: timewindowFormValue.history.fixedTimewindow | 173 | + fixedTimewindow: timewindowFormValue.history.fixedTimewindow, |
174 | + quickInterval: timewindowFormValue.history.quickInterval | ||
153 | }; | 175 | }; |
154 | if (this.aggregation) { | 176 | if (this.aggregation) { |
155 | this.timewindow.aggregation = { | 177 | this.timewindow.aggregation = { |
@@ -174,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | @@ -174,11 +196,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | ||
174 | } | 196 | } |
175 | 197 | ||
176 | minRealtimeAggInterval() { | 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 | maxRealtimeAggInterval() { | 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 | minHistoryAggInterval() { | 218 | minHistoryAggInterval() { |
@@ -193,6 +227,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | @@ -193,6 +227,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | ||
193 | const timewindowFormValue = this.timewindowForm.getRawValue(); | 227 | const timewindowFormValue = this.timewindowForm.getRawValue(); |
194 | if (timewindowFormValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { | 228 | if (timewindowFormValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
195 | return timewindowFormValue.history.timewindowMs; | 229 | return timewindowFormValue.history.timewindowMs; |
230 | + } else if (timewindowFormValue.history.historyType === HistoryWindowType.INTERVAL) { | ||
231 | + return quickTimeIntervalPeriod(timewindowFormValue.history.quickInterval); | ||
196 | } else if (timewindowFormValue.history.fixedTimewindow) { | 232 | } else if (timewindowFormValue.history.fixedTimewindow) { |
197 | return timewindowFormValue.history.fixedTimewindow.endTimeMs - | 233 | return timewindowFormValue.history.fixedTimewindow.endTimeMs - |
198 | timewindowFormValue.history.fixedTimewindow.startTimeMs; | 234 | timewindowFormValue.history.fixedTimewindow.startTimeMs; |
@@ -206,10 +242,18 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | @@ -206,10 +242,18 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { | ||
206 | this.timewindowForm.get('history.historyType').disable({emitEvent: false}); | 242 | this.timewindowForm.get('history.historyType').disable({emitEvent: false}); |
207 | this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false}); | 243 | this.timewindowForm.get('history.timewindowMs').disable({emitEvent: false}); |
208 | this.timewindowForm.get('history.fixedTimewindow').disable({emitEvent: false}); | 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 | } else { | 249 | } else { |
210 | this.timewindowForm.get('history.historyType').enable({emitEvent: false}); | 250 | this.timewindowForm.get('history.historyType').enable({emitEvent: false}); |
211 | this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false}); | 251 | this.timewindowForm.get('history.timewindowMs').enable({emitEvent: false}); |
212 | this.timewindowForm.get('history.fixedTimewindow').enable({emitEvent: false}); | 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 | this.timewindowForm.markAsDirty(); | 258 | this.timewindowForm.markAsDirty(); |
215 | } | 259 | } |
@@ -33,6 +33,8 @@ import { | @@ -33,6 +33,8 @@ import { | ||
33 | cloneSelectedTimewindow, | 33 | cloneSelectedTimewindow, |
34 | HistoryWindowType, | 34 | HistoryWindowType, |
35 | initModelFromDefaultTimewindow, | 35 | initModelFromDefaultTimewindow, |
36 | + QuickTimeIntervalTranslationMap, | ||
37 | + RealtimeWindowType, | ||
36 | Timewindow, | 38 | Timewindow, |
37 | TimewindowType | 39 | TimewindowType |
38 | } from '@shared/models/time/time.models'; | 40 | } from '@shared/models/time/time.models'; |
@@ -272,14 +274,20 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces | @@ -272,14 +274,20 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces | ||
272 | 274 | ||
273 | updateDisplayValue() { | 275 | updateDisplayValue() { |
274 | if (this.innerValue.selectedTab === TimewindowType.REALTIME && !this.historyOnly) { | 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 | } else { | 284 | } else { |
279 | this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : ''; | 285 | this.innerValue.displayValue = !this.historyOnly ? (this.translate.instant('timewindow.history') + ' - ') : ''; |
280 | if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { | 286 | if (this.innerValue.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
281 | this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' + | 287 | this.innerValue.displayValue += this.translate.instant('timewindow.last-prefix') + ' ' + |
282 | this.millisecondsToTimeStringPipe.transform(this.innerValue.history.timewindowMs); | 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 | } else { | 291 | } else { |
284 | const startString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.startTimeMs, 'yyyy-MM-dd HH:mm:ss'); | 292 | const startString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.startTimeMs, 'yyyy-MM-dd HH:mm:ss'); |
285 | const endString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.endTimeMs, 'yyyy-MM-dd HH:mm:ss'); | 293 | const endString = this.datePipe.transform(this.innerValue.history.fixedTimewindow.endTimeMs, 'yyyy-MM-dd HH:mm:ss'); |
@@ -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'; |
@@ -27,6 +27,7 @@ export const SECOND = 1000; | @@ -27,6 +27,7 @@ export const SECOND = 1000; | ||
27 | export const MINUTE = 60 * SECOND; | 27 | export const MINUTE = 60 * SECOND; |
28 | export const HOUR = 60 * MINUTE; | 28 | export const HOUR = 60 * MINUTE; |
29 | export const DAY = 24 * HOUR; | 29 | export const DAY = 24 * HOUR; |
30 | +export const WEEK = 7 * DAY; | ||
30 | export const YEAR = DAY * 365; | 31 | export const YEAR = DAY * 365; |
31 | 32 | ||
32 | export enum TimewindowType { | 33 | export enum TimewindowType { |
@@ -34,14 +35,25 @@ export enum TimewindowType { | @@ -34,14 +35,25 @@ export enum TimewindowType { | ||
34 | HISTORY | 35 | HISTORY |
35 | } | 36 | } |
36 | 37 | ||
38 | +export enum RealtimeWindowType { | ||
39 | + LAST_INTERVAL, | ||
40 | + INTERVAL | ||
41 | +} | ||
42 | + | ||
37 | export enum HistoryWindowType { | 43 | export enum HistoryWindowType { |
38 | LAST_INTERVAL, | 44 | LAST_INTERVAL, |
39 | - FIXED | 45 | + FIXED, |
46 | + INTERVAL | ||
40 | } | 47 | } |
41 | 48 | ||
42 | export interface IntervalWindow { | 49 | export interface IntervalWindow { |
43 | interval?: number; | 50 | interval?: number; |
44 | timewindowMs?: number; | 51 | timewindowMs?: number; |
52 | + quickInterval?: QuickTimeInterval; | ||
53 | +} | ||
54 | + | ||
55 | +export interface RealtimeWindow extends IntervalWindow{ | ||
56 | + realtimeType?: RealtimeWindowType; | ||
45 | } | 57 | } |
46 | 58 | ||
47 | export interface FixedWindow { | 59 | export interface FixedWindow { |
@@ -86,7 +98,7 @@ export interface Timewindow { | @@ -86,7 +98,7 @@ export interface Timewindow { | ||
86 | hideAggregation?: boolean; | 98 | hideAggregation?: boolean; |
87 | hideAggInterval?: boolean; | 99 | hideAggInterval?: boolean; |
88 | selectedTab?: TimewindowType; | 100 | selectedTab?: TimewindowType; |
89 | - realtime?: IntervalWindow; | 101 | + realtime?: RealtimeWindow; |
90 | history?: HistoryWindow; | 102 | history?: HistoryWindow; |
91 | aggregation?: Aggregation; | 103 | aggregation?: Aggregation; |
92 | } | 104 | } |
@@ -99,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation { | @@ -99,6 +111,7 @@ export interface SubscriptionAggregation extends Aggregation { | ||
99 | 111 | ||
100 | export interface SubscriptionTimewindow { | 112 | export interface SubscriptionTimewindow { |
101 | startTs?: number; | 113 | startTs?: number; |
114 | + quickInterval?: QuickTimeInterval; | ||
102 | realtimeWindowMs?: number; | 115 | realtimeWindowMs?: number; |
103 | fixedWindow?: FixedWindow; | 116 | fixedWindow?: FixedWindow; |
104 | aggregation?: SubscriptionAggregation; | 117 | aggregation?: SubscriptionAggregation; |
@@ -111,6 +124,42 @@ export interface WidgetTimewindow { | @@ -111,6 +124,42 @@ export interface WidgetTimewindow { | ||
111 | stDiff?: number; | 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 | export function historyInterval(timewindowMs: number): Timewindow { | 163 | export function historyInterval(timewindowMs: number): Timewindow { |
115 | const timewindow: Timewindow = { | 164 | const timewindow: Timewindow = { |
116 | selectedTab: TimewindowType.HISTORY, | 165 | selectedTab: TimewindowType.HISTORY, |
@@ -131,8 +180,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { | @@ -131,8 +180,10 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { | ||
131 | hideAggInterval: false, | 180 | hideAggInterval: false, |
132 | selectedTab: TimewindowType.REALTIME, | 181 | selectedTab: TimewindowType.REALTIME, |
133 | realtime: { | 182 | realtime: { |
183 | + realtimeType: RealtimeWindowType.LAST_INTERVAL, | ||
134 | interval: SECOND, | 184 | interval: SECOND, |
135 | - timewindowMs: MINUTE | 185 | + timewindowMs: MINUTE, |
186 | + quickInterval: QuickTimeInterval.CURRENT_DAY | ||
136 | }, | 187 | }, |
137 | history: { | 188 | history: { |
138 | historyType: HistoryWindowType.LAST_INTERVAL, | 189 | historyType: HistoryWindowType.LAST_INTERVAL, |
@@ -141,7 +192,8 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { | @@ -141,7 +192,8 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { | ||
141 | fixedTimewindow: { | 192 | fixedTimewindow: { |
142 | startTimeMs: currentTime - DAY, | 193 | startTimeMs: currentTime - DAY, |
143 | endTimeMs: currentTime | 194 | endTimeMs: currentTime |
144 | - } | 195 | + }, |
196 | + quickInterval: QuickTimeInterval.CURRENT_DAY | ||
145 | }, | 197 | }, |
146 | aggregation: { | 198 | aggregation: { |
147 | type: AggregationType.AVG, | 199 | type: AggregationType.AVG, |
@@ -170,7 +222,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | @@ -170,7 +222,20 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | ||
170 | if (isDefined(value.realtime.interval)) { | 222 | if (isDefined(value.realtime.interval)) { |
171 | model.realtime.interval = value.realtime.interval; | 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 | } else { | 239 | } else { |
175 | if (isDefined(value.history.interval)) { | 240 | if (isDefined(value.history.interval)) { |
176 | model.history.interval = value.history.interval; | 241 | model.history.interval = value.history.interval; |
@@ -178,6 +243,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | @@ -178,6 +243,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | ||
178 | if (isUndefined(value.history.historyType)) { | 243 | if (isUndefined(value.history.historyType)) { |
179 | if (isDefined(value.history.timewindowMs)) { | 244 | if (isDefined(value.history.timewindowMs)) { |
180 | model.history.historyType = HistoryWindowType.LAST_INTERVAL; | 245 | model.history.historyType = HistoryWindowType.LAST_INTERVAL; |
246 | + } else if (isDefined(value.history.quickInterval)) { | ||
247 | + model.history.historyType = HistoryWindowType.INTERVAL; | ||
181 | } else { | 248 | } else { |
182 | model.history.historyType = HistoryWindowType.FIXED; | 249 | model.history.historyType = HistoryWindowType.FIXED; |
183 | } | 250 | } |
@@ -186,6 +253,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | @@ -186,6 +253,8 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T | ||
186 | } | 253 | } |
187 | if (model.history.historyType === HistoryWindowType.LAST_INTERVAL) { | 254 | if (model.history.historyType === HistoryWindowType.LAST_INTERVAL) { |
188 | model.history.timewindowMs = value.history.timewindowMs; | 255 | model.history.timewindowMs = value.history.timewindowMs; |
256 | + } else if (model.history.historyType === HistoryWindowType.INTERVAL) { | ||
257 | + model.history.quickInterval = value.history.quickInterval; | ||
189 | } else { | 258 | } else { |
190 | model.history.fixedTimewindow.startTimeMs = value.history.fixedTimewindow.startTimeMs; | 259 | model.history.fixedTimewindow.startTimeMs = value.history.fixedTimewindow.startTimeMs; |
191 | model.history.fixedTimewindow.endTimeMs = value.history.fixedTimewindow.endTimeMs; | 260 | model.history.fixedTimewindow.endTimeMs = value.history.fixedTimewindow.endTimeMs; |
@@ -267,21 +336,40 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | @@ -267,21 +336,40 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | ||
267 | selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY; | 336 | selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY; |
268 | } | 337 | } |
269 | if (selectedTab === TimewindowType.REALTIME) { | 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 | subscriptionTimewindow.aggregation.interval = | 353 | subscriptionTimewindow.aggregation.interval = |
272 | timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval, | 354 | timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval, |
273 | subscriptionTimewindow.aggregation.type); | 355 | subscriptionTimewindow.aggregation.type); |
274 | subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs; | 356 | subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs; |
275 | const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval; | 357 | const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval; |
276 | aggTimewindow = subscriptionTimewindow.realtimeWindowMs; | 358 | aggTimewindow = subscriptionTimewindow.realtimeWindowMs; |
277 | - if (startDiff) { | 359 | + if (startDiff && realtimeType !== RealtimeWindowType.INTERVAL) { |
278 | subscriptionTimewindow.startTs -= startDiff; | 360 | subscriptionTimewindow.startTs -= startDiff; |
279 | aggTimewindow += subscriptionTimewindow.aggregation.interval; | 361 | aggTimewindow += subscriptionTimewindow.aggregation.interval; |
280 | } | 362 | } |
281 | } else { | 363 | } else { |
282 | let historyType = timewindow.history.historyType; | 364 | let historyType = timewindow.history.historyType; |
283 | if (isUndefined(historyType)) { | 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 | if (historyType === HistoryWindowType.LAST_INTERVAL) { | 374 | if (historyType === HistoryWindowType.LAST_INTERVAL) { |
287 | const currentTime = Date.now(); | 375 | const currentTime = Date.now(); |
@@ -290,6 +378,13 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | @@ -290,6 +378,13 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | ||
290 | endTimeMs: currentTime | 378 | endTimeMs: currentTime |
291 | }; | 379 | }; |
292 | aggTimewindow = timewindow.history.timewindowMs; | 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 | } else { | 388 | } else { |
294 | subscriptionTimewindow.fixedWindow = { | 389 | subscriptionTimewindow.fixedWindow = { |
295 | startTimeMs: timewindow.history.fixedTimewindow.startTimeMs, | 390 | startTimeMs: timewindow.history.fixedTimewindow.startTimeMs, |
@@ -309,6 +404,132 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | @@ -309,6 +404,132 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num | ||
309 | return subscriptionTimewindow; | 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 | export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, | 533 | export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, |
313 | timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow { | 534 | timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow { |
314 | const timewindowForComparison: SubscriptionTimewindow = { | 535 | const timewindowForComparison: SubscriptionTimewindow = { |
@@ -358,6 +579,8 @@ export function cloneSelectedHistoryTimewindow(historyWindow: HistoryWindow): Hi | @@ -358,6 +579,8 @@ export function cloneSelectedHistoryTimewindow(historyWindow: HistoryWindow): Hi | ||
358 | cloned.interval = historyWindow.interval; | 579 | cloned.interval = historyWindow.interval; |
359 | if (historyWindow.historyType === HistoryWindowType.LAST_INTERVAL) { | 580 | if (historyWindow.historyType === HistoryWindowType.LAST_INTERVAL) { |
360 | cloned.timewindowMs = historyWindow.timewindowMs; | 581 | cloned.timewindowMs = historyWindow.timewindowMs; |
582 | + } else if (historyWindow.historyType === HistoryWindowType.INTERVAL) { | ||
583 | + cloned.quickInterval = historyWindow.quickInterval; | ||
361 | } else if (historyWindow.historyType === HistoryWindowType.FIXED) { | 584 | } else if (historyWindow.historyType === HistoryWindowType.FIXED) { |
362 | cloned.fixedTimewindow = deepClone(historyWindow.fixedTimewindow); | 585 | cloned.fixedTimewindow = deepClone(historyWindow.fixedTimewindow); |
363 | } | 586 | } |
@@ -375,7 +598,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | @@ -375,7 +598,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | ||
375 | { | 598 | { |
376 | name: 'timeinterval.seconds-interval', | 599 | name: 'timeinterval.seconds-interval', |
377 | translateParams: {seconds: 1}, | 600 | translateParams: {seconds: 1}, |
378 | - value: 1 * SECOND | 601 | + value: SECOND |
379 | }, | 602 | }, |
380 | { | 603 | { |
381 | name: 'timeinterval.seconds-interval', | 604 | name: 'timeinterval.seconds-interval', |
@@ -400,7 +623,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | @@ -400,7 +623,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | ||
400 | { | 623 | { |
401 | name: 'timeinterval.minutes-interval', | 624 | name: 'timeinterval.minutes-interval', |
402 | translateParams: {minutes: 1}, | 625 | translateParams: {minutes: 1}, |
403 | - value: 1 * MINUTE | 626 | + value: MINUTE |
404 | }, | 627 | }, |
405 | { | 628 | { |
406 | name: 'timeinterval.minutes-interval', | 629 | name: 'timeinterval.minutes-interval', |
@@ -430,7 +653,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | @@ -430,7 +653,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | ||
430 | { | 653 | { |
431 | name: 'timeinterval.hours-interval', | 654 | name: 'timeinterval.hours-interval', |
432 | translateParams: {hours: 1}, | 655 | translateParams: {hours: 1}, |
433 | - value: 1 * HOUR | 656 | + value: HOUR |
434 | }, | 657 | }, |
435 | { | 658 | { |
436 | name: 'timeinterval.hours-interval', | 659 | name: 'timeinterval.hours-interval', |
@@ -455,7 +678,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | @@ -455,7 +678,7 @@ export const defaultTimeIntervals = new Array<TimeInterval>( | ||
455 | { | 678 | { |
456 | name: 'timeinterval.days-interval', | 679 | name: 'timeinterval.days-interval', |
457 | translateParams: {days: 1}, | 680 | translateParams: {days: 1}, |
458 | - value: 1 * DAY | 681 | + value: DAY |
459 | }, | 682 | }, |
460 | { | 683 | { |
461 | name: 'timeinterval.days-interval', | 684 | name: 'timeinterval.days-interval', |
@@ -140,6 +140,7 @@ import { TimezoneSelectComponent } from '@shared/components/time/timezone-select | @@ -140,6 +140,7 @@ import { TimezoneSelectComponent } from '@shared/components/time/timezone-select | ||
140 | import { FileSizePipe } from '@shared/pipe/file-size.pipe'; | 140 | import { FileSizePipe } from '@shared/pipe/file-size.pipe'; |
141 | import { WidgetsBundleSearchComponent } from '@shared/components/widgets-bundle-search.component'; | 141 | import { WidgetsBundleSearchComponent } from '@shared/components/widgets-bundle-search.component'; |
142 | import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; | 142 | import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; |
143 | +import { QuickTimeIntervalComponent } from '@shared/components/time/quick-time-interval.component'; | ||
143 | 144 | ||
144 | @NgModule({ | 145 | @NgModule({ |
145 | providers: [ | 146 | providers: [ |
@@ -175,6 +176,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; | @@ -175,6 +176,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; | ||
175 | TimewindowComponent, | 176 | TimewindowComponent, |
176 | TimewindowPanelComponent, | 177 | TimewindowPanelComponent, |
177 | TimeintervalComponent, | 178 | TimeintervalComponent, |
179 | + QuickTimeIntervalComponent, | ||
178 | DashboardSelectComponent, | 180 | DashboardSelectComponent, |
179 | DashboardSelectPanelComponent, | 181 | DashboardSelectPanelComponent, |
180 | DatetimePeriodComponent, | 182 | DatetimePeriodComponent, |
@@ -302,6 +304,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; | @@ -302,6 +304,7 @@ import { SelectableColumnsPipe } from '@shared/pipe/selectable-columns.pipe'; | ||
302 | TimewindowComponent, | 304 | TimewindowComponent, |
303 | TimewindowPanelComponent, | 305 | TimewindowPanelComponent, |
304 | TimeintervalComponent, | 306 | TimeintervalComponent, |
307 | + QuickTimeIntervalComponent, | ||
305 | DashboardSelectComponent, | 308 | DashboardSelectComponent, |
306 | DatetimePeriodComponent, | 309 | DatetimePeriodComponent, |
307 | DatetimeComponent, | 310 | DatetimeComponent, |
@@ -2118,7 +2118,24 @@ | @@ -2118,7 +2118,24 @@ | ||
2118 | "hours": "Hours", | 2118 | "hours": "Hours", |
2119 | "minutes": "Minutes", | 2119 | "minutes": "Minutes", |
2120 | "seconds": "Seconds", | 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 | "timeunit": { | 2140 | "timeunit": { |
2124 | "seconds": "Seconds", | 2141 | "seconds": "Seconds", |
@@ -2139,7 +2156,8 @@ | @@ -2139,7 +2156,8 @@ | ||
2139 | "date-range": "Date range", | 2156 | "date-range": "Date range", |
2140 | "last": "Last", | 2157 | "last": "Last", |
2141 | "time-period": "Time period", | 2158 | "time-period": "Time period", |
2142 | - "hide": "Hide" | 2159 | + "hide": "Hide", |
2160 | + "interval": "Interval" | ||
2143 | }, | 2161 | }, |
2144 | "user": { | 2162 | "user": { |
2145 | "user": "User", | 2163 | "user": "User", |