Browse Source

Add timezone support for timewindow

pull/4259/head
Igor Kulikov 6 years ago
parent
commit
3ed49e3f02
  1. 79
      ui-ngx/src/app/core/api/data-aggregator.ts
  2. 39
      ui-ngx/src/app/core/api/entity-data-subscription.ts
  3. 30
      ui-ngx/src/app/core/api/widget-subscription.ts
  4. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html
  5. 1
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html
  6. 12
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  7. 9
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts
  8. 14
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.html
  9. 26
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts
  10. 14
      ui-ngx/src/app/shared/components/time/timewindow.component.ts
  11. 57
      ui-ngx/src/app/shared/components/time/timezone-select.component.ts
  12. 41
      ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts
  13. 250
      ui-ngx/src/app/shared/models/time/time.models.ts

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

@ -18,8 +18,8 @@ import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/tel
import {
AggregationType,
calculateIntervalEndTime,
calculateIntervalStartTime,
QuickTimeInterval
calculateIntervalStartTime, getCurrentTime,
QuickTimeInterval, SubscriptionTimewindow
} from '@shared/models/time/time.models';
import { UtilsService } from '@core/services/utils.service';
import { deepClone } from '@core/utils';
@ -78,34 +78,29 @@ export class DataAggregator {
private resetPending = false;
private updatedData = false;
private noAggregation = this.aggregationType === AggregationType.NONE;
private aggregationTimeout = Math.max(this.interval, 1000);
private noAggregation = this.subsTw.aggregation.type === AggregationType.NONE;
private aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000);
private readonly aggFunction: AggFunction;
private intervalTimeoutHandle: Timeout;
private intervalScheduledTime: number;
private startTs = this.subsTw.startTs + this.subsTw.tsOffset;
private endTs: number;
private elapsed: number;
constructor(private onDataCb: onAggregatedData,
private tsKeyNames: string[],
private startTs: number,
private limit: number,
private aggregationType: AggregationType,
private timeWindow: number,
private interval: number,
private stateData: boolean,
private subsTw: SubscriptionTimewindow,
private utils: UtilsService,
private ignoreDataUpdateOnIntervalTick: boolean,
private quickInterval: QuickTimeInterval) {
private ignoreDataUpdateOnIntervalTick: boolean) {
this.tsKeyNames.forEach((key) => {
this.dataBuffer[key] = [];
});
if (this.stateData) {
if (this.subsTw.aggregation.stateData) {
this.lastPrevKvPairData = {};
}
switch (this.aggregationType) {
switch (this.subsTw.aggregation.type) {
case AggregationType.MIN:
this.aggFunction = min;
break;
@ -135,19 +130,21 @@ export class DataAggregator {
return prevOnDataCb;
}
public reset(startTs: number, timeWindow: number, interval: number) {
public reset(subsTw: SubscriptionTimewindow) {
if (this.intervalTimeoutHandle) {
clearTimeout(this.intervalTimeoutHandle);
this.intervalTimeoutHandle = null;
}
this.subsTw = subsTw;
this.intervalScheduledTime = this.utils.currentPerfTime();
this.startTs = startTs;
this.timeWindow = timeWindow;
this.interval = interval;
const endTs = this.startTs + this.timeWindow;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
this.startTs = this.subsTw.startTs + this.subsTw.tsOffset;
if (this.subsTw.quickInterval) {
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset;
} else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
}
this.elapsed = 0;
this.aggregationTimeout = Math.max(this.interval, 1000);
this.aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000);
this.resetPending = true;
this.updatedData = false;
this.intervalTimeoutHandle = setTimeout(this.onInterval.bind(this), this.aggregationTimeout);
@ -168,8 +165,11 @@ export class DataAggregator {
if (!this.dataReceived) {
this.elapsed = 0;
this.dataReceived = true;
const endTs = this.startTs + this.timeWindow;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
if (this.subsTw.quickInterval) {
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset;
} else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
}
}
if (this.resetPending) {
this.resetPending = false;
@ -203,15 +203,19 @@ export class DataAggregator {
this.intervalTimeoutHandle = null;
}
if (!history) {
const delta = Math.floor(this.elapsed / this.interval);
const delta = Math.floor(this.elapsed / this.subsTw.aggregation.interval);
if (delta || !this.data) {
const tickTs = delta * this.interval;
const startTS = this.startTs + tickTs;
this.startTs = calculateIntervalStartTime(this.quickInterval, startTS);
const endTs = this.endTs + tickTs;
this.endTs = calculateIntervalEndTime(this.quickInterval, endTs);
const tickTs = delta * this.subsTw.aggregation.interval;
if (this.subsTw.quickInterval) {
const currentDate = getCurrentTime(this.subsTw.timezone);
this.startTs = calculateIntervalStartTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
} else {
this.startTs += tickTs;
this.endTs += tickTs;
}
this.data = this.updateData();
this.elapsed = this.elapsed - delta * this.interval;
this.elapsed = this.elapsed - delta * this.subsTw.aggregation.interval;
}
} else {
this.data = this.updateData();
@ -234,7 +238,7 @@ export class DataAggregator {
let keyData = this.dataBuffer[key];
aggKeyData.forEach((aggData, aggTimestamp) => {
if (aggTimestamp <= this.startTs) {
if (this.stateData &&
if (this.subsTw.aggregation.stateData &&
(!this.lastPrevKvPairData[key] || this.lastPrevKvPairData[key][0] < aggTimestamp)) {
this.lastPrevKvPairData[key] = [aggTimestamp, aggData.aggValue];
}
@ -246,11 +250,11 @@ export class DataAggregator {
}
});
keyData.sort((set1, set2) => set1[0] - set2[0]);
if (this.stateData) {
if (this.subsTw.aggregation.stateData) {
this.updateStateBounds(keyData, deepClone(this.lastPrevKvPairData[key]));
}
if (keyData.length > this.limit) {
keyData = keyData.slice(keyData.length - this.limit);
if (keyData.length > this.subsTw.aggregation.limit) {
keyData = keyData.slice(keyData.length - this.subsTw.aggregation.limit);
}
this.dataBuffer[key] = keyData;
}
@ -286,7 +290,7 @@ export class DataAggregator {
}
private processAggregatedData(data: SubscriptionData): AggregationMap {
const isCount = this.aggregationType === AggregationType.COUNT;
const isCount = this.subsTw.aggregation.type === AggregationType.COUNT;
const aggregationMap: AggregationMap = {};
for (const key of Object.keys(data)) {
let aggKeyData = aggregationMap[key];
@ -311,7 +315,7 @@ export class DataAggregator {
}
private updateAggregatedData(data: SubscriptionData) {
const isCount = this.aggregationType === AggregationType.COUNT;
const isCount = this.subsTw.aggregation.type === AggregationType.COUNT;
for (const key of Object.keys(data)) {
let aggKeyData = this.aggregationMap[key];
if (!aggKeyData) {
@ -323,7 +327,8 @@ export class DataAggregator {
const timestamp = kvPair[0];
const value = this.convertValue(kvPair[1]);
const aggTimestamp = this.noAggregation ? timestamp : (this.startTs +
Math.floor((timestamp - this.startTs) / this.interval) * this.interval + this.interval / 2);
Math.floor((timestamp - this.startTs) / this.subsTw.aggregation.interval) *
this.subsTw.aggregation.interval + this.subsTw.aggregation.interval / 2);
let aggData = aggKeyData.get(aggTimestamp);
if (!aggData) {
aggData = {

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

@ -237,7 +237,7 @@ export class EntityDataSubscription {
};
if (this.entityDataSubscriptionOptions.isPaginatedDataSubscription) {
this.prepareSubscriptionCommands(this.dataCommand);
this.prepareSubscriptionCommands();
}
this.subscriber.subscriptionCommands.push(this.dataCommand);
@ -256,8 +256,8 @@ export class EntityDataSubscription {
if (this.started) {
const targetCommand = this.entityDataSubscriptionOptions.isPaginatedDataSubscription ? this.dataCommand : this.subsCommand;
if (this.entityDataSubscriptionOptions.type === widgetType.timeseries &&
!this.history && this.tsFields.length) {
const newSubsTw: SubscriptionTimewindow = this.listener.updateRealtimeSubscription();
!this.history && this.tsFields.length) {
const newSubsTw = this.listener.updateRealtimeSubscription();
this.subsTw = newSubsTw;
targetCommand.tsCmd.startTs = this.subsTw.startTs;
targetCommand.tsCmd.timeWindow = this.subsTw.aggregation.timeWindow;
@ -266,9 +266,10 @@ export class EntityDataSubscription {
targetCommand.tsCmd.agg = this.subsTw.aggregation.type;
targetCommand.tsCmd.fetchLatestPreviousPoint = this.subsTw.aggregation.stateData;
this.dataAggregators.forEach((dataAggregator) => {
dataAggregator.reset(newSubsTw.startTs, newSubsTw.aggregation.timeWindow, newSubsTw.aggregation.interval);
dataAggregator.reset(newSubsTw);
});
}
this.subscriber.setTsOffset(this.subsTw.tsOffset);
targetCommand.query = this.dataCommand.query;
this.subscriber.subscriptionCommands = [targetCommand];
} else {
@ -393,7 +394,7 @@ export class EntityDataSubscription {
if (this.datasourceType === DatasourceType.entity) {
this.subsCommand = new EntityDataCmd();
this.subsCommand.cmdId = this.dataCommand.cmdId;
this.prepareSubscriptionCommands(this.subsCommand);
this.prepareSubscriptionCommands();
if (!this.subsCommand.isEmpty()) {
this.subscriber.subscriptionCommands = [this.subsCommand];
this.subscriber.update();
@ -404,11 +405,11 @@ export class EntityDataSubscription {
this.started = true;
}
private prepareSubscriptionCommands(cmd: EntityDataCmd) {
private prepareSubscriptionCommands() {
if (this.entityDataSubscriptionOptions.type === widgetType.timeseries) {
if (this.tsFields.length > 0) {
if (this.history) {
cmd.historyCmd = {
this.subsCommand.historyCmd = {
keys: this.tsFields.map(key => key.key),
startTs: this.subsTw.fixedWindow.startTimeMs,
endTs: this.subsTw.fixedWindow.endTimeMs,
@ -418,7 +419,7 @@ export class EntityDataSubscription {
fetchLatestPreviousPoint: this.subsTw.aggregation.stateData
};
} else {
cmd.tsCmd = {
this.subsCommand.tsCmd = {
keys: this.tsFields.map(key => key.key),
startTs: this.subsTw.startTs,
timeWindow: this.subsTw.aggregation.timeWindow,
@ -429,9 +430,10 @@ export class EntityDataSubscription {
};
}
}
this.subscriber.setTsOffset(this.subsTw.tsOffset);
} else if (this.entityDataSubscriptionOptions.type === widgetType.latest) {
if (this.latestValues.length > 0) {
cmd.latestCmd = {
this.subsCommand.latestCmd = {
keys: this.latestValues
};
}
@ -745,15 +747,9 @@ export class EntityDataSubscription {
this.onData(data, dataKeyType, dataIndex, detectChanges, dataUpdatedCb);
},
tsKeyNames,
subsTw.startTs,
subsTw.aggregation.limit,
subsTw.aggregation.type,
subsTw.aggregation.timeWindow,
subsTw.aggregation.interval,
subsTw.aggregation.stateData,
subsTw,
this.utils,
this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick,
subsTw.quickInterval
this.entityDataSubscriptionOptions.ignoreDataUpdateOnIntervalTick
);
}
@ -828,7 +824,8 @@ export class EntityDataSubscription {
startTime = dataKey.lastUpdateTime + this.frequency;
endTime = dataKey.lastUpdateTime + deltaElapsed;
} else {
startTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.startTs;
startTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.startTs +
this.entityDataSubscriptionOptions.subscriptionTimewindow.tsOffset;
endTime = startTime + this.entityDataSubscriptionOptions.subscriptionTimewindow.realtimeWindowMs + this.frequency;
if (this.entityDataSubscriptionOptions.subscriptionTimewindow.aggregation.type === AggregationType.NONE) {
const time = endTime - this.frequency * this.entityDataSubscriptionOptions.subscriptionTimewindow.aggregation.limit;
@ -836,8 +833,10 @@ export class EntityDataSubscription {
}
}
} else {
startTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.fixedWindow.startTimeMs;
endTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.fixedWindow.endTimeMs;
startTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.fixedWindow.startTimeMs +
this.entityDataSubscriptionOptions.subscriptionTimewindow.tsOffset;
endTime = this.entityDataSubscriptionOptions.subscriptionTimewindow.fixedWindow.endTimeMs +
this.entityDataSubscriptionOptions.subscriptionTimewindow.tsOffset;
}
}
generatedData.data[`${dataKey.name}_${dataKey.index}`] = this.generateSeries(dataKey, index, startTime, endTime);

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

@ -40,7 +40,7 @@ import {
calculateIntervalEndTime,
calculateIntervalStartTime,
createSubscriptionTimewindow,
createTimewindowForComparison,
createTimewindowForComparison, getCurrentTime,
SubscriptionTimewindow,
Timewindow,
toHistoryTimewindow,
@ -839,9 +839,11 @@ export class WidgetSubscription implements IWidgetSubscription {
if (this.alarmDataListener) {
this.ctx.alarmDataService.stopSubscription(this.alarmDataListener);
}
if (this.timeWindowConfig) {
this.updateRealtimeSubscription();
}
this.alarmDataListener = {
subscriptionTimewindow: this.subscriptionTimewindow,
alarmSource: this.alarmSource,
@ -1082,14 +1084,21 @@ export class WidgetSubscription implements IWidgetSubscription {
private updateTimewindow() {
this.timeWindow.interval = this.subscriptionTimewindow.aggregation.interval || 1000;
this.timeWindow.timezone = this.subscriptionTimewindow.timezone;
if (this.subscriptionTimewindow.realtimeWindowMs) {
this.timeWindow.maxTime = calculateIntervalEndTime(
this.subscriptionTimewindow.quickInterval, moment().valueOf() + this.timeWindow.stDiff);
this.timeWindow.minTime = calculateIntervalStartTime(
this.subscriptionTimewindow.quickInterval, this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs);
if (this.subscriptionTimewindow.quickInterval) {
const currentDate = getCurrentTime(this.subscriptionTimewindow.timezone);
this.timeWindow.maxTime = calculateIntervalEndTime(
this.subscriptionTimewindow.quickInterval, currentDate) + this.subscriptionTimewindow.tsOffset;
this.timeWindow.minTime = calculateIntervalStartTime(
this.subscriptionTimewindow.quickInterval, currentDate) + this.subscriptionTimewindow.tsOffset;
} else {
this.timeWindow.maxTime = moment().valueOf() + this.subscriptionTimewindow.tsOffset + this.timeWindow.stDiff;
this.timeWindow.minTime = this.timeWindow.maxTime - this.subscriptionTimewindow.realtimeWindowMs;
}
} else if (this.subscriptionTimewindow.fixedWindow) {
this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs;
this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs;
this.timeWindow.maxTime = this.subscriptionTimewindow.fixedWindow.endTimeMs + this.subscriptionTimewindow.tsOffset;
this.timeWindow.minTime = this.subscriptionTimewindow.fixedWindow.startTimeMs + this.subscriptionTimewindow.tsOffset;
}
}
@ -1107,12 +1116,13 @@ export class WidgetSubscription implements IWidgetSubscription {
private updateComparisonTimewindow() {
this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000;
this.comparisonTimeWindow.timezone = this.timewindowForComparison.timezone;
if (this.timewindowForComparison.realtimeWindowMs) {
this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf();
this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf();
} else if (this.timewindowForComparison.fixedWindow) {
this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs;
this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs;
this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs + this.timewindowForComparison.tsOffset;
this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset;
}
}
@ -1339,7 +1349,7 @@ export class WidgetSubscription implements IWidgetSubscription {
this.onDataUpdated();
}
private alarmsUpdated(_updated: Array<AlarmData>, alarms: PageData<AlarmData>) {
private alarmsUpdated(updated: Array<AlarmData>, alarms: PageData<AlarmData>) {
this.alarmsLoaded(alarms, 0, 0);
}

1
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html

@ -91,6 +91,7 @@
direction="left"
tooltipPosition="below"
aggregation="true"
timezone="true"
[(ngModel)]="dashboardCtx.dashboardTimewindow">
</tb-timewindow>
<tb-filters-edit [fxShow]="!isEdit && displayFilters()"

1
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html

@ -95,6 +95,7 @@
<tb-timewindow *ngIf="widget.hasTimewindow"
#timewindowComponent
aggregation="{{widget.hasAggregation}}"
timezone="true"
[isEdit]="isEdit"
[(ngModel)]="widgetComponent.widget.config.timewindow"
(ngModelChange)="widgetComponent.onTimewindowChanged($event)">

12
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -55,7 +55,13 @@ import { EntityTypeTranslation } from '@shared/models/entity-type.models';
import { DialogService } from '@core/services/dialog.service';
import { AddEntityDialogComponent } from './add-entity-dialog.component';
import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-component.models';
import { HistoryWindowType, Timewindow } from '@shared/models/time/time.models';
import {
calculateIntervalEndTime,
calculateIntervalStartTime,
getCurrentTime,
HistoryWindowType,
Timewindow
} from '@shared/models/time/time.models';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { TbAnchorComponent } from '@shared/components/tb-anchor.component';
import { isDefined, isUndefined } from '@core/utils';
@ -296,6 +302,10 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn
const currentTime = Date.now();
timePageLink.startTime = currentTime - this.timewindow.history.timewindowMs;
timePageLink.endTime = currentTime;
} else if (this.timewindow.history.historyType === HistoryWindowType.INTERVAL) {
const currentDate = getCurrentTime();
timePageLink.startTime = calculateIntervalStartTime(this.timewindow.history.quickInterval, currentDate);
timePageLink.endTime = calculateIntervalEndTime(this.timewindow.history.quickInterval, currentDate);
} else {
timePageLink.startTime = this.timewindow.history.fixedTimewindow.startTimeMs;
timePageLink.endTime = this.timewindow.history.fixedTimewindow.endTimeMs;

9
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts

@ -94,11 +94,10 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator,
items: this.fb.array(Array.from({length: 7}, (value, i) => this.defaultItemsScheduler(i)), this.validateItems)
});
this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => {
getDefaultTimezone().subscribe((defaultTimezone) => {
this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: defaultTimezone}, {emitEvent: false});
this.updateValidators(type, true);
this.alarmScheduleForm.updateValueAndValidity();
});
const defaultTimezone = getDefaultTimezone();
this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: defaultTimezone}, {emitEvent: false});
this.updateValidators(type, true);
this.alarmScheduleForm.updateValueAndValidity();
});
this.alarmScheduleForm.valueChanges.subscribe(() => {
this.updateModel();

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

@ -49,7 +49,7 @@
formControlName="quickInterval"
onlyCurrentInterval="true"
[fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval>
</section>
@ -99,7 +99,7 @@
formControlName="quickInterval"
[fxShow]="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
style="padding-top: 8px; min-width: 364px"></tb-quick-time-interval>
</section>
</mat-radio-button>
@ -177,6 +177,16 @@
predefinedName="aggregation.group-interval">
</tb-timeinterval>
</div>
<div *ngIf="timezone" class="mat-content mat-padding" fxLayout="row">
<section fxLayout="column" [fxShow]="isEdit">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideTimezone"
(ngModelChange)="onHideTimezoneChanged()"></mat-checkbox>
</section>
<tb-timezone-select fxFlex [fxShow]="isEdit || !timewindow.hideTimezone"
formControlName="timezone">
</tb-timezone-select>
</div>
<div fxLayout="row" class="tb-panel-actions" fxLayoutAlign="end center">
<button type="button"
mat-button

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

@ -38,6 +38,7 @@ export interface TimewindowPanelData {
historyOnly: boolean;
timewindow: Timewindow;
aggregation: boolean;
timezone: boolean;
isEdit: boolean;
}
@ -52,6 +53,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
aggregation = false;
timezone = false;
isEdit = false;
timewindow: Timewindow;
@ -82,6 +85,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
this.historyOnly = data.historyOnly;
this.timewindow = data.timewindow;
this.aggregation = data.aggregation;
this.timezone = data.timezone;
this.isEdit = data.isEdit;
}
@ -89,6 +93,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
const hideInterval = this.timewindow.hideInterval || false;
const hideAggregation = this.timewindow.hideAggregation || false;
const hideAggInterval = this.timewindow.hideAggInterval || false;
const hideTimezone = this.timewindow.hideTimezone || false;
this.timewindowForm = this.fb.group({
realtime: this.fb.group(
@ -154,7 +159,12 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
disabled: hideAggInterval
}, [Validators.min(this.minDatapointsLimit()), Validators.max(this.maxDatapointsLimit())])
}
)
),
timezone: this.fb.control({
value: this.timewindow.timezone !== 'undefined'
? this.timewindow.timezone : null,
disabled: hideTimezone
})
});
}
@ -171,7 +181,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
timewindowMs: timewindowFormValue.history.timewindowMs,
interval: timewindowFormValue.history.interval,
fixedTimewindow: timewindowFormValue.history.fixedTimewindow,
quickInterval: timewindowFormValue.history.quickInterval
quickInterval: timewindowFormValue.history.quickInterval,
};
if (this.aggregation) {
this.timewindow.aggregation = {
@ -179,6 +189,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
limit: timewindowFormValue.aggregation.limit
};
}
if (this.timezone) {
this.timewindow.timezone = timewindowFormValue.timezone;
}
this.result = this.timewindow;
this.overlayRef.dispose();
}
@ -276,4 +289,13 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
this.timewindowForm.markAsDirty();
}
onHideTimezoneChanged() {
if (this.timewindow.hideTimezone) {
this.timewindowForm.get('timezone').disable({emitEvent: false});
} else {
this.timewindowForm.get('timezone').enable({emitEvent: false});
}
this.timewindowForm.markAsDirty();
}
}

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

@ -91,6 +91,17 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
return this.aggregationValue;
}
timezoneValue = false;
@Input()
set timezone(val) {
this.timezoneValue = coerceBooleanProperty(val);
}
get timezone() {
return this.timezoneValue;
}
isToolbarValue = false;
@Input()
@ -171,7 +182,7 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
});
if (isGtXs) {
config.minWidth = '417px';
config.maxHeight = '440px';
config.maxHeight = '500px';
const panelHeight = 375;
const panelWidth = 417;
const el = this.timewindowPanelOrigin.elementRef.nativeElement;
@ -227,6 +238,7 @@ export class TimewindowComponent implements OnInit, OnDestroy, ControlValueAcces
timewindow: deepClone(this.innerValue),
historyOnly: this.historyOnly,
aggregation: this.aggregation,
timezone: this.timezone,
isEdit: this.isEdit
}
);

57
ui-ngx/src/app/shared/components/time/timezone-select.component.ts

@ -16,7 +16,7 @@
import { AfterViewInit, Component, forwardRef, Input, NgZone, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
@ -43,10 +43,6 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af
defaultTimezoneId: string = null;
timezones$ = getTimezones().pipe(
share()
);
@Input()
set defaultTimezone(timezone: string) {
if (this.defaultTimezoneId !== timezone) {
@ -138,23 +134,20 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af
writeValue(value: string | null): void {
this.searchText = '';
getTimezoneInfo(value, this.defaultTimezoneId, this.userTimezoneByDefaultValue).subscribe(
(foundTimezone) => {
if (foundTimezone !== null) {
this.selectTimezoneFormGroup.get('timezone').patchValue(foundTimezone, {emitEvent: false});
if (foundTimezone.id !== value) {
setTimeout(() => {
this.updateView(foundTimezone.id);
}, 0);
} else {
this.modelValue = value;
}
} else {
this.modelValue = null;
this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false});
}
const foundTimezone = getTimezoneInfo(value, this.defaultTimezoneId, this.userTimezoneByDefaultValue);
if (foundTimezone !== null) {
this.selectTimezoneFormGroup.get('timezone').patchValue(foundTimezone, {emitEvent: false});
if (foundTimezone.id !== value) {
setTimeout(() => {
this.updateView(foundTimezone.id);
}, 0);
} else {
this.modelValue = value;
}
);
} else {
this.modelValue = null;
this.selectTimezoneFormGroup.get('timezone').patchValue('', {emitEvent: false});
}
this.dirty = true;
}
@ -170,14 +163,12 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af
this.ignoreClosePanel = false;
} else {
if (!this.modelValue && (this.defaultTimezoneId || this.userTimezoneByDefaultValue)) {
getTimezoneInfo(this.defaultTimezoneId, this.defaultTimezoneId, this.userTimezoneByDefaultValue).subscribe(
(defaultTimezoneInfo) => {
if (defaultTimezoneInfo !== null) {
this.ngZone.run(() => {
this.selectTimezoneFormGroup.get('timezone').reset(defaultTimezoneInfo, {emitEvent: true});
});
}
});
const defaultTimezoneInfo = getTimezoneInfo(this.defaultTimezoneId, this.defaultTimezoneId, this.userTimezoneByDefaultValue);
if (defaultTimezoneInfo !== null) {
this.ngZone.run(() => {
this.selectTimezoneFormGroup.get('timezone').reset(defaultTimezoneInfo, {emitEvent: true});
});
}
}
}
}
@ -196,12 +187,10 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af
fetchTimezones(searchText?: string): Observable<Array<TimezoneInfo>> {
this.searchText = searchText;
if (searchText && searchText.length) {
return getTimezones().pipe(
map((timezones) => timezones.filter((timezoneInfo) =>
timezoneInfo.name.toLowerCase().includes(searchText.toLowerCase())))
);
return of(getTimezones().filter((timezoneInfo) =>
timezoneInfo.name.toLowerCase().includes(searchText.toLowerCase())));
}
return getTimezones();
return of(getTimezones());
}
clear() {

41
ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts

@ -430,6 +430,38 @@ export class EntityDataUpdate extends DataUpdate<EntityData> {
constructor(msg: EntityDataUpdateMsg) {
super(msg);
}
public prepareData(tsOffset: number) {
if (this.data) {
this.processEntityData(this.data.data, tsOffset);
}
if (this.update) {
this.processEntityData(this.update, tsOffset);
}
}
private processEntityData(data: Array<EntityData>, tsOffset: number) {
for (const entityData of data) {
if (entityData.timeseries) {
for (const key of Object.keys(entityData.timeseries)) {
const tsValues = entityData.timeseries[key];
for (const tsValue of tsValues) {
tsValue.ts += tsOffset;
}
}
}
if (entityData.latest) {
for (const entityKeyType of Object.keys(entityData.latest)) {
const keyTypeValues = entityData.latest[entityKeyType];
for (const key of Object.keys(keyTypeValues)) {
const tsValue = keyTypeValues[key];
tsValue.ts += tsOffset;
}
}
}
}
}
}
export class AlarmDataUpdate extends DataUpdate<AlarmData> {
@ -468,6 +500,8 @@ export class TelemetrySubscriber {
private zone: NgZone;
private tsOffset = 0;
public subscriptionCommands: Array<WebsocketCmd>;
public data$ = this.dataSubject.asObservable();
@ -522,6 +556,10 @@ export class TelemetrySubscriber {
this.reconnectSubject.complete();
}
public setTsOffset(tsOffset: number) {
this.tsOffset = tsOffset;
}
public onData(message: SubscriptionUpdate) {
const cmdId = message.subscriptionId;
let keys: string[];
@ -545,6 +583,9 @@ export class TelemetrySubscriber {
}
public onEntityData(message: EntityDataUpdate) {
if (this.tsOffset) {
message.prepareData(this.tsOffset);
}
if (this.zone) {
this.zone.run(
() => {

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

@ -15,11 +15,9 @@
///
import { TimeService } from '@core/services/time.service';
import { deepClone, isDefined, isDefinedAndNotNull, isUndefined } from '@app/core/utils';
import { deepClone, isDefined, isUndefined } from '@app/core/utils';
import * as moment_ from 'moment';
import { Observable } from 'rxjs/internal/Observable';
import { from, of } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators';
import * as monentTz from 'moment-timezone';
const moment = moment_;
@ -97,10 +95,12 @@ export interface Timewindow {
hideInterval?: boolean;
hideAggregation?: boolean;
hideAggInterval?: boolean;
hideTimezone?: boolean;
selectedTab?: TimewindowType;
realtime?: RealtimeWindow;
history?: HistoryWindow;
aggregation?: Aggregation;
timezone?: string;
}
export interface SubscriptionAggregation extends Aggregation {
@ -112,6 +112,8 @@ export interface SubscriptionAggregation extends Aggregation {
export interface SubscriptionTimewindow {
startTs?: number;
quickInterval?: QuickTimeInterval;
timezone?: string;
tsOffset?: number;
realtimeWindowMs?: number;
fixedWindow?: FixedWindow;
aggregation?: SubscriptionAggregation;
@ -121,6 +123,7 @@ export interface WidgetTimewindow {
minTime?: number;
maxTime?: number;
interval?: number;
timezone?: string;
stDiff?: number;
}
@ -178,6 +181,7 @@ export function defaultTimewindow(timeService: TimeService): Timewindow {
hideInterval: false,
hideAggregation: false,
hideAggInterval: false,
hideTimezone: false,
selectedTab: TimewindowType.REALTIME,
realtime: {
realtimeType: RealtimeWindowType.LAST_INTERVAL,
@ -209,6 +213,7 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
model.hideInterval = value.hideInterval;
model.hideAggregation = value.hideAggregation;
model.hideAggInterval = value.hideAggInterval;
model.hideTimezone = value.hideTimezone;
if (isUndefined(value.selectedTab)) {
if (value.realtime) {
model.selectedTab = TimewindowType.REALTIME;
@ -266,6 +271,7 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
}
model.aggregation.limit = value.aggregation.limit || Math.floor(timeService.getMaxDatapointsLimit() / 2);
}
model.timezone = value.timezone;
}
return model;
}
@ -292,6 +298,7 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number,
hideInterval: timewindow.hideInterval || false,
hideAggregation: timewindow.hideAggregation || false,
hideAggInterval: timewindow.hideAggInterval || false,
hideTimezone: timewindow.hideTimezone || false,
selectedTab: TimewindowType.HISTORY,
history: {
historyType: HistoryWindowType.FIXED,
@ -304,7 +311,8 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number,
aggregation: {
type: aggType,
limit
}
},
timezone: timewindow.timezone
};
return historyTimewindow;
}
@ -318,8 +326,15 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
interval: SECOND,
limit: timeService.getMaxDatapointsLimit(),
type: AggregationType.AVG
}
},
timezone: timewindow.timezone,
tsOffset: 0
};
if (timewindow.timezone) {
const tz = getTimezone(timewindow.timezone);
const localOffset = moment().utcOffset();
subscriptionTimewindow.tsOffset = (tz.utcOffset() - localOffset) * 60 * 1000;
}
let aggTimewindow = 0;
if (stateData) {
subscriptionTimewindow.aggregation.type = AggregationType.NONE;
@ -345,20 +360,25 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
}
}
if (realtimeType === RealtimeWindowType.INTERVAL) {
subscriptionTimewindow.realtimeWindowMs = getSubscriptionRealtimeWindowFromTimeInterval(timewindow.realtime.quickInterval);
const currentDate = getCurrentTime(timewindow.timezone);
subscriptionTimewindow.realtimeWindowMs =
getSubscriptionRealtimeWindowFromTimeInterval(timewindow.realtime.quickInterval, currentDate);
subscriptionTimewindow.quickInterval = timewindow.realtime.quickInterval;
subscriptionTimewindow.startTs = calculateIntervalStartTime(timewindow.realtime.quickInterval, currentDate);
} else {
subscriptionTimewindow.realtimeWindowMs = timewindow.realtime.timewindowMs;
subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs;
}
subscriptionTimewindow.aggregation.interval =
timeService.boundIntervalToTimewindow(subscriptionTimewindow.realtimeWindowMs, timewindow.realtime.interval,
subscriptionTimewindow.aggregation.type);
subscriptionTimewindow.startTs = Date.now() + stDiff - subscriptionTimewindow.realtimeWindowMs;
const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval;
aggTimewindow = subscriptionTimewindow.realtimeWindowMs;
if (startDiff && realtimeType !== RealtimeWindowType.INTERVAL) {
subscriptionTimewindow.startTs -= startDiff;
aggTimewindow += subscriptionTimewindow.aggregation.interval;
if (realtimeType !== RealtimeWindowType.INTERVAL) {
const startDiff = subscriptionTimewindow.startTs % subscriptionTimewindow.aggregation.interval;
if (startDiff) {
subscriptionTimewindow.startTs -= startDiff;
aggTimewindow += subscriptionTimewindow.aggregation.interval;
}
}
} else {
let historyType = timewindow.history.historyType;
@ -372,23 +392,24 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
}
}
if (historyType === HistoryWindowType.LAST_INTERVAL) {
const currentTime = Date.now();
const currentDate = getCurrentTime(timewindow.timezone);
const currentTime = currentDate.valueOf();
subscriptionTimewindow.fixedWindow = {
startTimeMs: currentTime - timewindow.history.timewindowMs,
endTimeMs: currentTime
};
aggTimewindow = timewindow.history.timewindowMs;
} else if (historyType === HistoryWindowType.INTERVAL) {
const currentDate = moment();
const currentDate = getCurrentTime(timewindow.timezone);
subscriptionTimewindow.fixedWindow = {
startTimeMs: calculateIntervalStartTime(timewindow.history.quickInterval, null, currentDate),
endTimeMs: calculateIntervalEndTime(timewindow.history.quickInterval, null, currentDate)
startTimeMs: calculateIntervalStartTime(timewindow.history.quickInterval, currentDate),
endTimeMs: calculateIntervalEndTime(timewindow.history.quickInterval, currentDate)
};
aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
} else {
subscriptionTimewindow.fixedWindow = {
startTimeMs: timewindow.history.fixedTimewindow.startTimeMs,
endTimeMs: timewindow.history.fixedTimewindow.endTimeMs
startTimeMs: timewindow.history.fixedTimewindow.startTimeMs - subscriptionTimewindow.tsOffset,
endTimeMs: timewindow.history.fixedTimewindow.endTimeMs - subscriptionTimewindow.tsOffset
};
aggTimewindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
}
@ -404,88 +425,85 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
return subscriptionTimewindow;
}
function getSubscriptionRealtimeWindowFromTimeInterval(interval: QuickTimeInterval): number {
const currentDate = moment();
function getSubscriptionRealtimeWindowFromTimeInterval(interval: QuickTimeInterval, currentDate: moment_.Moment): number {
switch (interval) {
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.diff(currentDate.clone().startOf('hour'))
return HOUR;
case QuickTimeInterval.CURRENT_DAY:
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('day'));
return DAY;
case QuickTimeInterval.CURRENT_WEEK:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('week'));
return WEEK;
case QuickTimeInterval.CURRENT_MONTH:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('month'));
return currentDate.endOf('month').diff(currentDate.clone().startOf('month'));
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.diff(currentDate.clone().startOf('year'));
return currentDate.endOf('year').diff(currentDate.clone().startOf('year'));
}
}
export function calculateIntervalEndTime(interval: QuickTimeInterval, endTs = 0, nowDate?: moment_.Moment): number {
const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
switch (interval) {
case QuickTimeInterval.YESTERDAY:
currentDate.subtract(1, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
currentDate.subtract(2, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
currentDate.subtract(1, 'months');
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
currentDate.subtract(1, 'years');
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.endOf('hour').valueOf();
case QuickTimeInterval.CURRENT_DAY:
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.CURRENT_WEEK:
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.CURRENT_MONTH:
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.CURRENT_YEAR:
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.valueOf();
default:
return endTs;
export function calculateIntervalEndTime(interval: QuickTimeInterval, currentDate: moment_.Moment = null, tz: string = ''): number {
currentDate = currentDate ? currentDate.clone() : getCurrentTime(tz);
switch (interval) {
case QuickTimeInterval.YESTERDAY:
currentDate.subtract(1, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
currentDate.subtract(2, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
currentDate.subtract(1, 'months');
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
currentDate.subtract(1, 'years');
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.endOf('hour').valueOf();
case QuickTimeInterval.CURRENT_DAY:
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.CURRENT_WEEK:
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.CURRENT_MONTH:
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.CURRENT_YEAR:
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.valueOf();
}
}
export function calculateIntervalStartTime(interval: QuickTimeInterval, startTS = 0, nowDate?: moment_.Moment): number {
const currentDate = isDefinedAndNotNull(nowDate) ? nowDate.clone() : moment();
export function calculateIntervalStartTime(interval: QuickTimeInterval, currentDate: moment_.Moment = null, tz: string = ''): number {
currentDate = currentDate ? currentDate.clone() : getCurrentTime(tz);
switch (interval) {
case QuickTimeInterval.YESTERDAY:
currentDate.subtract(1, 'days');
return currentDate.startOf('day').valueOf();
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
currentDate.subtract(2, 'days');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('day').valueOf();
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('week').valueOf();
return currentDate.startOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
currentDate.subtract(1, 'months');
return currentDate.startOf('month').valueOf();
return currentDate.startOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
currentDate.subtract(1, 'years');
return currentDate.startOf('year').valueOf();
return currentDate.startOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
return currentDate.startOf('hour').valueOf();
case QuickTimeInterval.CURRENT_DAY:
@ -500,8 +518,6 @@ export function calculateIntervalStartTime(interval: QuickTimeInterval, startTS
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.startOf('year').valueOf();
default:
return startTS;
}
}
@ -560,6 +576,7 @@ export function cloneSelectedTimewindow(timewindow: Timewindow): Timewindow {
cloned.hideInterval = timewindow.hideInterval || false;
cloned.hideAggregation = timewindow.hideAggregation || false;
cloned.hideAggInterval = timewindow.hideAggInterval || false;
cloned.hideTimezone = timewindow.hideTimezone || false;
if (isDefined(timewindow.selectedTab)) {
cloned.selectedTab = timewindow.selectedTab;
if (timewindow.selectedTab === TimewindowType.REALTIME) {
@ -569,6 +586,7 @@ export function cloneSelectedTimewindow(timewindow: Timewindow): Timewindow {
}
}
cloned.aggregation = deepClone(timewindow.aggregation);
cloned.timezone = timewindow.timezone;
return cloned;
}
@ -718,60 +736,50 @@ export interface TimezoneInfo {
let timezones: TimezoneInfo[] = null;
let defaultTimezone: string = null;
export function getTimezones(): Observable<TimezoneInfo[]> {
if (timezones) {
return of(timezones);
} else {
return from(import('moment-timezone')).pipe(
map((monentTz) => {
return monentTz.tz.names().map((zoneName) => {
const tz = monentTz.tz(zoneName);
return {
id: zoneName,
name: zoneName.replace(/_/g, ' '),
offset: `UTC${tz.format('Z')}`,
nOffset: tz.utcOffset()
};
});
}),
tap((zones) => {
timezones = zones;
})
);
export function getTimezones(): TimezoneInfo[] {
if (!timezones) {
timezones = monentTz.tz.names().map((zoneName) => {
const tz = monentTz.tz(zoneName);
return {
id: zoneName,
name: zoneName.replace(/_/g, ' '),
offset: `UTC${tz.format('Z')}`,
nOffset: tz.utcOffset()
};
});
}
return timezones;
}
export function getTimezoneInfo(timezoneId: string, defaultTimezoneId?: string, userTimezoneByDefault?: boolean): TimezoneInfo {
const timezoneList = getTimezones();
let foundTimezone = timezoneId ? timezoneList.find(timezoneInfo => timezoneInfo.id === timezoneId) : null;
if (!foundTimezone) {
if (userTimezoneByDefault) {
const userTimezone = getDefaultTimezone();
foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === userTimezone);
} else if (defaultTimezoneId) {
foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === defaultTimezoneId);
}
}
return foundTimezone;
}
export function getTimezoneInfo(timezoneId: string, defaultTimezoneId?: string, userTimezoneByDefault?: boolean): Observable<TimezoneInfo> {
return getTimezones().pipe(
mergeMap((timezoneList) => {
let foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === timezoneId);
if (!foundTimezone) {
if (userTimezoneByDefault) {
return getDefaultTimezone().pipe(
map((userTimezone) => {
return timezoneList.find(timezoneInfo => timezoneInfo.id === userTimezone);
})
);
} else if (defaultTimezoneId) {
foundTimezone = timezoneList.find(timezoneInfo => timezoneInfo.id === defaultTimezoneId);
}
}
return of(foundTimezone);
})
);
export function getDefaultTimezone(): string {
if (!defaultTimezone) {
defaultTimezone = monentTz.tz.guess();
}
return defaultTimezone;
}
export function getDefaultTimezone(): Observable<string> {
if (defaultTimezone) {
return of(defaultTimezone);
export function getCurrentTime(tz?: string): moment_.Moment {
if (tz) {
return moment().tz(tz);
} else {
return from(import('moment-timezone')).pipe(
map((monentTz) => {
return monentTz.tz.guess();
}),
tap((zone) => {
defaultTimezone = zone;
})
);
return moment();
}
}
export function getTimezone(tz: string): moment_.Moment {
return moment.tz(tz);
}

Loading…
Cancel
Save