@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
555 lines (546 loc) • 112 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, forwardRef, Input, Component, EventEmitter, Output, Pipe, ContentChild, Optional, NgModule, signal, computed, inject } from '@angular/core';
import * as i1 from '@angular/forms';
import { FormControl, Validators, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, NgForm, ControlContainer } from '@angular/forms';
import { take, takeUntil, map, startWith, tap, switchMap, shareReplay, distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { NgIf, NgFor, NgClass, AsyncPipe } from '@angular/common';
import * as i2 from '@c8y/ngx-components';
import { FormGroupComponent, RequiredInputPlaceholderDirective, MessagesComponent, MessageDirective, C8yTranslatePipe, IconDirective, ListItemComponent, ListItemDragHandleComponent, ListItemCheckboxComponent, HighlightComponent, ListItemCollapseComponent, EmptyStateComponent, LoadingComponent, ListGroupComponent, C8yTranslateDirective, ViewContext, CommonModule, CoreModule } from '@c8y/ngx-components';
import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle, DragDropModule } from '@angular/cdk/drag-drop';
import * as i6 from '@c8y/ngx-components/context-dashboard';
import { WidgetConfigService, WidgetConfigFeedbackComponent } from '@c8y/ngx-components/context-dashboard';
import * as i1$2 from 'ngx-bootstrap/modal';
import { MillerViewComponent, AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
import { Subject, BehaviorSubject, combineLatest } from 'rxjs';
import * as i1$1 from '@c8y/client';
import { uniqBy } from 'lodash-es';
import { gettext } from '@c8y/ngx-components/gettext';
import { CollapseDirective, CollapseModule } from 'ngx-bootstrap/collapse';
import { PopoverDirective, PopoverModule } from 'ngx-bootstrap/popover';
import * as i2$1 from 'ngx-bootstrap/tooltip';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import * as i4 from '@angular/router';
import { RouterModule } from '@angular/router';
class AlarmEventAttributesFormService {
duplicateTypeValidator(selectedItems) {
return (control) => {
if (!control.value || !selectedItems?.length) {
return null;
}
const isDuplicate = selectedItems.some(item => item.filters?.type?.toLowerCase() === control.value.toLowerCase());
return isDuplicate ? { duplicateType: true } : null;
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventAttributesFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventAttributesFormService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventAttributesFormService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class AlarmEventAttributesFormComponent {
constructor(formBuilder, alarmEventAttributesFormService) {
this.formBuilder = formBuilder;
this.alarmEventAttributesFormService = alarmEventAttributesFormService;
this.omitProperties = {};
this.selectedItems = [];
this.datapoints = [];
}
ngOnInit() {
this.formGroup = this.formBuilder.group({
filters: this.formBuilder.group({
type: new FormControl('', [
Validators.required,
this.alarmEventAttributesFormService.duplicateTypeValidator(this.selectedItems)
])
}),
timelineType: new FormControl(''),
selectedDatapoint: new FormControl(null)
});
if (!this.omitProperties.label) {
this.formGroup.addControl('label', new FormControl('', Validators.required));
}
if (this.datapoints?.length > 0) {
this.filterKpis();
}
}
validate(_control) {
return this.formGroup?.valid ? null : { formInvalid: {} };
}
writeValue(obj) {
this.formGroup.patchValue(obj);
}
registerOnChange(fn) {
this.formGroup.valueChanges.subscribe(fn);
}
registerOnTouched(fn) {
this.formGroup.valueChanges.pipe(take(1)).subscribe(fn);
}
setDisabledState(isDisabled) {
isDisabled ? this.formGroup.disable() : this.formGroup.enable();
}
changeDatapointSelection(event) {
const selectElement = event.target;
const selectedIndex = selectElement.selectedIndex;
const selectedDatapoint = this.datapoints[selectedIndex];
const trimmedDatapoint = {
target: selectedDatapoint.__target.id,
fragment: selectedDatapoint.fragment,
series: selectedDatapoint.series
};
this.formGroup.patchValue({ selectedDatapoint: trimmedDatapoint });
}
trackByFn(_index, item) {
return `${item.fragment}-${item.series}-${item.__target?.id}`;
}
filterKpis() {
if (this.target && this.target.id) {
this.datapoints = this.datapoints.filter(dp => dp.__target?.id === this.target.id);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventAttributesFormComponent, deps: [{ token: i1.FormBuilder }, { token: AlarmEventAttributesFormService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: AlarmEventAttributesFormComponent, isStandalone: true, selector: "c8y-alarm-event-attributes-form", inputs: { timelineType: "timelineType", omitProperties: "omitProperties", selectedItems: "selectedItems", target: "target", datapoints: "datapoints" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AlarmEventAttributesFormComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AlarmEventAttributesFormComponent),
multi: true
}
], ngImport: i0, template: "<div [formGroup]=\"formGroup\">\n <c8y-form-group\n class=\"form-group-sm\"\n *ngIf=\"formGroup.controls.label\"\n >\n <label class=\"m-0\">{{ 'Label' | translate }}</label>\n <input\n class=\"form-control flex-grow\"\n name=\"label\"\n formControlName=\"label\"\n [placeholder]=\"\n 'e.g. {{ example }}'\n | translate\n : {\n example: timelineType === 'ALARM' ? 'Unavailability alarm' : 'Location update'\n }\n \"\n />\n </c8y-form-group>\n\n <div formGroupName=\"filters\">\n <c8y-form-group class=\"form-group-sm\">\n <label class=\"m-0\">{{ 'Type' | translate }}</label>\n <input\n class=\"form-control flex-grow\"\n name=\"type\"\n formControlName=\"type\"\n [placeholder]=\"\n 'e.g. {{ example }}'\n | translate\n : {\n example:\n timelineType === 'ALARM' ? 'c8y_UnavailabilityAlarm' : 'c8y_LocationUpdate'\n }\n \"\n />\n <c8y-messages>\n <c8y-message\n name=\"duplicateType\"\n [text]=\"'Type already used.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <c8y-form-group\n class=\"form-group-sm\"\n *ngIf=\"datapoints?.length > 0\"\n >\n <label>{{ 'Select data point' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control input-sm\"\n (change)=\"changeDatapointSelection($event)\"\n >\n <option\n *ngFor=\"let datapoint of datapoints; trackBy: trackByFn\"\n [ngValue]=\"{\n target: datapoint.__target.id,\n fragment: datapoint.fragment,\n series: datapoint.series\n }\"\n [selected]=\"\n datapoint.__target.id === formGroup.value.selectedDatapoint?.target &&\n datapoint.fragment === formGroup.value.selectedDatapoint?.fragment &&\n datapoint.series === formGroup.value.selectedDatapoint?.series\n \"\n >\n {{ datapoint?.label }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventAttributesFormComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-alarm-event-attributes-form', providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AlarmEventAttributesFormComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AlarmEventAttributesFormComponent),
multi: true
}
], imports: [
FormsModule,
ReactiveFormsModule,
NgIf,
FormGroupComponent,
RequiredInputPlaceholderDirective,
MessagesComponent,
MessageDirective,
NgFor,
C8yTranslatePipe
], template: "<div [formGroup]=\"formGroup\">\n <c8y-form-group\n class=\"form-group-sm\"\n *ngIf=\"formGroup.controls.label\"\n >\n <label class=\"m-0\">{{ 'Label' | translate }}</label>\n <input\n class=\"form-control flex-grow\"\n name=\"label\"\n formControlName=\"label\"\n [placeholder]=\"\n 'e.g. {{ example }}'\n | translate\n : {\n example: timelineType === 'ALARM' ? 'Unavailability alarm' : 'Location update'\n }\n \"\n />\n </c8y-form-group>\n\n <div formGroupName=\"filters\">\n <c8y-form-group class=\"form-group-sm\">\n <label class=\"m-0\">{{ 'Type' | translate }}</label>\n <input\n class=\"form-control flex-grow\"\n name=\"type\"\n formControlName=\"type\"\n [placeholder]=\"\n 'e.g. {{ example }}'\n | translate\n : {\n example:\n timelineType === 'ALARM' ? 'c8y_UnavailabilityAlarm' : 'c8y_LocationUpdate'\n }\n \"\n />\n <c8y-messages>\n <c8y-message\n name=\"duplicateType\"\n [text]=\"'Type already used.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <c8y-form-group\n class=\"form-group-sm\"\n *ngIf=\"datapoints?.length > 0\"\n >\n <label>{{ 'Select data point' | translate }}</label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control input-sm\"\n (change)=\"changeDatapointSelection($event)\"\n >\n <option\n *ngFor=\"let datapoint of datapoints; trackBy: trackByFn\"\n [ngValue]=\"{\n target: datapoint.__target.id,\n fragment: datapoint.fragment,\n series: datapoint.series\n }\"\n [selected]=\"\n datapoint.__target.id === formGroup.value.selectedDatapoint?.target &&\n datapoint.fragment === formGroup.value.selectedDatapoint?.fragment &&\n datapoint.series === formGroup.value.selectedDatapoint?.series\n \"\n >\n {{ datapoint?.label }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: AlarmEventAttributesFormService }], propDecorators: { timelineType: [{
type: Input
}], omitProperties: [{
type: Input
}], selectedItems: [{
type: Input
}], target: [{
type: Input
}], datapoints: [{
type: Input
}] } });
const EVENT_TEXTS = {
listTitle: gettext('Events'),
emptyStateIcon: 'online1',
emptyStateTitle: gettext('No events to display.'),
emptyStateSubtitle: gettext('Add your first event.'),
addButtonLabel: gettext('Add event'),
addCustomItemButtonLabel: gettext('Add custom event'),
selectorTitle: gettext('Events selector'),
availableItemsTitle: gettext('Available events'),
assetWithNoItemsEmptyStateSubtitle: gettext('Select an asset with events from the list.'),
largeNumberOfItemsInfo: gettext('Due to the large number, only a subset of events are displayed. Use search to narrow down the number of results.'),
selectedItemsTitle: gettext('Selected events'),
noSelectedItemsTitle: gettext('No events selected.'),
recentItemsWarningTitle: gettext('The list below may not be complete.'),
recentItemsWarningText: gettext('Recent events are displayed below. Past events might not be shown.'),
addCustomText: gettext('Optionally you can add a custom event.')
};
const ALARM_TEXTS = {
listTitle: gettext('Alarms'),
emptyStateIcon: 'c8y-alarm',
emptyStateTitle: gettext('No alarms to display.'),
emptyStateSubtitle: gettext('Add your first alarm.'),
addButtonLabel: gettext('Add alarm'),
addCustomItemButtonLabel: gettext('Add custom alarm'),
selectorTitle: gettext('Alarms selector'),
availableItemsTitle: gettext('Available alarms'),
assetWithNoItemsEmptyStateSubtitle: gettext('Select an asset with alarms from the list.'),
largeNumberOfItemsInfo: gettext('Due to the large number, only a subset of alarms are displayed. Use search to narrow down the number of results.'),
selectedItemsTitle: gettext('Selected alarms'),
noSelectedItemsTitle: gettext('No alarms selected.'),
recentItemsWarningTitle: gettext('The list below may not be complete.'),
recentItemsWarningText: gettext('Recent alarms are displayed below but older ones may not be shown.'),
addCustomText: gettext('Optionally, you can add a custom alarm.')
};
class AlarmEventSelectorService {
constructor(alarmService, eventsService, color) {
this.alarmService = alarmService;
this.eventsService = eventsService;
this.color = color;
this.timelineTypeTextsMap = new Map([
['ALARM', ALARM_TEXTS],
['EVENT', EVENT_TEXTS]
]);
}
/**
* This method returns the texts for the timeline type.
* @param timelineType The timeline type.
* @returns The texts for the timeline type.
*/
timelineTypeTexts(timelineType) {
return this.timelineTypeTextsMap.get(timelineType);
}
/**
* This method returns all alarms or events of the platform based on the timeline type
* @param timelineType The timeline type.
* @returns The alarms or events of the asset.
*/
async getItems(timelineType) {
const filters = {
pageSize: 1000
};
return timelineType === 'ALARM'
? await this.getAlarmsOfAsset(filters)
: await this.getEventsOfAsset(filters);
}
/**
* This method returns the items of the asset based on the timeline type.
* @param parentReference The parent reference.
* @param timelineType The timeline type.
* @returns The alarms or events of the asset.
*/
async getAlarmsOrEvents(parentReference, timelineType) {
const filters = { source: parentReference.id, pageSize: 1000 };
return timelineType === 'ALARM'
? await this.getAlarmsOfAsset(filters)
: await this.getEventsOfAsset(filters);
}
async getUniqueAlarmsOnly(data) {
return Promise.all(uniqBy(data, 'type').map(async (alarm) => this.createItem('ALARM', alarm)));
}
async getUniqueEventsOnly(data) {
return Promise.all(uniqBy(data, 'type').map(async (event) => this.createItem('EVENT', event)));
}
async createItem(timelineType, item) {
const color = await this.color.generateColor(item.type);
if (item.source && !item.source.name) {
item.source.name = `Device ${item.source.id}`;
}
return {
timelineType,
color,
label: item.type,
filters: {
type: item.type
},
__target: item.source
};
}
async getAlarmsOfAsset(filters) {
const res = await this.alarmService.list({
...filters,
withSourceAssets: !!filters.source,
withSourceDevices: !!filters.source,
pageSize: 1000
});
const alarms = await this.getUniqueAlarmsOnly(res.data);
return alarms;
}
async getEventsOfAsset(filters) {
const res = await this.eventsService.list(filters);
const events = this.getUniqueEventsOnly(res.data);
return events;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventSelectorService, deps: [{ token: i1$1.AlarmService }, { token: i1$1.EventService }, { token: i2.ColorService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventSelectorService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventSelectorService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1$1.AlarmService }, { type: i1$1.EventService }, { type: i2.ColorService }] });
class CustomAlarmEventFormComponent {
constructor(formBuilder) {
this.formBuilder = formBuilder;
this.omitProperties = {};
this.selectedItems = [];
this.added = new EventEmitter();
this.cancel = new EventEmitter();
this.destroy$ = new Subject();
this.formGroup = this.formBuilder.group({
details: [],
color: [],
__active: [],
__target: []
});
this.valid$ = this.formGroup.statusChanges.pipe(takeUntil(this.destroy$), map(val => val === 'VALID'), startWith(false));
}
ngOnInit() {
this.formGroup.patchValue({
color: this.defaultColor,
__target: this.target,
details: { timelineType: this.timelineType }
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
add() {
if (this.formGroup.valid) {
const formValue = this.transformFormValue(this.formGroup.value);
this.added.emit(formValue);
}
}
transformFormValue(formValue) {
const obj = Object.assign({}, formValue.details || {}, formValue);
delete obj.details;
return obj;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomAlarmEventFormComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: CustomAlarmEventFormComponent, isStandalone: true, selector: "c8y-custom-alarm-event-form", inputs: { timelineType: "timelineType", target: "target", omitProperties: "omitProperties", selectedItems: "selectedItems", defaultColor: "defaultColor" }, outputs: { added: "added", cancel: "cancel" }, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"p-16\">\n <div\n *ngIf=\"!omitProperties.color\"\n class=\"form-group d-flex a-i-center gap-8\"\n [title]=\"'Change color' | translate\"\n >\n <label class=\"m-0\">{{ 'Color' | translate }}</label>\n <div class=\"c8y-colorpicker\"\n [ngClass]=\"{\n 'c8y-colorpicker--event': timelineType === 'EVENT',\n 'c8y-colorpicker--alarm': timelineType !== 'EVENT'\n }\"\n >\n <input\n type=\"color\"\n formControlName=\"color\"\n (click)=\"$event.stopPropagation()\"\n />\n <span [style.background-color]=\"formGroup.value.color\">\n <i [c8yIcon]=\"timelineType === 'EVENT' ? 'online1' : 'bell'\"></i>\n </span>\n </div>\n </div>\n\n <c8y-alarm-event-attributes-form\n formControlName=\"details\"\n [timelineType]=\"timelineType\"\n [omitProperties]=\"omitProperties\"\n [selectedItems]=\"selectedItems\"\n ></c8y-alarm-event-attributes-form>\n\n <div class=\"d-flex p-t-16 gap-8\">\n <button class=\"btn btn-default btn-sm\" (click)=\"cancel.emit()\">\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n [disabled]=\"(valid$ | async) === false\"\n (click)=\"add()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Select' | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: AlarmEventAttributesFormComponent, selector: "c8y-alarm-event-attributes-form", inputs: ["timelineType", "omitProperties", "selectedItems", "target", "datapoints"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomAlarmEventFormComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-custom-alarm-event-form', imports: [
FormsModule,
ReactiveFormsModule,
NgIf,
NgClass,
RequiredInputPlaceholderDirective,
IconDirective,
AlarmEventAttributesFormComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<form [formGroup]=\"formGroup\" class=\"p-16\">\n <div\n *ngIf=\"!omitProperties.color\"\n class=\"form-group d-flex a-i-center gap-8\"\n [title]=\"'Change color' | translate\"\n >\n <label class=\"m-0\">{{ 'Color' | translate }}</label>\n <div class=\"c8y-colorpicker\"\n [ngClass]=\"{\n 'c8y-colorpicker--event': timelineType === 'EVENT',\n 'c8y-colorpicker--alarm': timelineType !== 'EVENT'\n }\"\n >\n <input\n type=\"color\"\n formControlName=\"color\"\n (click)=\"$event.stopPropagation()\"\n />\n <span [style.background-color]=\"formGroup.value.color\">\n <i [c8yIcon]=\"timelineType === 'EVENT' ? 'online1' : 'bell'\"></i>\n </span>\n </div>\n </div>\n\n <c8y-alarm-event-attributes-form\n formControlName=\"details\"\n [timelineType]=\"timelineType\"\n [omitProperties]=\"omitProperties\"\n [selectedItems]=\"selectedItems\"\n ></c8y-alarm-event-attributes-form>\n\n <div class=\"d-flex p-t-16 gap-8\">\n <button class=\"btn btn-default btn-sm\" (click)=\"cancel.emit()\">\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n [disabled]=\"(valid$ | async) === false\"\n (click)=\"add()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Select' | translate }}\n </button>\n </div>\n</form>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }], propDecorators: { timelineType: [{
type: Input
}], target: [{
type: Input
}], omitProperties: [{
type: Input
}], selectedItems: [{
type: Input
}], defaultColor: [{
type: Input
}], added: [{
type: Output
}], cancel: [{
type: Output
}] } });
class AlarmEventSelectorListItemComponent {
constructor(formBuilder) {
this.formBuilder = formBuilder;
this.showAddRemoveButton = true;
this.isSelected = false;
this.optionToRemove = false;
this.showActiveToggle = false;
this.allowItemEdit = false;
this.hideSource = false;
this.displayAsSwitch = false;
this.omitProperties = {};
this.added = new EventEmitter();
this.removed = new EventEmitter();
this.destroy$ = new Subject();
this.formGroup = this.formBuilder.group({
details: [],
color: [],
__active: [],
__target: []
});
this.valid$ = this.formGroup.statusChanges.pipe(takeUntil(this.destroy$), map(val => val === 'VALID'));
}
ngOnInit() {
this.colorPickerTitle = this.allowItemEdit ? gettext('Change color') : '';
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
toggleActive() {
this.formGroup.controls.__active.setValue(!this.formGroup.value.__active);
}
validate(_control) {
return this.formGroup?.valid ? null : { formInvalid: {} };
}
writeValue(obj) {
this.formGroup.patchValue({ ...obj, details: obj });
}
registerOnChange(fn) {
this.formGroup.valueChanges
.pipe(map(tmp => this.transformFormValue(tmp)), takeUntil(this.destroy$))
.subscribe(fn);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
registerOnTouched(fn) {
this.formGroup.valueChanges.pipe(take(1)).subscribe(fn);
}
setDisabledState(isDisabled) {
isDisabled ? this.formGroup.disable() : this.formGroup.enable();
}
addOrRemoveItem() {
const value = this.transformFormValue(this.formGroup.value);
if (this.isSelected) {
this.removed.emit(value);
}
else {
this.added.emit(value);
}
}
remove() {
this.removed.emit(this.transformFormValue(this.formGroup.value));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
transformFormValue(formValue) {
const obj = Object.assign({}, formValue.details || {}, formValue);
delete obj.details;
return obj;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventSelectorListItemComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AlarmEventSelectorListItemComponent, isStandalone: true, selector: "c8y-alarm-event-selector-list-item", inputs: { timelineType: "timelineType", datapoints: "datapoints", highlightText: "highlightText", showAddRemoveButton: "showAddRemoveButton", isSelected: "isSelected", optionToRemove: "optionToRemove", showActiveToggle: "showActiveToggle", allowItemEdit: "allowItemEdit", hideSource: "hideSource", displayAsSwitch: "displayAsSwitch", omitProperties: "omitProperties" }, outputs: { added: "added", removed: "removed" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AlarmEventSelectorListItemComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AlarmEventSelectorListItemComponent),
multi: true
}
], ngImport: i0, template: "<c8y-li\n class=\"c8y-list__item__collapse--container-small\"\n [formGroup]=\"formGroup\"\n #li\n>\n <c8y-li-drag-handle><ng-content select=\"c8y-li-drag-handle\"></ng-content></c8y-li-drag-handle>\n @if (showActiveToggle) {\n <c8y-li-checkbox\n class=\"a-s-center m-t-4 p-r-0\"\n [displayAsSwitch]=\"displayAsSwitch\"\n formControlName=\"__active\"\n (click)=\"$event.stopPropagation()\"\n ></c8y-li-checkbox>\n }\n\n <div class=\"d-flex a-i-center p-l-0\">\n <div\n class=\"c8y-list__item__colorpicker p-t-0 p-b-0 p-l-16\"\n [title]=\"colorPickerTitle | translate\"\n >\n <div\n class=\"c8y-colorpicker\"\n [class.c8y-colorpicker--alarm]=\"timelineType === 'ALARM'\"\n [class.c8y-colorpicker--event]=\"timelineType === 'EVENT'\"\n >\n <input\n [style.pointer-events]=\"allowItemEdit && !omitProperties.color ? 'auto' : 'none'\"\n type=\"color\"\n formControlName=\"color\"\n (click)=\"$event.stopPropagation()\"\n />\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--medium\"\n [style.background-color]=\"formGroup.value.color\"\n >\n <i\n class=\"stroked-icon\"\n [c8yIcon]=\"timelineType === 'EVENT' ? 'online1' : 'bell'\"\n ></i>\n </span>\n </div>\n </div>\n <button\n class=\"btn-clean text-truncate\"\n [title]=\"formGroup.value.details?.label\"\n (click)=\"\n allowItemEdit\n ? (li.collapsed = !li.collapsed)\n : showActiveToggle\n ? toggleActive()\n : addOrRemoveItem()\n \"\n >\n <span class=\"text-truncate\">\n <c8y-highlight\n [text]=\"\n omitProperties.label\n ? formGroup.value.details?.filters?.type\n : formGroup.value.details?.label\n \"\n [pattern]=\"highlightText\"\n [shouldTrimPattern]=\"true\"\n ></c8y-highlight>\n </span>\n @if (formGroup.value.__target && !hideSource) {\n <small class=\"text-truncate text-muted icon-flex\">\n <i c8yIcon=\"exchange\"></i>\n <span class=\"text-truncate\">{{ formGroup.value.__target.name }}</span>\n </small>\n }\n </button>\n\n <span class=\"m-l-auto d-flex a-i-center m-r-4\">\n @if ((valid$ | async) === false && li.collapsed) {\n <button\n class=\"btn-dot btn-dot--danger\"\n title=\"{{ 'Invalid entries' | translate }}\"\n [popover]=\"'Some entries are invalid. Check the required input fields.' | translate\"\n container=\"body\"\n type=\"button\"\n [outsideClick]=\"true\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"exclamation-circle\"\n ></i>\n </button>\n }\n @if (showAddRemoveButton) {\n <span>\n @if (isSelected) {\n <button\n class=\"btn btn-dot text-danger\"\n [attr.aria-label]=\"'Remove' | translate\"\n [tooltip]=\"'Remove' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"addOrRemoveItem()\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"minus-circle\"\n ></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot text-primary\"\n [attr.aria-label]=\"'Select' | translate\"\n [tooltip]=\"'Select' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [disabled]=\"(valid$ | async) === false\"\n [delay]=\"500\"\n (click)=\"addOrRemoveItem()\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"plus-circle\"\n ></i>\n </button>\n }\n </span>\n }\n @if (optionToRemove) {\n <button\n class=\"showOnHover btn btn-dot btn-dot--danger m-r-4\"\n [attr.aria-label]=\"'Remove from list' | translate\"\n [tooltip]=\"'Remove from list' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n data-cy=\"alarm-event-selector-list-item--remove-btn\"\n [delay]=\"500\"\n (click)=\"remove()\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n }\n </span>\n </div>\n\n @if (allowItemEdit) {\n <c8y-li-collapse>\n <div class=\"data-point-details\">\n <c8y-alarm-event-attributes-form\n formControlName=\"details\"\n [timelineType]=\"timelineType\"\n [omitProperties]=\"omitProperties\"\n [datapoints]=\"datapoints\"\n [target]=\"formGroup.value.__target\"\n ></c8y-alarm-event-attributes-form>\n </div>\n </c8y-li-collapse>\n }\n</c8y-li>\n", dependencies: [{ kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ListItemDragHandleComponent, selector: "c8y-list-item-drag-handle, c8y-li-drag-handle" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "directive", type: 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: TooltipModule }, { kind: "directive", type: i2$1.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: "component", type: ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: AlarmEventAttributesFormComponent, selector: "c8y-alarm-event-attributes-form", inputs: ["timelineType", "omitProperties", "selectedItems", "target", "datapoints"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AlarmEventSelectorListItemComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-alarm-event-selector-list-item', providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AlarmEventSelectorListItemComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AlarmEventSelectorListItemComponent),
multi: true
}
], imports: [
ListItemComponent,
FormsModule,
ReactiveFormsModule,
ListItemDragHandleComponent,
IconDirective,
ListItemCheckboxComponent,
RequiredInputPlaceholderDirective,
HighlightComponent,
PopoverDirective,
TooltipModule,
ListItemCollapseComponent,
AlarmEventAttributesFormComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-li\n class=\"c8y-list__item__collapse--container-small\"\n [formGroup]=\"formGroup\"\n #li\n>\n <c8y-li-drag-handle><ng-content select=\"c8y-li-drag-handle\"></ng-content></c8y-li-drag-handle>\n @if (showActiveToggle) {\n <c8y-li-checkbox\n class=\"a-s-center m-t-4 p-r-0\"\n [displayAsSwitch]=\"displayAsSwitch\"\n formControlName=\"__active\"\n (click)=\"$event.stopPropagation()\"\n ></c8y-li-checkbox>\n }\n\n <div class=\"d-flex a-i-center p-l-0\">\n <div\n class=\"c8y-list__item__colorpicker p-t-0 p-b-0 p-l-16\"\n [title]=\"colorPickerTitle | translate\"\n >\n <div\n class=\"c8y-colorpicker\"\n [class.c8y-colorpicker--alarm]=\"timelineType === 'ALARM'\"\n [class.c8y-colorpicker--event]=\"timelineType === 'EVENT'\"\n >\n <input\n [style.pointer-events]=\"allowItemEdit && !omitProperties.color ? 'auto' : 'none'\"\n type=\"color\"\n formControlName=\"color\"\n (click)=\"$event.stopPropagation()\"\n />\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--medium\"\n [style.background-color]=\"formGroup.value.color\"\n >\n <i\n class=\"stroked-icon\"\n [c8yIcon]=\"timelineType === 'EVENT' ? 'online1' : 'bell'\"\n ></i>\n </span>\n </div>\n </div>\n <button\n class=\"btn-clean text-truncate\"\n [title]=\"formGroup.value.details?.label\"\n (click)=\"\n allowItemEdit\n ? (li.collapsed = !li.collapsed)\n : showActiveToggle\n ? toggleActive()\n : addOrRemoveItem()\n \"\n >\n <span class=\"text-truncate\">\n <c8y-highlight\n [text]=\"\n omitProperties.label\n ? formGroup.value.details?.filters?.type\n : formGroup.value.details?.label\n \"\n [pattern]=\"highlightText\"\n [shouldTrimPattern]=\"true\"\n ></c8y-highlight>\n </span>\n @if (formGroup.value.__target && !hideSource) {\n <small class=\"text-truncate text-muted icon-flex\">\n <i c8yIcon=\"exchange\"></i>\n <span class=\"text-truncate\">{{ formGroup.value.__target.name }}</span>\n </small>\n }\n </button>\n\n <span class=\"m-l-auto d-flex a-i-center m-r-4\">\n @if ((valid$ | async) === false && li.collapsed) {\n <button\n class=\"btn-dot btn-dot--danger\"\n title=\"{{ 'Invalid entries' | translate }}\"\n [popover]=\"'Some entries are invalid. Check the required input fields.' | translate\"\n container=\"body\"\n type=\"button\"\n [outsideClick]=\"true\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"exclamation-circle\"\n ></i>\n </button>\n }\n @if (showAddRemoveButton) {\n <span>\n @if (isSelected) {\n <button\n class=\"btn btn-dot text-danger\"\n [attr.aria-label]=\"'Remove' | translate\"\n [tooltip]=\"'Remove' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [delay]=\"500\"\n (click)=\"addOrRemoveItem()\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"minus-circle\"\n ></i>\n </button>\n } @else {\n <button\n class=\"btn btn-dot text-primary\"\n [attr.aria-label]=\"'Select' | translate\"\n [tooltip]=\"'Select' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [disabled]=\"(valid$ | async) === false\"\n [delay]=\"500\"\n (click)=\"addOrRemoveItem()\"\n >\n <i\n class=\"icon-20\"\n c8yIcon=\"plus-circle\"\n ></i>\n </button>\n }\n </span>\n }\n @if (optionToRemove) {\n <button\n class=\"showOnHover btn btn-dot btn-dot--danger m-r-4\"\n [attr.aria-label]=\"'Remove from list' | translate\"\n [tooltip]=\"'Remove from list' | translate\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n data-cy=\"alarm-event-selector-list-item--remove-btn\"\n [delay]=\"500\"\n (click)=\"remove()\"\n >\n <i c8yIcon=\"minus-circle\"></i>\n </button>\n }\n </span>\n </div>\n\n @if (allowItemEdit) {\n <c8y-li-collapse>\n <div class=\"data-point-details\">\n <c8y-alarm-event-attributes-form\n formControlName=\"details\"\n [timelineType]=\"timelineType\"\n [omitProperties]=\"omitProperties\"\n [datapoints]=\"datapoints\"\n [target]=\"formGroup.value.__target\"\n ></c8y-alarm-event-attributes-form>\n </div>\n </c8y-li-collapse>\n }\n</c8y-li>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }], propDecorators: { timelineType: [{
type: Input
}], datapoints: [{
type: Input
}], highlightText: [{
type: Input
}], showAddRemoveButton: [{
type: Input
}], isSelected: [{
type: Input
}], optionToRemove: [{
type: Input
}], showActiveToggle: [{
type: Input
}], allowItemEdit: [{
type: Input
}], hideSource: [{
type: Input
}], displayAsSwitch: [{
type: Input
}], omitProperties: [{
type: Input
}], added: [{
type: Output
}], removed: [{
type: Output
}] } });
class IncludesAlarmOrEventPipe {
transform(itemList, item) {
if (!Array.isArray(itemList) || !item) {
return false;
}
return itemList.some(tmp => tmp.label === item.label &&
tmp.filters.type === item.filters.type &&
tmp.__target?.id === item.__target?.id);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: IncludesAlarmOrEventPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: IncludesAlarmOrEventPipe, isStandalone: true, name: "includesAlarmOrEvent" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: IncludesAlarmOrEventPipe, decorators: [{
type: Pipe,
args: [{ name: 'includesAlarmOrEvent' }]
}] });
class AlarmEventSelectorComponent {
constructor(alarmEventSelectorService) {
this.alarmEventSelectorService = alarmEventSelectorService;
this.timelineType = 'ALARM';
this.allowChangingContext = true;
this.selectedItems = new Array();
this.allowSearch = true;
this.groupsSelectable = true;
this.hideSource = false;
this.omitProperties = {};
this.selectionChange = new EventEmitter();
this.filterString = '';
this.maxNumberOfItems = 50;
this.loadingItems$ = new BehaviorSubject(false);
this.assetSelection = new BehaviorSubject({});
this.isExpanded = false;
this.defaultColor = getComputedStyle(document.documentElement).getPropertyValue('--brand-primary') ||
getComputedStyle(document.documentElement).getPropertyValue('--c8y-brand-primary') ||
'#1776BF';
this.filterString$ = new BehaviorSubject('');
}
ngOnInit() {
this.timelineTypeTexts = this.alarmEventSelectorService.timelineTypeTexts(this.timelineType);
this.setupObservables();
if (this.contextAsset) {
this.selectAsset(this.contextAsset);
}
}
itemAdded(item) {
item.__active = true;
this.selectedItems = [...this.selectedItems, item];
this.emitCurrentSelection();
}
itemRemoved(alarm) {
this.selectedItems = this.selectedItems.filter(tmp => tmp.label !== alarm.label ||
tmp.filters.type !== alarm.filters.type ||
tmp.__target?.id !== alarm.__target?.id);
this.emitCurrentSelection();
}
assetSelectionChanged(evt) {
if (evt.items) {
return this.selectAsset(evt.items.length ? evt.items[0] : evt.items);
}
// reset selection
this.assetSelection.next(null);
}
trackByFn(_index, item) {
return `${item.filters.type}-${item.__target?.id}`;
}
filterStringChanged(newValue = '') {
this.filterString$.next(newValue);
this.filterString = newValue;
}
setLoadingState(state) {