@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
241 lines • 70.6 kB
JavaScript
import { Component, Input, Optional, ViewChild } from '@angular/core';
import { AGGREGATION_ICONS, AGGREGATION_TEXTS, CoreModule, gettext, WidgetTimeContextDateRangeService } from '@c8y/ngx-components';
import { cloneDeep } from 'lodash-es';
import { FormBuilder, Validators } from '@angular/forms';
import { takeUntil } from 'rxjs/operators';
import { ALARM_STATUS_LABELS } from '@c8y/client';
import { TranslateService } from '@ngx-translate/core';
import { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';
import { A11yModule } from '@angular/cdk/a11y';
import { CommonModule } from '@angular/common';
import { ChartsComponent, ChartEventsService, ChartAlarmsService } from '@c8y/ngx-components/echart';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { AlarmsModule } from '@c8y/ngx-components/alarms';
import { Subject } from 'rxjs';
import { TimeContextComponent } from '@c8y/ngx-components/time-context';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@ngx-translate/core";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@c8y/ngx-components/context-dashboard";
import * as i5 from "@angular/common";
import * as i6 from "ngx-bootstrap/tooltip";
import * as i7 from "ngx-bootstrap/popover";
import * as i8 from "@c8y/ngx-components/alarms";
export class DatapointsGraphWidgetViewComponent {
set config(value) {
this.displayConfig = cloneDeep(value);
}
get config() {
throw Error('"config" property should not be referenced in view component to avoid mutating data.');
}
constructor(formBuilder, translate, widgetTimeContextDateRangeService, dashboardContextComponent) {
this.formBuilder = formBuilder;
this.translate = translate;
this.widgetTimeContextDateRangeService = widgetTimeContextDateRangeService;
this.dashboardContextComponent = dashboardContextComponent;
this.events = [];
this.alarms = [];
this.AGGREGATION_ICONS = AGGREGATION_ICONS;
this.AGGREGATION_TEXTS = AGGREGATION_TEXTS;
this.datapointsOutOfSync = new Map();
this.hasAtLeastOneDatapointActive = true;
this.hasAtLeastOneAlarmActive = true;
this.isMarkedAreaEnabled = false;
this.legendHelp = this.translate.instant(gettext(`<ul class="m-l-0 p-l-8 m-t-8 m-b-0">
<li>
<b>Visibility:</b>
use visibility icon to toggle datapoint, alarm or event visibility on chart. At least one datapoint is required to display chart.
</li>
<li>
<b>Alarm details</b>
Click alarm legend item to highlight area between alarm raised timestamp and alarm cleared timestamp.
You can also click alarm markline on chart to highlight alarm and to pause tooltip. Click on highlighted area or legend item to cancel highlighting.
</li>
</ul>`));
this.disableZoomInLabel = gettext('Disable zoom in');
this.enableZoomInLabel = gettext('Click to enable zoom, then click and drag on the desired area in the chart.');
this.hideDatapointLabel = gettext('Hide data point');
this.showDatapointLabel = gettext('Show data point');
this.destroy$ = new Subject();
this.timeControlsFormGroup = this.initForm();
this.timeControlsFormGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => {
this.displayConfig = { ...this.displayConfig, ...value };
});
}
ngOnInit() {
this.displayConfig?.datapoints?.forEach(dp => this.assignContextFromContextDashboard(dp));
if (this.displayConfig.dateFrom && this.displayConfig.dateTo) {
this.timeProps = {
dateFrom: new Date(this.displayConfig?.dateFrom),
dateTo: new Date(this.displayConfig?.dateTo),
interval: this.displayConfig?.interval,
realtime: this.displayConfig?.realtime,
aggregation: this.displayConfig?.realtime ? null : this.displayConfig?.aggregation
};
}
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
ngOnChanges(changes) {
this.timeControlsFormGroup.patchValue(this.displayConfig || {});
const config = changes['config']?.currentValue;
if (config?.date && config?.widgetInstanceGlobalTimeContext && this.displayConfig?.date) {
if (!this.displayConfig.sliderChange) {
this.widgetTimeContextDateRangeService.updateInitialTimeRange(null);
}
this.timePropsChanged({
currentDateContextFromDate: this.displayConfig?.date[0].toISOString(),
currentDateContextToDate: this.displayConfig?.date[1].toISOString(),
currentDateContextInterval: this.displayConfig?.interval,
realtime: this.displayConfig?.realtime,
aggregation: this.displayConfig?.aggregation
});
}
}
timePropsChanged(timeProps) {
const patchValues = {
dateFrom: new Date(timeProps.currentDateContextFromDate),
dateTo: new Date(timeProps.currentDateContextToDate),
interval: timeProps.currentDateContextInterval,
...(timeProps.aggregation && { aggregation: timeProps.aggregation }),
...(timeProps.realtime && { realtime: timeProps.realtime })
};
this.timeControlsFormGroup.patchValue(patchValues);
}
updateDashboardTimeContext(timeProps) {
if (this.displayConfig?.widgetInstanceGlobalTimeContext) {
this.widgetTimeContextDateRangeService.emitPropertyUpdate(timeProps);
}
this.timeControlsFormGroup.patchValue(timeProps);
this.timeProps = { ...timeProps, realtime: false };
}
updateTimeRangeOnRealtime(timeRange) {
this.timeControlsFormGroup.patchValue(timeRange, { emitEvent: false });
}
toggleChart(datapoint) {
if (this.displayConfig?.datapoints?.filter(dp => dp.__active).length === 1 &&
datapoint.__active) {
// at least 1 datapoint should be active
this.hasAtLeastOneDatapointActive = false;
return;
}
datapoint.__active = !datapoint.__active;
this.hasAtLeastOneDatapointActive = true;
this.displayConfig = { ...this.displayConfig };
}
handleDatapointOutOfSync(dpOutOfSync) {
const key = (dp) => dp.__target?.id + dp.fragment + dp.series;
const dpMatch = this.displayConfig?.datapoints?.find(dp => key(dp) === key(dpOutOfSync));
if (!dpMatch) {
return;
}
this.datapointsOutOfSync.set(dpMatch, true);
}
toggleMarkedArea(alarm) {
this.enabledMarkedAreaAlarmType = alarm.filters.type;
const params = {
data: {
itemType: alarm.filters.type
}
};
this.chartComponent.onChartClick(params);
}
toggleAlarmEventType(alarmOrEvent) {
if (alarmOrEvent.timelineType === 'ALARM') {
this.alarms = this.alarms.map(alarm => {
if (alarm.filters.type === alarmOrEvent.filters.type) {
alarm.__hidden = !alarm.__hidden;
}
return alarm;
});
}
else {
this.events = this.events.map(event => {
if (event.filters.type === alarmOrEvent.filters.type) {
event.__hidden = !event.__hidden;
}
return event;
});
}
this.displayConfig = { ...this.displayConfig };
}
updateAlarmsAndEvents(alarmsEventsConfigs) {
this.alarms = alarmsEventsConfigs.filter(alarm => alarm.timelineType === 'ALARM');
this.events = alarmsEventsConfigs.filter(event => event.timelineType === 'EVENT');
if (this.alarms.length === 0 || !this.alarms.find(alarm => alarm.__active)) {
this.hasAtLeastOneAlarmActive = false;
}
}
filterSeverity(eventTarget) {
this.alarms = this.alarms.map(alarm => {
if (!alarm.__severity) {
alarm.__severity = [];
}
alarm.__severity = Object.keys(eventTarget.severityOptions).filter((severity) => eventTarget.severityOptions[severity]);
if (!alarm.__status) {
alarm.__status = [];
}
const statuses = Object.keys(ALARM_STATUS_LABELS);
const filteredStatuses = eventTarget.showCleared
? statuses
: statuses.filter(status => status !== 'CLEARED');
alarm.__status = filteredStatuses;
return alarm;
});
this.displayConfig = { ...this.displayConfig };
}
assignContextFromContextDashboard(datapoint) {
if (!this.dashboardContextComponent?.isDeviceTypeDashboard) {
return;
}
const context = this.dashboardContextComponent?.context;
if (context?.id) {
const { name, id } = context;
datapoint.__target = { name, id };
}
}
initForm() {
const form = this.formBuilder.group({
dateFrom: [undefined, [Validators.required]],
dateTo: [undefined, [Validators.required]],
interval: [
this.displayConfig?.interval || 'hours',
[Validators.required]
],
aggregation: [null, []],
realtime: [false, [Validators.required]],
widgetInstanceGlobalTimeContext: [false, []]
});
form.patchValue(this.displayConfig || {});
return form;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatapointsGraphWidgetViewComponent, deps: [{ token: i1.FormBuilder }, { token: i2.TranslateService }, { token: i3.WidgetTimeContextDateRangeService }, { token: i4.ContextDashboardComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DatapointsGraphWidgetViewComponent, isStandalone: true, selector: "c8y-datapoints-graph-widget-view", inputs: { config: "config" }, providers: [ChartEventsService, ChartAlarmsService], viewQueries: [{ propertyName: "chartComponent", first: true, predicate: ChartsComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"p-l-16 p-r-16\">\n <div class=\"d-flex gap-16 a-i-start\">\n <div\n class=\"btn-group btn-group-sm flex-no-shrink\"\n *ngIf=\"!displayConfig?.widgetInstanceGlobalTimeContext\"\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Aggregation' | translate\"\n tooltip=\"{{\n (displayConfig?.aggregation\n ? AGGREGATION_TEXTS[displayConfig.aggregation]\n : AGGREGATION_TEXTS.undefined\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n displayConfig?.aggregation\n ? AGGREGATION_ICONS[displayConfig.aggregation]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n </button>\n\n <c8y-time-context\n class=\"d-contents\"\n (contextChange)=\"timePropsChanged($event)\"\n [changedDateContext]=\"timeProps\"\n [controlsAvailable]=\"{\n realtime: true,\n timeRange: displayConfig?.displayDateSelection,\n interval: displayConfig?.displayDateSelection,\n aggregation: displayConfig?.displayAggregationSelection\n }\"\n ></c8y-time-context>\n </div>\n <c8y-alarms-filter\n class=\"d-contents form-group-sm\"\n *ngIf=\"hasAtLeastOneAlarmActive\"\n (filterApplied)=\"filterSeverity($event)\"\n ></c8y-alarms-filter>\n\n <div class=\"m-l-auto btn-group btn-group-sm flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Save as image' | translate\"\n tooltip=\"{{ 'Save as image' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"chart.saveAsImage()\"\n [adaptivePosition]=\"false\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"image-file-checked\"\n ></i>\n </button>\n </div>\n </div>\n <div\n class=\"d-flex\"\n style=\"align-items: center\"\n >\n <button\n class=\"btn-help btn-help--sm m-r-8\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"legendHelpTemplate\"\n placement=\"bottom\"\n triggers=\"focus\"\n container=\"body\"\n [adaptivePosition]=\"false\"\n ></button>\n <div class=\"inner-scroll\">\n <div class=\"flex-grow p-t-8 d-flex a-i-start gap-8 p-b-4\">\n <div\n class=\"c8y-datapoint-pill flex-no-shrink\"\n title=\"{{ datapoint.label }} - {{ datapoint.__target.name }}\"\n *ngFor=\"let datapoint of displayConfig.datapoints\"\n [ngClass]=\"{ active: datapoint.__active }\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"'At least 1 active data points must be active.' | translate\"\n container=\"body\"\n *ngIf=\"!hasAtLeastOneDatapointActive && datapoint.__active\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-datapoint-pill__btn\"\n title=\"{{\n (datapoint.__active ? hideDatapointLabel : showDatapointLabel) | translate\n }} \"\n type=\"button\"\n (click)=\"toggleChart(datapoint)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"datapoint.__active ? 'eye text-primary' : 'eye-slash text-muted'\"\n ></i>\n </button>\n <div class=\"c8y-datapoint-pill__label c8y-datapoint-pill__btn\">\n <i\n class=\"m-r-4 icon-14\"\n c8yIcon=\"circle\"\n [ngStyle]=\"{\n color: datapoint.color\n }\"\n ></i>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': !datapoint.__active }\"\n >\n <span class=\"text-truncate\">\n {{ datapoint.label }}\n </span>\n <small class=\"text-muted text-10\">\n {{ datapoint.__target.name }}\n </small>\n </span>\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Measurements received for this data point may be out of sync.' | translate\n \"\n container=\"body\"\n *ngIf=\"datapointsOutOfSync.get(datapoint)\"\n [adaptivePosition]=\"false\"\n ></i>\n </div>\n </div>\n <!-- Alarms -->\n\n <ng-container *ngFor=\"let alarm of alarms\">\n <div\n class=\"c8y-alarm-pill flex-no-shrink\"\n title=\"{{ alarm.filters.type }} \"\n *ngIf=\"alarm.__active\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Alarm of this type is currently active and outside of the selected time range'\n | translate\n \"\n container=\"body\"\n *ngIf=\"displayConfig?.activeAlarmTypesOutOfRange?.includes(alarm.filters.type)\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-alarm-pill__btn\"\n title=\"{{ alarm.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(alarm)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"alarm.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <button\n class=\"c8y-alarm-pill__label c8y-alarm-pill__btn\"\n (click)=\"toggleMarkedArea(alarm)\"\n [ngClass]=\"{\n active: !isMarkedAreaEnabled && alarm.filters.type === enabledMarkedAreaAlarmType\n }\"\n >\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [style.background-color]=\"alarm.color\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"bell\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': alarm.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ alarm.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ alarm.__target.name }}\n </small>\n </span>\n </button>\n </div>\n </ng-container>\n\n <!-- Events -->\n <ng-container *ngFor=\"let event of events\">\n <div\n class=\"c8y-event-pill flex-no-shrink\"\n title=\"{{ event.filters.type }}\"\n *ngIf=\"event.__active\"\n >\n <button\n class=\"c8y-event-pill__btn\"\n title=\"{{ event.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(event)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"event.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <div class=\"c8y-event-pill__label c8y-event-pill__btn\">\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [ngStyle]=\"{ 'background-color': event.color }\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"c8y-events\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': event.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ event.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ event.__target.name }}\n </small>\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-charts\n #chart\n [config]=\"displayConfig\"\n [alerts]=\"alerts\"\n (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n (configChangeOnZoomOut)=\"updateDashboardTimeContext($event)\"\n (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n></c8y-charts>\n\n<ng-template #legendHelpTemplate>\n <div [innerHTML]=\"legendHelp\"></div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ChartsComponent, selector: "c8y-charts", inputs: ["config", "alerts"], outputs: ["configChangeOnZoomOut", "timeRangeChangeOnRealtime", "datapointOutOfSync", "updateAlarmsAndEvents", "isMarkedAreaEnabled"] }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i7.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "ngmodule", type: AlarmsModule }, { kind: "component", type: i8.AlarmsFilterComponent, selector: "c8y-alarms-filter", inputs: ["contextSourceId"], outputs: ["onFilterApplied"] }, { kind: "component", type: TimeContextComponent, selector: "c8y-time-context", inputs: ["changedDateContext", "controlsAvailable", "context"], outputs: ["contextChange"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatapointsGraphWidgetViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-datapoints-graph-widget-view', standalone: true, imports: [
A11yModule,
CommonModule,
ChartsComponent,
CoreModule,
TooltipModule,
BsDropdownModule,
PopoverModule,
AlarmsModule,
TimeContextComponent
], providers: [ChartEventsService, ChartAlarmsService], template: "<div class=\"p-l-16 p-r-16\">\n <div class=\"d-flex gap-16 a-i-start\">\n <div\n class=\"btn-group btn-group-sm flex-no-shrink\"\n *ngIf=\"!displayConfig?.widgetInstanceGlobalTimeContext\"\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Aggregation' | translate\"\n tooltip=\"{{\n (displayConfig?.aggregation\n ? AGGREGATION_TEXTS[displayConfig.aggregation]\n : AGGREGATION_TEXTS.undefined\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n displayConfig?.aggregation\n ? AGGREGATION_ICONS[displayConfig.aggregation]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n </button>\n\n <c8y-time-context\n class=\"d-contents\"\n (contextChange)=\"timePropsChanged($event)\"\n [changedDateContext]=\"timeProps\"\n [controlsAvailable]=\"{\n realtime: true,\n timeRange: displayConfig?.displayDateSelection,\n interval: displayConfig?.displayDateSelection,\n aggregation: displayConfig?.displayAggregationSelection\n }\"\n ></c8y-time-context>\n </div>\n <c8y-alarms-filter\n class=\"d-contents form-group-sm\"\n *ngIf=\"hasAtLeastOneAlarmActive\"\n (filterApplied)=\"filterSeverity($event)\"\n ></c8y-alarms-filter>\n\n <div class=\"m-l-auto btn-group btn-group-sm flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Save as image' | translate\"\n tooltip=\"{{ 'Save as image' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"chart.saveAsImage()\"\n [adaptivePosition]=\"false\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"image-file-checked\"\n ></i>\n </button>\n </div>\n </div>\n <div\n class=\"d-flex\"\n style=\"align-items: center\"\n >\n <button\n class=\"btn-help btn-help--sm m-r-8\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"legendHelpTemplate\"\n placement=\"bottom\"\n triggers=\"focus\"\n container=\"body\"\n [adaptivePosition]=\"false\"\n ></button>\n <div class=\"inner-scroll\">\n <div class=\"flex-grow p-t-8 d-flex a-i-start gap-8 p-b-4\">\n <div\n class=\"c8y-datapoint-pill flex-no-shrink\"\n title=\"{{ datapoint.label }} - {{ datapoint.__target.name }}\"\n *ngFor=\"let datapoint of displayConfig.datapoints\"\n [ngClass]=\"{ active: datapoint.__active }\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"'At least 1 active data points must be active.' | translate\"\n container=\"body\"\n *ngIf=\"!hasAtLeastOneDatapointActive && datapoint.__active\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-datapoint-pill__btn\"\n title=\"{{\n (datapoint.__active ? hideDatapointLabel : showDatapointLabel) | translate\n }} \"\n type=\"button\"\n (click)=\"toggleChart(datapoint)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"datapoint.__active ? 'eye text-primary' : 'eye-slash text-muted'\"\n ></i>\n </button>\n <div class=\"c8y-datapoint-pill__label c8y-datapoint-pill__btn\">\n <i\n class=\"m-r-4 icon-14\"\n c8yIcon=\"circle\"\n [ngStyle]=\"{\n color: datapoint.color\n }\"\n ></i>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': !datapoint.__active }\"\n >\n <span class=\"text-truncate\">\n {{ datapoint.label }}\n </span>\n <small class=\"text-muted text-10\">\n {{ datapoint.__target.name }}\n </small>\n </span>\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Measurements received for this data point may be out of sync.' | translate\n \"\n container=\"body\"\n *ngIf=\"datapointsOutOfSync.get(datapoint)\"\n [adaptivePosition]=\"false\"\n ></i>\n </div>\n </div>\n <!-- Alarms -->\n\n <ng-container *ngFor=\"let alarm of alarms\">\n <div\n class=\"c8y-alarm-pill flex-no-shrink\"\n title=\"{{ alarm.filters.type }} \"\n *ngIf=\"alarm.__active\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Alarm of this type is currently active and outside of the selected time range'\n | translate\n \"\n container=\"body\"\n *ngIf=\"displayConfig?.activeAlarmTypesOutOfRange?.includes(alarm.filters.type)\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-alarm-pill__btn\"\n title=\"{{ alarm.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(alarm)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"alarm.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <button\n class=\"c8y-alarm-pill__label c8y-alarm-pill__btn\"\n (click)=\"toggleMarkedArea(alarm)\"\n [ngClass]=\"{\n active: !isMarkedAreaEnabled && alarm.filters.type === enabledMarkedAreaAlarmType\n }\"\n >\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [style.background-color]=\"alarm.color\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"bell\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': alarm.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ alarm.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ alarm.__target.name }}\n </small>\n </span>\n </button>\n </div>\n </ng-container>\n\n <!-- Events -->\n <ng-container *ngFor=\"let event of events\">\n <div\n class=\"c8y-event-pill flex-no-shrink\"\n title=\"{{ event.filters.type }}\"\n *ngIf=\"event.__active\"\n >\n <button\n class=\"c8y-event-pill__btn\"\n title=\"{{ event.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(event)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"event.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <div class=\"c8y-event-pill__label c8y-event-pill__btn\">\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [ngStyle]=\"{ 'background-color': event.color }\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"c8y-events\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': event.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ event.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ event.__target.name }}\n </small>\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-charts\n #chart\n [config]=\"displayConfig\"\n [alerts]=\"alerts\"\n (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n (configChangeOnZoomOut)=\"updateDashboardTimeContext($event)\"\n (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n></c8y-charts>\n\n<ng-template #legendHelpTemplate>\n <div [innerHTML]=\"legendHelp\"></div>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.TranslateService }, { type: i3.WidgetTimeContextDateRangeService }, { type: i4.ContextDashboardComponent, decorators: [{
type: Optional
}] }], propDecorators: { config: [{
type: Input
}], chartComponent: [{
type: ViewChild,
args: [ChartsComponent]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXBvaW50cy1ncmFwaC13aWRnZXQtdmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi93aWRnZXRzL2ltcGxlbWVudGF0aW9ucy9kYXRhcG9pbnRzLWdyYXBoL2RhdGFwb2ludHMtZ3JhcGgtdmlldy9kYXRhcG9pbnRzLWdyYXBoLXdpZGdldC12aWV3LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2RhdGFwb2ludHMtZ3JhcGgvZGF0YXBvaW50cy1ncmFwaC12aWV3L2RhdGFwb2ludHMtZ3JhcGgtd2lkZ2V0LXZpZXcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxLQUFLLEVBR0wsUUFBUSxFQUVSLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNqQixVQUFVLEVBRVYsT0FBTyxFQUNQLGlDQUFpQyxFQUNsQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUNMLG1CQUFtQixFQUlwQixNQUFNLGFBQWEsQ0FBQztBQUVyQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNsRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFD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S0FBSyxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLCtCQUErQixFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztTQUM3QyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDOytHQXhPVSxrQ0FBa0M7bUdBQWxDLGtDQUFrQyw2R0FGbEMsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsQ0FBQywwRUEyQnhDLGVBQWUscUVDOUY1Qix5MVJBcVFBLDJDRDVNSSxVQUFVLDhCQUNWLFlBQVksbWJBQ1osZUFBZSwyTkFDZixVQUFVLHlMQUNWLGFBQWEsaWtCQUNiLGdCQUFnQiw4QkFDaEIsYUFBYSw4VkFDYixZQUFZLGdMQUNaLG9CQUFvQjs7NEZBSVgsa0NBQWtDO2tCQWpCOUMsU0FBUzsrQkFDRSxrQ0FBa0MsY0FFaEMsSUFBSSxXQUNQO3dCQUNQLFVBQVU7d0JBQ1YsWUFBWTt3QkFDWixlQUFlO3dCQUNmLFVBQVU7d0JBQ1YsYUFBYTt3QkFDYixnQkFBZ0I7d0JBQ2hCLGFBQWE7d0JBQ2IsWUFBWTt3QkFDWixvQkFBb0I7cUJBQ3JCLGFBQ1UsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsQ0FBQzs7MEJBc0RoRCxRQUFRO3lDQW5DRSxNQUFNO3NCQUFsQixLQUFLO2dCQVFzQixjQUFjO3NCQUF6QyxTQUFTO3VCQUFDLGVBQWUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT3B0aW9uYWwsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFHR1JFR0FUSU9OX0lDT05TLFxuICBBR0dSRUdBVElPTl9URVhUUyxcbiAgQ29yZU1vZHVsZSxcbiAgRHluYW1pY0NvbXBvbmVudEFsZXJ0QWdncmVnYXRvcixcbiAgZ2V0dGV4dCxcbiAgV2lkZ2V0VGltZUNvbnRleHREYXRlUmFuZ2VTZXJ2aWNlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEZvcm1CdWlsZGVyLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtcbiAgQUxBUk1fU1RBVFVTX0xBQkVMUyxcbiAgQWxhcm1TdGF0dXNUeXBlLFxuICBTZXZlcml0eVNldHRpbmdzLFxuICBhZ2dyZWdhdGlvblR5cGVcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHR5cGUgeyBLUElEZXRhaWxzIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9kYXRhcG9pbnQtc2VsZWN0b3InO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgQ29udGV4dERhc2hib2FyZENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvY29udGV4dC1kYXNoYm9hcmQnO1xuaW1wb3J0IHsgQTExeU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9hMTF5JztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBDaGFydHNDb21wb25lbnQsXG4gIERhdGFwb2ludHNHcmFwaEtQSURldGFpbHMsXG4gIERhdGFwb2ludHNHcmFwaFdpZGdldENvbmZpZyxcbiAgRGF0YXBvaW50c0dyYXBoV2lkZ2V0VGltZVByb3BzLFxuICBTZXZlcml0eVR5cGUsXG4gIEFsYXJtRGV0YWlsc0V4dGVuZGVkLFxuICBBbGFybU9yRXZlbnRFeHRlbmRlZCxcbiAgRXZlbnREZXRhaWxzRXh0ZW5kZWQsXG4gIENoYXJ0RXZlbnRzU2VydmljZSxcbiAgQ2hhcnRBbGFybXNTZXJ2aWNlLFxuICBUaW1lQ29udGV4dFByb3BzXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvZWNoYXJ0JztcbmltcG9ydCB7IFRvb2x0aXBNb2R1bGUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL3Rvb2x0aXAnO1xuaW1wb3J0IHsgQnNEcm9wZG93bk1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvZHJvcGRvd24nO1xuaW1wb3J0IHsgUG9wb3Zlck1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvcG9wb3Zlcic7XG5pbXBvcnQgeyBBbGFybXNNb2R1bGUgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2FsYXJtcyc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUaW1lQ29udGV4dENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvdGltZS1jb250ZXh0JztcbmltcG9ydCB7IEludGVydmFsIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9pbnRlcnZhbC1waWNrZXInO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktZGF0YXBvaW50cy1ncmFwaC13aWRnZXQtdmlldycsXG4gIHRlbXBsYXRlVXJsOiAnLi9kYXRhcG9pbnRzLWdyYXBoLXdpZGdldC12aWV3LmNvbXBvbmVudC5odG1sJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIEExMXlNb2R1bGUsXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIENoYXJ0c0NvbXBvbmVudCxcbiAgICBDb3JlTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gICAgQnNEcm9wZG93bk1vZHVsZSxcbiAgICBQb3BvdmVyTW9kdWxlLFxuICAgIEFsYXJtc01vZHVsZSxcbiAgICBUaW1lQ29udGV4dENvbXBvbmVudFxuICBdLFxuICBwcm92aWRlcnM6IFtDaGFydEV2ZW50c1NlcnZpY2UsIENoYXJ0QWxhcm1zU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgRGF0YXBvaW50c0dyYXBoV2lkZ2V0Vmlld0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgZXZlbnRzOiBFdmVudERldGFpbHNFeHRlbmRlZFtdID0gW107XG4gIGFsYXJtczogQWxhcm1EZXRhaWxzRXh0ZW5kZWRbXSA9IFtdO1xuICBBR0dSRUdBVElPTl9JQ09OUyA9IEFHR1JFR0FUSU9OX0lDT05TO1xuICBBR0dSRUdBVElPTl9URVhUUyA9IEFHR1JFR0FUSU9OX1RFWFRTO1xuICBhbGVydHM6IER5bmFtaWNDb21wb25lbnRBbGVydEFnZ3JlZ2F0b3IgfCB1bmRlZmluZWQ7XG4gIGRhdGFwb2ludHNPdXRPZlN5bmMgPSBuZXcgTWFwPERhdGFwb2ludHNHcmFwaEtQSURldGFpbHMsIGJvb2xlYW4+KCk7XG4gIHRpbWVQcm9wczogRGF0YXBvaW50c0dyYXBoV2lkZ2V0VGltZVByb3BzIHwgdW5kZWZpbmVkO1xuICBoYXNBdExlYXN0T25lRGF0YXBvaW50QWN0aXZlID0gdHJ1ZTtcbiAgaGFzQXRMZWFzdE9uZUFsYXJtQWN0aXZlID0gdHJ1ZTtcbiAgdGltZUNvbnRyb2xzRm9ybUdyb3VwOiBSZXR1cm5UeXBlPERhdGFwb2ludHNHcmFwaFdpZGdldFZpZXdDb21wb25lbnRbJ2luaXRGb3JtJ10+O1xuICBpc01hcmtlZEFyZWFFbmFibGVkID0gZmFsc2U7XG4gIC8qXG4gICAqIEBkZXNjcmlwdGlvbjogVGhlIHR5cGUgb2YgYWxhcm0gdGhhdCBoYXMgbWFya2VkIGFyZWEgZW5hYmxlZC5cbiAgICovXG4gIGVuYWJsZWRNYXJrZWRBcmVhQWxhcm1UeXBlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgQElucHV0KCkgc2V0IGNvbmZpZyh2YWx1ZTogRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnKSB7XG4gICAgdGhpcy5kaXNwbGF5Q29uZmlnID0gY2xvbmVEZWVwKHZhbHVlKTtcbiAgfVxuICBnZXQgY29uZmlnKCk6IG5ldmVyIHtcbiAgICB0aHJvdyBFcnJvcihcbiAgICAgICdcImNvbmZpZ1wiIHByb3BlcnR5IHNob3VsZCBub3QgYmUgcmVmZXJlbmNlZCBpbiB2aWV3IGNvbXBvbmVudCB0byBhdm9pZCBtdXRhdGluZyBkYXRhLidcbiAgICApO1xuICB9XG4gIEBWaWV3Q2hpbGQoQ2hhcnRzQ29tcG9uZW50KSBjaGFydENvbXBvbmVudCE6IENoYXJ0c0NvbXBvbmVudDtcbiAgZGlzcGxheUNvbmZpZzogRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnIHwgdW5kZWZpbmVkO1xuICBsZWdlbmRIZWxwID0gdGhpcy50cmFuc2xhdGUuaW5zdGFudChcbiAgICBnZXR0ZXh0KGA8dWwgY2xhc3M9XCJtLWwtMCBwLWwtOCBtLXQtOCBtLWItMFwiPlxuICAgIDxsaT5cbiAgICAgIDxiPlZpc2liaWxpdHk6PC9iPlxuICAgICAgdXNlIHZpc2liaWxpdHkgaWNvbiB0byB0b2dnbGUgZGF0YXBvaW50LCBhbGFybSBvciBldmVudCB2aXNpYmlsaXR5IG9uIGNoYXJ0LiBBdCBsZWFzdCBvbmUgZGF0YXBvaW50IGlzIHJlcXVpcmVkIHRvIGRpc3BsYXkgY2hhcnQuXG4gICAgPC9saT5cbiAgICA8bGk+XG4gICAgICA8Yj5BbGFybSBkZXRhaWxzPC9iPlxuICAgICAgQ2xpY2sgYWxhcm0gbGVnZW5kIGl0ZW0gdG8gaGlnaGxpZ2h0IGFyZWEgYmV0d2VlbiBhbGFybSByYWlzZWQgdGltZXN0YW1wIGFuZCBhbGFybSBjbGVhcmVkIHRpbWVzdGFtcC5cbiAgICAgIFlvdSBjYW4gYWxzbyBjbGljayBhbGFybSBtYXJrbGluZSBvbiBjaGFydCB0byBoaWdobGlnaHQgYWxhcm0gYW5kIHRvIHBhdXNlIHRvb2x0aXAuIENsaWNrIG9uIGhpZ2hsaWdodGVkIGFyZWEgb3IgbGVnZW5kIGl0ZW0gdG8gY2FuY2VsIGhpZ2hsaWdodGluZy5cbiAgICA8L2xpPlxuICA8L3VsPmApXG4gICk7XG4gIHJlYWRvbmx5IGRpc2FibGVab29tSW5MYWJlbCA9IGdldHRleHQoJ0Rpc2FibGUgem9vbSBpbicpO1xuICByZWFkb25seSBlbmFibGVab29tSW5MYWJlbCA9IGdldHRleHQoXG4gICAgJ0NsaWNrIHRvIGVuYWJsZSB6b29tLCB0aGVuIGNsaWNrIGFuZCBkcmFnIG9uIHRoZSBkZXNpcmVkIGFyZWEgaW4gdGhlIGNoYXJ0LidcbiAgKTtcbiAgcmVhZG9ubHkgaGlkZURhdGFwb2ludExhYmVsID0gZ2V0dGV4dCgnSGlkZSBkYXRhIHBvaW50Jyk7XG4gIHJlYWRvbmx5IHNob3dEYXRhcG9pbnRMYWJlbCA9IGdldHRleHQoJ1Nob3cgZGF0YSBwb2ludCcpO1xuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIHdpZGdldFRpbWVDb250ZXh0RGF0ZVJhbmdlU2VydmljZTogV2lkZ2V0VGltZUNvbnRleHREYXRlUmFuZ2VTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgZGFzaGJvYXJkQ29udGV4dENvbXBvbmVudDogQ29udGV4dERhc2hib2FyZENvbXBvbmVudFxuICApIHtcbiAgICB0aGlzLnRpbWVDb250cm9sc0Zvcm1Hcm91cCA9IHRoaXMuaW5pdEZvcm0oKTtcbiAgICB0aGlzLnRpbWVDb250cm9sc0Zvcm1Hcm91cC52YWx1ZUNoYW5nZXMucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZSh2YWx1ZSA9PiB7XG4gICAgICB0aGlzL