UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

875 lines 67.8 kB
import { NgClass, AsyncPipe, CommonModule as CommonModule$1 } from '@angular/common';
import * as i0 from '@angular/core';
import { Injectable, Pipe, ViewChild, Input, Component, inject, signal, NgModule } from '@angular/core';
import * as i5 from '@angular/forms';
import { FormControl, NgForm, ControlContainer, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i2 from '@c8y/client';
import { AlarmStatus, Severity, SEVERITY_LABELS, ALARM_STATUS_LABELS, AlarmService } from '@c8y/client';
import * as i4 from '@c8y/ngx-components';
import { FormGroupComponent, RequiredInputPlaceholderDirective, IconDirective, MessagesComponent, MessageDirective, C8yTranslatePipe, DashboardChildComponent, AlertService, DismissAlertStrategy, DynamicComponentAlert, AlarmRealtimeService, AlarmWithChildrenRealtimeService, CommonModule, CountdownIntervalModule, DocsModule, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
import * as i1 from '@c8y/ngx-components/alarms';
import { ALARM_STATUS_ICON, DEFAULT_SEVERITY_VALUES, DEFAULT_STATUS_VALUES, AlarmsDateFilterComponent, AlarmsListComponent, AlarmsModule } from '@c8y/ngx-components/alarms';
import * as i6 from '@c8y/ngx-components/context-dashboard';
import { PRESET_NAME, GLOBAL_CONTEXT_DISPLAY_MODE, LocalControlsComponent, WidgetConfigMigrationService, CONTEXT_FEATURE, REFRESH_OPTION, GlobalContextConnectorComponent, GlobalContextConfigComponent, GlobalContextInlineComponent, ConfigContextSelectorComponent, GlobalContextWidgetWrapperComponent } from '@c8y/ngx-components/global-context';
import { merge, isEmpty, isMatch } from 'lodash-es';
import { PopoverDirective, PopoverModule } from 'ngx-bootstrap/popover';
import { BehaviorSubject, Subject, EMPTY, from } from 'rxjs';
import { filter, tap, takeUntil, shareReplay, switchMap } from 'rxjs/operators';
import { gettext } from '@c8y/ngx-components/gettext';
import { defaultWidgetIds } from '@c8y/ngx-components/widgets/definitions';
import { RouterModule } from '@angular/router';
import * as i1$1 from 'ngx-bootstrap/tooltip';
import { TooltipModule } from 'ngx-bootstrap/tooltip';

const ALARM_ORDER_VALUES = {
    BY_ACTIVE: 'BY_ACTIVE',
    BY_DATE_ASCENDING: 'BY_DATE_ASCENDING',
    BY_DATE_DESCENDING: 'BY_DATE_DESCENDING',
    BY_SEVERITY: 'BY_SEVERITY'
};
const ALARM_ORDER_LABELS = {
    BY_ACTIVE: gettext('By active status'),
    BY_DATE_ASCENDING: gettext('By date (ascending)'),
    BY_DATE_DESCENDING: gettext('By date (descending)'),
    BY_SEVERITY: gettext('By severity')
};
const ASSET_ALARMS_WIDGET_ID = 'Asset Alarms';
const RECENT_ALARMS_WIDGET_ID = 'Recent Alarms';
// TODO: remove
const GLOBAL_INTERVAL_OPTION = 'global-interval';

const DEFAULT_PAGE_SIZE = 20;
class AlarmWidgetService {
    constructor(alarmsViewService) {
        this.alarmsViewService = alarmsViewService;
    }
    /**
     * Checks if the provided data follows the LegacyAlarmConfig structure.
     *
     * This function determines if a given data object is an instance of LegacyAlarmConfig
     * by checking for the presence of the 'options' property.
     *
     * @param data - The data object to be checked.
     * @returns - Returns `true` if the data object is a LegacyAlarmConfig, otherwise `false`.
     */
    isOldAlarmConfigStructure(data) {
        return data !== null && typeof data === 'object' && 'options' in data;
    }
    /**
     * Creates predefined widget configuration object.
     *
     * This method creates a new configuration object based on
     * a widgets ID (that determines if is a legacy Recent or Critical alarms widget).
     *
     * @param isIntervalRefresh - determines a type of a refresh.
     * @param widgetId - determines if a config should be done for Recent or Critical alarms widget.
     * @returns The new, predefined configuration object.
     */
    getPredefinedConfiguration(widgetId, existingConfig) {
        // Check if any time/refresh configuration exists (cast to any for legacy properties)
        const hasAnyTimeConfig = existingConfig?.dateTimeContext ||
            existingConfig?.dateFilter ||
            existingConfig?.date ||
            existingConfig?.dateFrom ||
            existingConfig?.dateTo ||
            existingConfig?.refreshOption ||
            existingConfig?.isAutoRefreshEnabled !== undefined ||
            existingConfig?.refreshInterval ||
            existingConfig?.aggregation !== undefined;
        const config = {
            order: ALARM_ORDER_VALUES.BY_ACTIVE,
            severities: widgetId === RECENT_ALARMS_WIDGET_ID
                ? {
                    [Severity.CRITICAL]: true,
                    [Severity.MAJOR]: true,
                    [Severity.MINOR]: true,
                    [Severity.WARNING]: true
                }
                : {
                    [Severity.CRITICAL]: true,
                    [Severity.MAJOR]: false,
                    [Severity.MINOR]: false,
                    [Severity.WARNING]: false
                },
            status: widgetId === RECENT_ALARMS_WIDGET_ID
                ? {
                    [AlarmStatus.ACKNOWLEDGED]: true,
                    [AlarmStatus.ACTIVE]: true,
                    [AlarmStatus.CLEARED]: true
                }
                : {
                    [AlarmStatus.ACKNOWLEDGED]: false,
                    [AlarmStatus.ACTIVE]: true,
                    [AlarmStatus.CLEARED]: false
                },
            types: [''],
            widgetId: widgetId || ''
        };
        // Only add global context defaults if no time/refresh config exists at all
        if (!hasAnyTimeConfig) {
            config.isAutoRefreshEnabled = true;
            config.refreshInterval = this.alarmsViewService.DEFAULT_INTERVAL_VALUE;
            config.aggregation = null;
            config.refreshOption = 'live';
            config.dateTimeContext = {
                dateFrom: new Date(0).toISOString(),
                dateTo: new Date().toISOString(),
                interval: 'custom'
            };
        }
        return config;
    }
    /**
     * Transforms a LegacyAlarmConfig object into an AlarmListWidgetConfig object.
     *
     * This function maps the properties from an old configuration structure (LegacyAlarmConfig)
     * to a new configuration structure (AlarmListWidgetConfig).
     *
     * @param oldConfig - The old configuration object to be transformed.
     * @returns - The new configuration object mapped from the old one.
     */
    mapToNewConfigStructure(oldConfig) {
        const order = oldConfig.options.orderMode === 'ACTIVE_FIRST'
            ? ALARM_ORDER_VALUES.BY_ACTIVE
            : ALARM_ORDER_VALUES.BY_SEVERITY;
        if (!this.isContainingAllSeverityTypes(oldConfig.options.severity)) {
            oldConfig.options.severity = this.addAllMissingSeverityTypes(oldConfig.options.severity);
        }
        return {
            order: order,
            isRealtime: oldConfig.realtime,
            device: oldConfig.device,
            showAlarmsForChildren: true,
            severities: oldConfig.options.severity,
            status: this.allValuesFalse(oldConfig.options.status)
                ? {
                    [AlarmStatus.ACKNOWLEDGED]: true,
                    [AlarmStatus.ACTIVE]: true,
                    [AlarmStatus.CLEARED]: true
                }
                : oldConfig.options.status,
            types: oldConfig.options.types?.length ? oldConfig.options.types : [''],
            isAutoRefreshEnabled: true,
            refreshInterval: this.alarmsViewService.DEFAULT_INTERVAL_VALUE
        };
    }
    /**
     * Checks if the provided severity object contains all the predefined severity types.
     *
     * @param severity - A record object where keys are severity type strings and values are boolean.
     *                 - This object is checked against the predefined severity types.
     * @returns `true` if all predefined severity types are present in the severity object; otherwise, `false`.
     */
    isContainingAllSeverityTypes(severity) {
        return Object.keys(SEVERITY_LABELS).every(severityType => severityType in severity);
    }
    /**
     * Adds any missing severity types to the provided severity object with a default value of `false`.
     *
     * @param severity - A record object where keys are severity type strings and values are boolean.
     *                 - Missing severity types will be added to this object.
     * @returns The modified severity object, which includes all predefined severity types, adding any
     *          that were missing with a value of `false`.
     */
    addAllMissingSeverityTypes(severity) {
        Object.keys(SEVERITY_LABELS).forEach(severityType => {
            if (!(severityType in severity)) {
                severity[severityType] = false;
            }
        });
        return severity;
    }
    /**
     * Maps an AlarmListWidgetConfig object to an AlarmQueryFilter.
     *
     * This function converts the provided AlarmListWidgetConfig into a format suitable for querying alarms.
     *
     * @param config - The configuration object for the alarm list widget.
     * @param pageSize - Optional number specifying the size of the pages to be returned in the query.
     * @returns - The query filter object constructed from the provided configuration.
     */
    mapConfigToQueryFilter(config, pageSize) {
        const filter = {
            pageSize: pageSize || DEFAULT_PAGE_SIZE,
            query: this.getOrderParameters(config.order),
            severity: this.extractFilterParams(config.severities || {}),
            status: this.extractFilterParams(config.status || {}),
            type: (config.types || []).join(','),
            withTotalPages: true
        };
        if (config.dateTimeContext) {
            const { dateFrom, dateTo } = config.dateTimeContext;
            filter.lastUpdatedFrom = typeof dateFrom === 'string' ? dateFrom : dateFrom.toISOString();
            filter.createdTo = typeof dateTo === 'string' ? dateTo : dateTo.toISOString();
        }
        if (config.device) {
            filter.source = config.device.id;
            filter.withSourceAssets = true;
            filter.withSourceDevices = true;
            filter.withSourceAssets = config.showAlarmsForChildren ?? true;
            filter.withSourceDevices = config.showAlarmsForChildren ?? true;
        }
        return filter;
    }
    /**
     * Extracts and concatenates filter parameters from a given object.
     *
     * This function takes an object containing filter settings (either SeverityFilter
     * or AlarmStatusSettings) and returns a string of all keys where the corresponding value is true.
     * If the object is empty or null, an empty string is returned.
     *
     * @param obj - The object containing filter settings.
     * @returns - A concatenated string of keys with true values, separated by commas.
     */
    extractFilterParams(obj) {
        if (!obj) {
            return '';
        }
        return Object.entries(obj)
            .filter(([, value]) => value)
            .map(([key]) => key)
            .join(',');
    }
    /**
     * Determines if an incoming real-time alarm has a different status than an existing alarm.
     *
     * This function checks if the provided incoming real-time alarm's status differs
     * from that of an existing alarm with the same ID in the given array of alarms.
     *
     * @param existingAlarms - The array of existing alarms.
     * @param incomingRealtimeAlarm - The incoming real-time alarm to check.
     * @returns - True if the existing alarm's status has changed, otherwise false.
     */
    hasExistingAlarmChangedStatus(existingAlarms, incomingRealtimeAlarm) {
        const existingAlarm = existingAlarms.find(alarm => alarm.id === incomingRealtimeAlarm.id);
        return !!existingAlarm && existingAlarm.status !== incomingRealtimeAlarm.status;
    }
    /**
     * Filters alarms based on their status, severity, and type.
     *
     * This method determines if a given alarm, identified either by a numeric ID or an `IAlarm` object,
     * matches specific criteria defined in `alarms` and optionally `config`.
     *
     * @param alarm - The alarm to check, represented either by a numeric ID or an `IAlarm` object.
     * @param alarms - An array of `IAlarm` objects against which the given alarm is evaluated.
     * @param config - Optional. Configuration for the alarm list widget, used to define additional
     *                 filtering criteria.
     *
     * @returns `true` if the alarm matches the specified criteria; otherwise, `false`.
     *          If `alarm` is a number, it always returns `false`.
     *          If `config` is not provided, it uses a legacy filter for critical alarms.
     *
     * @remarks
     * - When `alarm` is a numeric ID, the function returns `false` as it cannot match against type and severity.
     * - If `config` is not provided, the function assumes a legacy scenario for filtering all critical alarms.
     */
    filterAlarmsByStatusSeverityAndType(alarm, alarms, config) {
        if (typeof alarm === 'number') {
            return false;
        }
        return this.isAlarmMatchedByConfig(alarm, alarms, config);
    }
    /**
     * Determines if all values in the given object are false.
     *
     * This function checks every value in the provided object to see if they are all false.
     *
     * @param obj - An object with boolean values.
     * @returns - Returns `true` if all values in the object are false, otherwise `false`.
     */
    allValuesFalse(obj) {
        return Object.values(obj).every(value => !value);
    }
    /**
     * Constructs a string of order parameters for a query based on the specified alarm order.
     *
     * This function takes an alarm order and maps it to a corresponding set of order parameters.
     * It supports different ordering types, such as BY_ACTIVE, BY_SEVERITY, and BY_DATE_ASCENDING.
     * The order parameters are used to construct a query string that determines the order
     * in which alarms are retrieved or displayed.
     *
     * @param order - The specified order for sorting alarms (e.g., BY_ACTIVE).
     * @returns - A string of order parameters to be used in a query, or an empty string if the order type is unrecognized.
     */
    getOrderParameters(order) {
        let orderParams;
        switch (order) {
            case ALARM_ORDER_VALUES.BY_ACTIVE:
                orderParams = ['status asc', 'severity asc', 'time.date desc', 'text asc'];
                return this.buildOrderParameters(orderParams);
            case ALARM_ORDER_VALUES.BY_SEVERITY:
                orderParams = ['severity asc', 'time.date desc', 'text asc'];
                return this.buildOrderParameters(orderParams);
            case ALARM_ORDER_VALUES.BY_DATE_ASCENDING:
                orderParams = ['time.date asc', 'text asc'];
                return this.buildOrderParameters(orderParams);
            default:
                orderParams = ['time.date desc', 'text asc'];
                return this.buildOrderParameters(orderParams);
        }
    }
    /**
     * Determines if an alarm is matched by the specified widget configuration.
     *
     * This function evaluates whether a given alarm should be included based on the severity,
     * status, and type filters defined in the AlarmListWidgetConfig. It checks if the alarm's
     * severity and status match the configuration settings and if the alarm's type is included
     * in the configuration's types (if specified).
     *
     * @ignore
     * @param alarm - The alarm to evaluate.
     * @param alarms - An array of existing alarms, used for status matching.
     * @param config - The configuration settings to match against.
     * @returns - Returns `true` if the alarm matches the configuration criteria; otherwise, `false`.
     */
    isAlarmMatchedByConfig(alarm, alarms, config) {
        const isSeverityMatched = this.isSeverityMatching(alarm.severity, config);
        const isStatusMatched = this.isStatusMatching(alarm, alarms, config);
        const isTypeMatched = this.isTypesMatching(config, alarm);
        return isSeverityMatched && isStatusMatched && isTypeMatched;
    }
    /**
     * Checks if the severity of an alarm matches the configuration setting.
     *
     * This function determines whether the severity of an alarm is included in the
     * severity settings defined in the AlarmListWidgetConfig.
     *
     * @ignore
     * @param severity - The severity of the alarm to check.
     * @param config - The configuration with severity settings.
     * @returns - Returns `true` if the alarm's severity matches the configuration; otherwise, `false`.
     */
    isSeverityMatching(severity, config) {
        return !!config.severities[severity];
    }
    /**
     * Evaluates if the status of an alarm matches the configuration setting or has changed.
     *
     * This function checks if the status of an alarm is included in the status settings defined in
     * the AlarmListWidgetConfig, or if the alarm's status has changed based on the existing alarms.
     *
     * @ignore
     * @param alarm - The alarm whose status is to be evaluated.
     * @param alarms - An array of existing alarms to compare against for status changes.
     * @param config - The configuration with status settings.
     * @returns - Returns `true` if the alarm's status matches or has changed as per the configuration; otherwise, `false`.
     */
    isStatusMatching(alarm, alarms, config) {
        return !!config.status[alarm.status] || this.hasExistingAlarmChangedStatus(alarms, alarm);
    }
    /**
     * Checks if the configuration's types array contains only empty string or includes a specific alarm type.
     *
     * @param config - The configuration object with a `types` property.
     * @param alarm - The alarm object with a `type` property to check against the config's types.
     * @returns `true` if the config's types array contains only empty string or includes the alarm's type, otherwise `false`.
     */
    isTypesMatching(config, alarm) {
        return Array.isArray(config.types) && config.types.length === 1 && config.types[0] === ''
            ? true
            : (config.types?.includes(alarm.type) ?? false);
    }
    /**
     * Constructs a query string from an array of order parameters.
     *
     * This function takes an array of ordering parameters and constructs a query string
     * for use in alarm ordering queries. The parameters are concatenated into a single string,
     * prefixed with '$orderby='.
     *
     * @ignore
     * @private
     * @param orderParams - The order parameters to be included in the query.
     * @returns - A query string representing the order parameters.
     */
    buildOrderParameters(orderParams) {
        return `$orderby=${orderParams.join(',')}`;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmWidgetService, deps: [{ token: i1.AlarmsViewService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmWidgetService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmWidgetService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.AlarmsViewService }] });

class SeverityIconPipe {
    transform(severity) {
        let severityClassName = '';
        let iconClassName = '';
        switch (severity) {
            case Severity.CRITICAL:
                severityClassName = 'critical';
                iconClassName = 'exclamation-circle';
                break;
            case Severity.MAJOR:
                severityClassName = 'major';
                iconClassName = 'warning';
                break;
            case Severity.MINOR:
                severityClassName = 'minor';
                iconClassName = 'high-priority';
                break;
            case Severity.WARNING:
                severityClassName = 'warning';
                iconClassName = 'circle';
                break;
            default:
                return { iconClass: '', severityClass: '' };
        }
        return {
            iconClass: `status icon-lg stroked-icon dlt-c8y-icon-${iconClassName} ${severityClassName}`,
            c8yIcon: severityClassName
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SeverityIconPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SeverityIconPipe, isStandalone: true, name: "severityIcon" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SeverityIconPipe, decorators: [{
            type: Pipe,
            args: [{ name: 'severityIcon' }]
        }] });

class SortingDescriptionPopoverMessagePipe {
    transform(order) {
        switch (order) {
            case ALARM_ORDER_VALUES.BY_ACTIVE:
                return gettext('Order alarms by active status, severity, and time.');
            case ALARM_ORDER_VALUES.BY_DATE_ASCENDING:
                return gettext('Order alarms by time, starting with the oldest ones.');
            case ALARM_ORDER_VALUES.BY_DATE_DESCENDING:
                return gettext('Order alarms by time, starting with the latest ones.');
            case ALARM_ORDER_VALUES.BY_SEVERITY:
                return gettext('Order alarms by severity and time.');
            default:
                return '';
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SortingDescriptionPopoverMessagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SortingDescriptionPopoverMessagePipe, isStandalone: true, name: "sortingDescriptionPopoverMessage" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SortingDescriptionPopoverMessagePipe, decorators: [{
            type: Pipe,
            args: [{ name: 'sortingDescriptionPopoverMessage' }]
        }] });

class AlarmListWidgetConfigComponent {
    set previewMapSet(template) {
        if (template) {
            this.widgetConfigService.setPreview(template);
            return;
        }
        this.widgetConfigService.setPreview(null);
    }
    constructor(alarmListWidgetService, alarmService, alarmsViewService, alertService, form, formBuilder, widgetConfigService) {
        this.alarmListWidgetService = alarmListWidgetService;
        this.alarmService = alarmService;
        this.alarmsViewService = alarmsViewService;
        this.alertService = alertService;
        this.form = form;
        this.formBuilder = formBuilder;
        this.widgetConfigService = widgetConfigService;
        this.REFRESH_INTERVAL_IN_MILLISECONDS = this.alarmsViewService.DEFAULT_INTERVAL_VALUES;
        this.SEVERITY_LABELS = SEVERITY_LABELS;
        this.STATUS_LABELS = ALARM_STATUS_LABELS;
        this.ACKNOWLEDGE_STATUS_VALUE = AlarmStatus.ACKNOWLEDGED;
        this.CLEARED_STATUS_VALUE = AlarmStatus.CLEARED;
        this.BELL_SLASH_ICON = ALARM_STATUS_ICON.BELL_SLASH;
        this.BELL_ICON = ALARM_STATUS_ICON.BELL;
        this.C8Y_ALERT_IDLE_ICON = ALARM_STATUS_ICON.ALERT_IDLE;
        this.ALARM_ORDER_LABELS = ALARM_ORDER_LABELS;
        this.alarms$ = new BehaviorSubject(null);
        this.orderList = Object.values(ALARM_ORDER_VALUES);
        this.severityList = Object.keys(SEVERITY_LABELS);
        /**
         * Order does matter.
         */
        this.statusList = [AlarmStatus.ACTIVE, AlarmStatus.ACKNOWLEDGED, AlarmStatus.CLEARED];
        this.destroy$ = new Subject();
        this.config$ = this.widgetConfigService.currentConfig$.pipe(filter(config => !!config), filter(c => c.dateTimeContext), tap(config => {
            if (!this.formGroup) {
                this.initializeForm();
            }
            else {
                this.formGroup.patchValue(config, { emitEvent: false });
            }
        }), takeUntil(this.destroy$), shareReplay(1));
        this.controls = PRESET_NAME.ALARM_LIST;
    }
    ngOnInit() {
        this.config$
            .pipe(takeUntil(this.destroy$), filter(config => {
            const displayMode = config?.displayMode ?? GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD;
            if (displayMode === GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {
                return !!config?.isGlobalContextReady;
            }
            return true;
        }), switchMap(config => {
            if ((config?.severities && this.alarmListWidgetService.allValuesFalse(config.severities)) ||
                (config?.status && this.alarmListWidgetService.allValuesFalse(config.status))) {
                this.alarms$.next({ data: [], res: null });
                return EMPTY;
            }
            const isWidgetWithExistingConfig = config.order && config.severities && config.status;
            const filterConfig = isWidgetWithExistingConfig
                ? config
                : { ...this.formGroup.value, ...config };
            return from(this.getAlarms(filterConfig));
        }))
            .subscribe();
    }
    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    onBeforeSave(config) {
        const { types } = this.formGroup.value;
        if (types.length > 1) {
            const stringTypes = types;
            if (this.isContainingOnlyEmptyTypes(stringTypes)) {
                this.formGroup.value.types = [''];
            }
            else {
                this.formGroup.value.types = this.filterEmptyTypes(stringTypes);
            }
        }
        /**
         * Applies only to converted legacy Alarm list widget
         */
        if (config['options']) {
            delete config['options'];
        }
        Object.assign(config, this.formGroup.value);
        return true;
    }
    removeType(index) {
        if (this.types.controls.length === 1) {
            this.formGroup.get('types').reset();
        }
        else {
            this.types.removeAt(index);
        }
    }
    addType() {
        this.types.push(this.formBuilder.control(''));
    }
    get types() {
        return this.formGroup.get('types');
    }
    filterEmptyTypes(types) {
        return types.filter((element) => element !== '' && element !== null);
    }
    isContainingOnlyEmptyTypes(types) {
        return types.every((element) => element === '' || element === null);
    }
    async getAlarms(config) {
        try {
            this.isLoading = true;
            const result = await this.alarmService.list(this.alarmListWidgetService.mapConfigToQueryFilter(config, DEFAULT_PAGE_SIZE));
            this.alarms$.next(result);
        }
        catch (error) {
            this.alertService.addServerFailure(error);
        }
        finally {
            this.isLoading = false;
        }
    }
    initializeForm() {
        this.formGroup = this.createForm();
        this.form.form.addControl('config', this.formGroup);
        this.formGroup.patchValue(this.config, { emitEvent: false });
        this.initializeTypes(this.config.types);
        this.formGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => {
            this.config = merge(this.config, value);
            this.getAlarms(this.config);
        });
    }
    createForm() {
        return this.formBuilder.group({
            status: this.formBuilder.group(DEFAULT_STATUS_VALUES, {
                validators: this.minSelectedCheckboxes(1)
            }),
            showAlarmsForChildren: true,
            types: this.formBuilder.array([]),
            severities: this.formBuilder.group(DEFAULT_SEVERITY_VALUES, {
                validators: this.minSelectedCheckboxes(1)
            }),
            order: ALARM_ORDER_VALUES.BY_ACTIVE,
            device: this.config.device ? new FormControl(this.config.device) : new FormControl(undefined)
        });
    }
    minSelectedCheckboxes(min = 1) {
        const validator = (formGroup) => {
            const totalSelected = Object.values(formGroup.controls).reduce((prev, next) => (next.value ? prev + next.value : prev), 0);
            return totalSelected >= min ? null : { required: true };
        };
        return validator;
    }
    initializeTypes(types) {
        const typesControl = this.formGroup.get('types');
        if (types) {
            types.forEach(type => {
                typesControl.push(this.formBuilder.control(type));
            });
        }
        else {
            typesControl.push(this.formBuilder.control(''));
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmListWidgetConfigComponent, deps: [{ token: AlarmWidgetService }, { token: i2.AlarmService }, { token: i1.AlarmsViewService }, { token: i4.AlertService }, { token: i5.NgForm }, { token: i5.FormBuilder }, { token: i6.WidgetConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AlarmListWidgetConfigComponent, isStandalone: true, selector: "c8y-alarm-list-widget-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "previewMapSet", first: true, predicate: ["alarmListPreview"], descendants: true }], ngImport: i0, template: "<div\n  class=\"p-l-24 p-r-24\"\n  [style.pointer-events]=\"'auto'\"\n  [style.opacity]=\"1\"\n></div>\n\n@if (formGroup) {\n  <form\n    class=\"row d-flex flex-wrap\"\n    [formGroup]=\"formGroup\"\n  >\n    <div class=\"col-md-6\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Order`of items on a list, noun`' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          @for (order of orderList; track order; let i = $index) {\n            <div\n              class=\"d-flex p-b-8 p-t-4 a-i-center\"\n              data-cy=\"c8y-alarm-list-widget-config--order-elements\"\n            >\n              <label\n                class=\"c8y-radio gap-4\"\n                title=\"{{ ALARM_ORDER_LABELS[order] | translate }}\"\n              >\n                <input\n                  type=\"radio\"\n                  [value]=\"order\"\n                  formControlName=\"order\"\n                />\n                <span class=\"a-s-center\"></span>\n                <span class=\"text-truncate\">{{ ALARM_ORDER_LABELS[order] | translate }}</span>\n              </label>\n              <button\n                class=\"btn-help btn-help--sm\"\n                [attr.aria-label]=\"'Help' | translate\"\n                [popover]=\"order | sortingDescriptionPopoverMessage | translate\"\n                placement=\"right\"\n                triggers=\"focus\"\n                container=\"body\"\n                type=\"button\"\n                [adaptivePosition]=\"true\"\n              ></button>\n            </div>\n          }\n        </c8y-form-group>\n      </fieldset>\n    </div>\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        formGroupName=\"severities\"\n      >\n        <legend>{{ 'Severities' | translate }}</legend>\n        <c8y-form-group\n          [hasError]=\"formGroup.controls.severities.hasError('required')\"\n          [ngClass]=\"{\n            'm-b-8': !formGroup.controls.severities.hasError('required')\n          }\"\n          data-cy=\"c8y-alarm-list-widget-config--severities-elements\"\n        >\n          @for (severityOption of severityList; track severityOption) {\n            <label\n              class=\"c8y-checkbox m-t-0 gap-4\"\n              [title]=\"SEVERITY_LABELS[severityOption] | translate\"\n            >\n              <input\n                type=\"checkbox\"\n                [formControlName]=\"severityOption\"\n                [name]=\"severityOption\"\n              />\n              <span class=\"a-s-center\"></span>\n              @let severityIcon = severityOption | severityIcon;\n              <i\n                class=\"a-s-center m-r-4 icon-20 {{ severityIcon.iconClass }}\"\n                [c8yIcon]=\"severityIcon.c8yIcon\"\n              ></i>\n              <span>{{ SEVERITY_LABELS[severityOption] | translate }}</span>\n            </label>\n          }\n          <c8y-messages>\n            @if (formGroup.controls.severities.hasError('required')) {\n              <c8y-message>\n                {{ 'Select at least one severity.' | translate }}\n              </c8y-message>\n            }\n          </c8y-messages>\n        </c8y-form-group>\n      </fieldset>\n      @if (showDateFilter) {\n        <fieldset class=\"c8y-fieldset\">\n          <legend>{{ 'Date filter' | translate }}</legend>\n          <c8y-form-group class=\"m-b-8\">\n            <c8y-alarms-date-filter\n              [updateQueryParams]=\"false\"\n              [DEFAULT_INTERVAL]=\"config.interval || 'none'\"\n              formControlName=\"dateFilter\"\n              (dateFilterChange)=\"onDateFilterChange($event)\"\n            ></c8y-alarms-date-filter>\n          </c8y-form-group>\n        </fieldset>\n      }\n    </div>\n\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        formGroupName=\"status\"\n      >\n        <legend data-cy=\"c8y-alarm-list-widget-config-status-label\">\n          {{ 'Status' | translate }}\n        </legend>\n        <c8y-form-group\n          [hasError]=\"formGroup.controls.status.hasError('required')\"\n          [ngClass]=\"{\n            'm-b-8': !formGroup.controls.status.hasError('required')\n          }\"\n          data-cy=\"c8y-alarm-list-widget-config--status-elements\"\n        >\n          @for (statusOption of statusList; track statusOption) {\n            <label\n              class=\"c8y-checkbox m-t-0 gap-4\"\n              [title]=\"STATUS_LABELS[statusOption] | translate\"\n            >\n              <input\n                type=\"checkbox\"\n                [formControlName]=\"statusOption\"\n                [name]=\"statusOption\"\n              />\n              <span class=\"a-s-center\"></span>\n              <i\n                class=\"a-s-center m-l-4 m-r-4 text-gray-dark c8y-icon icon-20\"\n                [c8yIcon]=\"\n                  statusOption === CLEARED_STATUS_VALUE\n                    ? C8Y_ALERT_IDLE_ICON\n                    : statusOption === ACKNOWLEDGE_STATUS_VALUE\n                      ? BELL_SLASH_ICON\n                      : BELL_ICON\n                \"\n              ></i>\n              <span>{{ STATUS_LABELS[statusOption] | translate }}</span>\n            </label>\n          }\n          <c8y-messages>\n            @if (formGroup.controls.status.hasError('required')) {\n              <c8y-message>\n                {{ 'Select at least one status.' | translate }}\n              </c8y-message>\n            }\n          </c8y-messages>\n        </c8y-form-group>\n      </fieldset>\n    </div>\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        data-cy=\"c8y-alarm-list-widget-config--child-devices-section\"\n      >\n        <legend>{{ 'Child devices' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          <label\n            class=\"c8y-switch\"\n            [title]=\"'Show alarms from child devices' | translate\"\n            data-cy=\"c8y-alarm-list-widget-config--child-devices-label\"\n          >\n            <input\n              type=\"checkbox\"\n              formControlName=\"showAlarmsForChildren\"\n              data-cy=\"c8y-alarm-list-widget-config--showAlarmsForChildren-checkbox\"\n            />\n            <span></span>\n            <span>{{ 'Show alarms' | translate }}</span>\n            <span class=\"sr-only\">{{ 'Show alarms' | translate }}</span>\n          </label>\n        </c8y-form-group>\n      </fieldset>\n    </div>\n\n    <div class=\"col-xs-12\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Types' | translate }}</legend>\n        <c8y-form-group\n          class=\"m-b-8\"\n          formArrayName=\"types\"\n        >\n          @for (type of types.controls; track type; let i = $index) {\n            <div\n              class=\"input-group m-b-4\"\n              data-cy=\"c8y-alarm-list-widget-config--types-elements\"\n            >\n              <input\n                class=\"form-control\"\n                type=\"text\"\n                [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'c8y_Alarm' }\"\n                [formControlName]=\"i\"\n              />\n              <div class=\"input-group-btn\">\n                <button\n                  class=\"btn-dot btn-dot--danger m-l-auto\"\n                  [title]=\"'Remove' | translate\"\n                  type=\"button\"\n                  (click)=\"removeType(i)\"\n                  data-cy=\"c8y-alarm-list-widget-config--types-remove-type\"\n                  [disabled]=\"types.controls?.length === 1 && !type.value\"\n                >\n                  <i c8yIcon=\"minus-circle\"></i>\n                </button>\n              </div>\n              @if (i === types.controls.length - 1) {\n                <div class=\"input-group-btn\">\n                  <button\n                    class=\"btn-dot btn-dot--primary m-l-auto\"\n                    [title]=\"'Add alarm type' | translate\"\n                    type=\"button\"\n                    (click)=\"addType()\"\n                    data-cy=\"c8y-alarm-list-widget-config--types-add-type\"\n                  >\n                    <i c8yIcon=\"plus-circle\"></i>\n                  </button>\n                </div>\n              }\n            </div>\n          }\n        </c8y-form-group>\n      </fieldset>\n    </div>\n  </form>\n}\n\n<ng-template #alarmListPreview>\n  @if ((config$ | async)?.displayMode !== 'dashboard') {\n    <c8y-local-controls\n      [controls]=\"controls\"\n      [displayMode]=\"(config$ | async)?.displayMode\"\n      [config]=\"config$ | async\"\n      [disabled]=\"true\"\n    ></c8y-local-controls>\n  }\n  <c8y-alarms-list\n    [alarms]=\"alarms$ | async\"\n    [isInPreviewMode]=\"true\"\n    [isInitialLoading]=\"isLoading\"\n    [navigationOptions]=\"{\n      allowNavigationToAlarmsView: false,\n      alwaysNavigateToAllAlarms: false,\n      includeClearedQueryParams: false,\n      queryParamsHandling: 'merge'\n    }\"\n    data-cy=\"c8y-alarm-list-widget-config--preview-alarm-list\"\n  ></c8y-alarms-list>\n</ng-template>\n\n<ng-template #dateSelectionHelpTemplate>\n  <div [innerHTML]=\"dateSelectionHelp\"></div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.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: i5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i5.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i5.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i5.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i5.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { 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: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: AlarmsDateFilterComponent, selector: "c8y-alarms-date-filter", inputs: ["DEFAULT_INTERVAL", "updateQueryParams", "date"], outputs: ["dateFilterChange"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: AlarmsListComponent, selector: "c8y-alarms-list", inputs: ["alarms", "hasPermissions", "typeFilters", "loadMoreMode", "navigationOptions", "isInitialLoading", "splitView", "isInPreviewMode"], outputs: ["onSelectedAlarm", "onScrollingStateChange"] }, { kind: "component", type: LocalControlsComponent, selector: "c8y-local-controls", inputs: ["controls", "displayMode", "config", "isLoading", "disabled"], outputs: ["configChange", "refresh"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: SeverityIconPipe, name: "severityIcon" }, { kind: "pipe", type: SortingDescriptionPopoverMessagePipe, name: "sortingDescriptionPopoverMessage" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmListWidgetConfigComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-alarm-list-widget-config', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], imports: [
                        FormsModule,
                        ReactiveFormsModule,
                        PopoverDirective,
                        FormGroupComponent,
                        AlarmsDateFilterComponent,
                        RequiredInputPlaceholderDirective,
                        NgClass,
                        IconDirective,
                        MessagesComponent,
                        MessageDirective,
                        AlarmsListComponent,
                        C8yTranslatePipe,
                        AsyncPipe,
                        SeverityIconPipe,
                        SortingDescriptionPopoverMessagePipe,
                        LocalControlsComponent
                    ], template: "<div\n  class=\"p-l-24 p-r-24\"\n  [style.pointer-events]=\"'auto'\"\n  [style.opacity]=\"1\"\n></div>\n\n@if (formGroup) {\n  <form\n    class=\"row d-flex flex-wrap\"\n    [formGroup]=\"formGroup\"\n  >\n    <div class=\"col-md-6\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Order`of items on a list, noun`' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          @for (order of orderList; track order; let i = $index) {\n            <div\n              class=\"d-flex p-b-8 p-t-4 a-i-center\"\n              data-cy=\"c8y-alarm-list-widget-config--order-elements\"\n            >\n              <label\n                class=\"c8y-radio gap-4\"\n                title=\"{{ ALARM_ORDER_LABELS[order] | translate }}\"\n              >\n                <input\n                  type=\"radio\"\n                  [value]=\"order\"\n                  formControlName=\"order\"\n                />\n                <span class=\"a-s-center\"></span>\n                <span class=\"text-truncate\">{{ ALARM_ORDER_LABELS[order] | translate }}</span>\n              </label>\n              <button\n                class=\"btn-help btn-help--sm\"\n                [attr.aria-label]=\"'Help' | translate\"\n                [popover]=\"order | sortingDescriptionPopoverMessage | translate\"\n                placement=\"right\"\n                triggers=\"focus\"\n                container=\"body\"\n                type=\"button\"\n                [adaptivePosition]=\"true\"\n              ></button>\n            </div>\n          }\n        </c8y-form-group>\n      </fieldset>\n    </div>\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        formGroupName=\"severities\"\n      >\n        <legend>{{ 'Severities' | translate }}</legend>\n        <c8y-form-group\n          [hasError]=\"formGroup.controls.severities.hasError('required')\"\n          [ngClass]=\"{\n            'm-b-8': !formGroup.controls.severities.hasError('required')\n          }\"\n          data-cy=\"c8y-alarm-list-widget-config--severities-elements\"\n        >\n          @for (severityOption of severityList; track severityOption) {\n            <label\n              class=\"c8y-checkbox m-t-0 gap-4\"\n              [title]=\"SEVERITY_LABELS[severityOption] | translate\"\n            >\n              <input\n                type=\"checkbox\"\n                [formControlName]=\"severityOption\"\n                [name]=\"severityOption\"\n              />\n              <span class=\"a-s-center\"></span>\n              @let severityIcon = severityOption | severityIcon;\n              <i\n                class=\"a-s-center m-r-4 icon-20 {{ severityIcon.iconClass }}\"\n                [c8yIcon]=\"severityIcon.c8yIcon\"\n              ></i>\n              <span>{{ SEVERITY_LABELS[severityOption] | translate }}</span>\n            </label>\n          }\n          <c8y-messages>\n            @if (formGroup.controls.severities.hasError('required')) {\n              <c8y-message>\n                {{ 'Select at least one severity.' | translate }}\n              </c8y-message>\n            }\n          </c8y-messages>\n        </c8y-form-group>\n      </fieldset>\n      @if (showDateFilter) {\n        <fieldset class=\"c8y-fieldset\">\n          <legend>{{ 'Date filter' | translate }}</legend>\n          <c8y-form-group class=\"m-b-8\">\n            <c8y-alarms-date-filter\n              [updateQueryParams]=\"false\"\n              [DEFAULT_INTERVAL]=\"config.interval || 'none'\"\n              formControlName=\"dateFilter\"\n              (dateFilterChange)=\"onDateFilterChange($event)\"\n            ></c8y-alarms-date-filter>\n          </c8y-form-group>\n        </fieldset>\n      }\n    </div>\n\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        formGroupName=\"status\"\n      >\n        <legend data-cy=\"c8y-alarm-list-widget-config-status-label\">\n          {{ 'Status' | translate }}\n        </legend>\n        <c8y-form-group\n          [hasError]=\"formGroup.controls.status.hasError('required')\"\n          [ngClass]=\"{\n            'm-b-8': !formGroup.controls.status.hasError('required')\n          }\"\n          data-cy=\"c8y-alarm-list-widget-config--status-elements\"\n        >\n          @for (statusOption of statusList; track statusOption) {\n            <label\n              class=\"c8y-checkbox m-t-0 gap-4\"\n              [title]=\"STATUS_LABELS[statusOption] | translate\"\n            >\n              <input\n                type=\"checkbox\"\n                [formControlName]=\"statusOption\"\n                [name]=\"statusOption\"\n              />\n              <span class=\"a-s-center\"></span>\n              <i\n                class=\"a-s-center m-l-4 m-r-4 text-gray-dark c8y-icon icon-20\"\n                [c8yIcon]=\"\n                  statusOption === CLEARED_STATUS_VALUE\n                    ? C8Y_ALERT_IDLE_ICON\n                    : statusOption === ACKNOWLEDGE_STATUS_VALUE\n                      ? BELL_SLASH_ICON\n                      : BELL_ICON\n                \"\n              ></i>\n              <span>{{ STATUS_LABELS[statusOption] | translate }}</span>\n            </label>\n          }\n          <c8y-messages>\n            @if (formGroup.controls.status.hasError('required')) {\n              <c8y-message>\n                {{ 'Select at least one status.' | translate }}\n              </c8y-message>\n            }\n          </c8y-messages>\n        </c8y-form-group>\n      </fieldset>\n    </div>\n    <div class=\"col-md-6 col-xs-12\">\n      <fieldset\n        class=\"c8y-fieldset\"\n        data-cy=\"c8y-alarm-list-widget-config--child-devices-section\"\n      >\n        <legend>{{ 'Child devices' | translate }}</legend>\n        <c8y-form-group class=\"m-b-8\">\n          <label\n            class=\"c8y-switch\"\n            [title]=\"'Show alarms from child devices' | translate\"\n            data-cy=\"c8y-alarm-list-widget-config--child-devices-label\"\n          >\n            <input\n              type=\"checkbox\"\n              formControlName=\"showAlarmsForChildren\"\n              data-cy=\"c8y-alarm-list-widget-config--showAlarmsForChildren-checkbox\"\n            />\n            <span></span>\n            <span>{{ 'Show alarms' | translate }}</span>\n            <span class=\"sr-only\">{{ 'Show alarms' | translate }}</span>\n          </label>\n        </c8y-form-group>\n      </fieldset>\n    </div>\n\n    <div class=\"col-xs-12\">\n      <fieldset class=\"c8y-fieldset\">\n        <legend>{{ 'Types' | translate }}</legend>\n        <c8y-form-group\n          class=\"m-b-8\"\n          formArrayName=\"types\"\n        >\n          @for (type of types.controls; track type; let i = $index) {\n            <div\n              class=\"input-group m-b-4\"\n              data-cy=\"c8y-alarm-list-widget-config--types-elements\"\n            >\n              <input\n                class=\"form-control\"\n                type=\"text\"\n                [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'c8y_Alarm' }\"\n                [formControlName]=\"i\"\n              />\n              <div class=\"input-group-btn\">\n                <button\n                  class=\"btn-dot btn-dot--danger m-l-auto\"\n                  [title]=\"'Remove' | translate\"\n                  type=\"button\"\n                  (click)=\"removeType(i)\"\n                  data-cy=\"c8y-alarm-list-widget-config--types-remove-type\"\n                  [disabled]=\"types.controls?.length === 1 && !type.value\"\n                >\n                  <i c8yIcon=\"minus-circle\"></i>\n                </button>\n              </div>\n              @if (i === types.controls.length - 1) {\n                <div class=\"input-group-btn\">\n                  <button\n                    class=\"btn-dot btn-dot--primary m-l-auto\"\n                    [title]=\"'Add alarm type' | translate\"\n                    type=\"button\"\n                    (click)=\"addType()\"\n                    data-cy=\"c8y-alarm-list-widget-config--types-add-type\"\n                  >\n                    <i c8yIcon=\"plus-circle\"></i>\n                  </button>\n                </div>\n              }\n            </div>\n          }\n        </c8y-form-group>\n      </fieldset>\n    </div>\n  </form>\n}\n\n<ng-template #alarmListPreview>\n  @if ((config$ | async)?.displayMode !== 'dashboard') {\n    <c8y-local-controls\n      [controls]=\"controls\"\n      [displayMode]=\"(config$ | async)?.displayMode\"\n      [config]=\"config$ | async\"\n      [disabled]=\"true\"\n    ></c8y-local-controls>\n  }\n  <c8y-alarms-list\n    [alarms]=\"alarms$ | async\"\n    [isInPreviewMode]=\"true\"\n    [isInitialLoading]=\"isLoading\"\n    [navigationOptions]=\"{\n      allowNavigationToAlarmsView: false,\n      alwaysNavigateToAllAlarms: false,\n      includeClearedQueryParams: false,\n      queryParamsHandling: 'merge'\n    }\"\n    data-cy=\"c8y-alarm-list-widget-config--preview-alarm-list\"\n  ></c8y-alarms-list>\n</ng-template>\n\n<ng-template #dateSelectionHelpTemplate>\n  <div [innerHTML]=\"dateSelectionHelp\"></div>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: AlarmWidgetService }, { type: i2.AlarmService }, { type: i1.AlarmsViewService }, { type: i4.AlertService }, { type: i5.NgForm }, { type: i5.FormBuilder }, { type: i6.WidgetConfigService }], propDecorators: { config: [{
                type: Input
            }], previewMapSet: [{
                type: ViewChild,
                args: ['alarmListPreview']
            }] } });

class AlarmListWidgetComponent {
    constructor() {
        this.alarmWidgetService = inject(AlarmWidgetService);
        this.alarmService = inject(AlarmService);
        this.dashboardChild = inject(DashboardChildComponent);
        this.alertService = inject(AlertService);
        this.widgetConfigMigrationService = inject(WidgetConfigMigrationService);
        this.displayMode = signal(GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD, ...(ngDevMode ? [{ debugName: "displayMode" }] : []));
        this.contextConfig = signal({}, ...(ngDevMode ? [{ debugName: "contextConfig" }] : []));
        this.isLinkedToGlobal = signal(undefined, ...(ngDevMode ? [{ debugName: "isLinkedToGlobal" }] : []));
        this.alarms$ = new BehaviorSubject(null);
        this.isLoading$ = new BehaviorSubject(true);
        this.widgetControls = signal(PRESET_NAME.ALARM_LIST, ...(ngDevMode ? [{ debugName: "widgetControls" }] : []));
        this.GLOBAL_CONTEXT_DISPLAY_MODE = GLOBAL_CONTEXT_DISPLAY_MODE;
        this.CONTEXT_FEATURE = CONTEXT_FEATURE;
        this.REFRESH_OPTION = REFRESH_OPTION;
        this.PRESET_NAME = PRESET_NAME;
        this.TIMEOUT_ERROR_TEXT = gettext('The request is taking longer than usual. We apologize for the inconvenience.');
        this.SERVER_ERROR_TEXT = gettext('Server error occurred.');
        this.unsubscribe$ = new Subject();
        this.hasPermissions = true;
    }
    async ngOnInit() {
        this.alerts.setAlertGroupDismissStrategy('warning', DismissAlertStrategy.TEMPORARY_OR_PERMANENT);
        const alarmsWidgetId = this.dashboardChild['data']?.componentId ?? this.dashboardChild['data']?.name;
        // Check for legacy angularJS widget without proper configuration
        const isLegacyWidgetWithoutConfiguration = (this.config?.widgetId ?? alarmsWidgetId) === defaultWidgetIds.ALL_CRITICAL_ALARMS ||
            (this.config?.widgetId ?? alarmsWidgetId) === defaultWidgetIds.RECENT_ALARMS ||
            isEmpty(this.config) ||
            (isMatch(this.config, { displaySettings: { globalAutoRefreshContext: true } }) &&
                !this.config['options']?.device &&
                !this.config.types &&
                !this.config.status &&
                !this.config.severities);
        if (isLegacyWidgetWithoutConfiguration) {
            let updatedId = alarmsWidgetId;
            const assetAlarms = this.dashboardChild['data']?.title === 'Active, critical alarms' && 'Asset alarms';
            const recentAlarms = this.dashboardChild['data']?.title === 'Recent alarms' && 'Recent alarms';
            if (assetAlarms) {
                updatedId = ASSET_ALARMS_WIDGET_ID;
            }
            if (recentAlarms) {
                updatedId = RECENT_ALARMS_WIDGET_ID;
            }
            this.setLegacyRecentOrCriticalAlarmWidgetConfig(updatedId);
            this.config.widgetId = updatedId;
        }
        else if (this.alarmWidgetService.isOldAlarmConfigStructure(this.config)) {
            const mappedConfig = this.alarmWidgetService.mapToNewConfigStructure(this.config);
            Object.assign(this.config, mappedConfig);
        }
        if (this.config?.widgetId === RECENT_ALARMS_WIDGET_ID ||
            this.config?.widgetId === ASSET_ALARMS_WIDGET_ID) {
            this.widgetControls.set(PRESET_NAME.ALARM_LIST_LEGACY);
        }
        const migratedConfig = this.widgetConfigMigrationService.migrateWidgetConfig(this.config);
        this.config = merge(this.config, migratedConfig);
        const resolvedWidgetId = this.config?.widgetId ?? alarmsWidgetId ?? defaultWidgetIds.ALARM_LIST;
        this.config.widgetId = resolvedWidgetId;
        const displayMode = this.config.displayMode || GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD;
        this.displayMode.set(displayMode);
        const initialContextConfig = {
            dateTimeContext: this.config.dateTimeContext,
            aggregation: this.config.aggregation,
            isAutoRefreshEnabled: this.config.isAutoRefreshEnabled,
            refreshInterval: this.config.refreshInterval,
            refreshOption: this.config.refreshOption
        };
        this.contextConfig.set(initialContextConfig);
        // In dashboard mode, wait for GlobalContextConnector to emit the first state
        // In config modes, fetch immediately with widget config
        if (displayMode !== GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {
            await this.fetchAlarms();
        }
    }
    ngOnDestroy() {
        if (this.config?.isRealtime) {
            this.unsubscribe$.next();
            this.unsubscribe$.complete();
        }
    }
    onContextChange(event) {
        const { diff, context } = event;
        if (diff.isAutoRefreshEnabled === false &&
            Object.keys(diff).length === 1 &&
            context.refreshOption === REFRESH_OPTION.LIVE) {
            return;
        }
        this.contextConfig.set(event.context);
        void this.fetchAlarms();
    }
    getDashboardChild() {
        return this.dashboardChild;
    }
    onRefresh() {
        void this.fetchAlarms();
    }
    onScrollingStateChange(isScrolling) {
        const current = this.contextConfig();
        if (current.refreshOption === REFRESH_OPTION.HISTORY) {
            return;
        }
        this.contextConfig.set({ ...current, isAutoRefreshEnabled: !isScrolling });
        this.isLinkedToGlobal.set(!isScrolling);
    }
    async fetchAlarms() {
        const alarms = await this.getAlarms();
        this.alarms$.next(alarms);
    }
    async getAlarms() {
        try {
            this.isLoading$.next(true);
            const effectiveConfig = {
                ...this.config,
                ...this.contextConfig()
            };
            return await this.alarmService.list(this.alarmWidgetService.mapConfigToQueryFilter(effectiveConfig));
        }
        catch (error) {
            this.alerts.addAlerts(new DynamicComponentAlert({
                type: 'warning',
                text: error?.name === 'TimeoutError'
                    ? this.TIMEOUT_ERROR_TEXT
                    : (error?.message ?? this.SERVER_ERROR_TEXT)
            }));
            if (error?.res?.status === 403) {
                this.hasPermissions = false;
                return;
            }
            this.alertService.addServerFailure(error);
        }
        finally {
            this.isLoading$.next(false);
        }
    }
    setLegacyRecentOrCriticalAlarmWidgetConfig(widgetId) {
        if (widgetId === RECENT_ALARMS_WIDGET_ID) {
            const predefinedConfig = this.alarmWidgetService.getPredefinedConfiguration(RECENT_ALARMS_WIDGET_ID, this.config);
            Object.assign(this.config, predefinedConfig);
            return;
        }
        if (widgetId === ASSET_ALARMS_WIDGET_ID) {
            const predefinedConfig = this.alarmWidgetService.getPredefinedConfiguration(ASSET_ALARMS_WIDGET_ID, this.config);
            Object.assign(this.config, predefinedConfig);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmListWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AlarmListWidgetComponent, isStandalone: true, selector: "c8y-alarm-list-widget", inputs: { config: "config" }, providers: [AlarmRealtimeService, AlarmWithChildrenRealtimeService], ngImport: i0, template: "@if (displayMode() === GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {\n  <c8y-global-context-connector\n    [controls]=\"widgetControls()\"\n    [config]=\"contextConfig()\"\n    [isLoading]=\"isLoading$ | async\"\n    [dashboardChild]=\"getDashboardChild()\"\n    [linked]=\"isLinkedToGlobal()\"\n    (configChange)=\"onContextChange($event)\"\n    (refresh)=\"onRefresh()\"\n  ></c8y-global-context-connector>\n} @else {\n  <c8y-local-controls\n    [controls]=\"widgetControls()\"\n    [displayMode]=\"displayMode()\"\n    [config]=\"contextConfig()\"\n    [isLoading]=\"isLoading$ | async\"\n    (configChange)=\"onContextChange($event)\"\n    (refresh)=\"onRefresh()\"\n  ></c8y-local-controls>\n}\n\n<c8y-alarms-list\n  #list\n  [alarms]=\"alarms$ | async\"\n  [navigationOptions]=\"{\n    alwaysNavigateToAllAlarms: !config.device,\n    allowNavigationToAlarmsView: true,\n    includeClearedQueryParams: true,\n    queryParamsHandling: ''\n  }\"\n  [isInitialLoading]=\"isLoading$ | async\"\n  [hasPermissions]=\"hasPermissions\"\n  (onScrollingStateChange)=\"onScrollingStateChange($event)\"\n></c8y-alarms-list>\n", dependencies: [{ kind: "component", type: AlarmsListComponent, selector: "c8y-alarms-list", inputs: ["alarms", "hasPermissions", "typeFilters", "loadMoreMode", "navigationOptions", "isInitialLoading", "splitView", "isInPreviewMode"], outputs: ["onSelectedAlarm", "onScrollingStateChange"] }, { kind: "component", type: LocalControlsComponent, selector: "c8y-local-controls", inputs: ["controls", "displayMode", "config", "isLoading", "disabled"], outputs: ["configChange", "refresh"] }, { kind: "component", type: GlobalContextConnectorComponent, selector: "c8y-global-context-connector", inputs: ["controls", "config", "isLoading", "dashboardChild", "linked"], outputs: ["configChange", "refresh"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmListWidgetComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-alarm-list-widget', providers: [AlarmRealtimeService, AlarmWithChildrenRealtimeService], imports: [AlarmsListComponent, AsyncPipe, LocalControlsComponent, GlobalContextConnectorComponent], template: "@if (displayMode() === GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD) {\n  <c8y-global-context-connector\n    [controls]=\"widgetControls()\"\n    [config]=\"contextConfig()\"\n    [isLoading]=\"isLoading$ | async\"\n    [dashboardChild]=\"getDashboardChild()\"\n    [linked]=\"isLinkedToGlobal()\"\n    (configChange)=\"onContextChange($event)\"\n    (refresh)=\"onRefresh()\"\n  ></c8y-global-context-connector>\n} @else {\n  <c8y-local-controls\n    [controls]=\"widgetControls()\"\n    [displayMode]=\"displayMode()\"\n    [config]=\"contextConfig()\"\n    [isLoading]=\"isLoading$ | async\"\n    (configChange)=\"onContextChange($event)\"\n    (refresh)=\"onRefresh()\"\n  ></c8y-local-controls>\n}\n\n<c8y-alarms-list\n  #list\n  [alarms]=\"alarms$ | async\"\n  [navigationOptions]=\"{\n    alwaysNavigateToAllAlarms: !config.device,\n    allowNavigationToAlarmsView: true,\n    includeClearedQueryParams: true,\n    queryParamsHandling: ''\n  }\"\n  [isInitialLoading]=\"isLoading$ | async\"\n  [hasPermissions]=\"hasPermissions\"\n  (onScrollingStateChange)=\"onScrollingStateChange($event)\"\n></c8y-alarms-list>\n" }]
        }], propDecorators: { config: [{
                type: Input
            }] } });

class AlarmsWidgetModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmsWidgetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: AlarmsWidgetModule, imports: [AlarmsModule,
            CommonModule,
            CountdownIntervalModule,
            DocsModule,
            FormsModule$1,
            CommonModule$1,
            FormsModule,
            PopoverModule,
            ReactiveFormsModule,
            RouterModule, i1$1.TooltipModule, AlarmListWidgetComponent,
            AlarmListWidgetConfigComponent,
            SeverityIconPipe,
            SortingDescriptionPopoverMessagePipe,
            GlobalContextConfigComponent,
            GlobalContextInlineComponent,
            ConfigContextSelectorComponent,
            GlobalContextWidgetWrapperComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmsWidgetModule, imports: [AlarmsModule,
            CommonModule,
            CountdownIntervalModule,
            DocsModule,
            FormsModule$1,
            CommonModule$1,
            FormsModule,
            PopoverModule,
            ReactiveFormsModule,
            RouterModule,
            TooltipModule.forRoot(),
            AlarmListWidgetComponent,
            AlarmListWidgetConfigComponent,
            GlobalContextConfigComponent,
            GlobalContextInlineComponent,
            ConfigContextSelectorComponent,
            GlobalContextWidgetWrapperComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AlarmsWidgetModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        AlarmsModule,
                        CommonModule,
                        CountdownIntervalModule,
                        DocsModule,
                        FormsModule$1,
                        CommonModule$1,
                        FormsModule,
                        PopoverModule,
                        ReactiveFormsModule,
                        RouterModule,
                        TooltipModule.forRoot(),
                        AlarmListWidgetComponent,
                        AlarmListWidgetConfigComponent,
                        SeverityIconPipe,
                        SortingDescriptionPopoverMessagePipe,
                        GlobalContextConfigComponent,
                        GlobalContextInlineComponent,
                        ConfigContextSelectorComponent,
                        GlobalContextWidgetWrapperComponent
                    ]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { ALARM_ORDER_LABELS, ALARM_ORDER_VALUES, ASSET_ALARMS_WIDGET_ID, AlarmListWidgetComponent, AlarmListWidgetConfigComponent, AlarmWidgetService, AlarmsWidgetModule, DEFAULT_PAGE_SIZE, GLOBAL_INTERVAL_OPTION, RECENT_ALARMS_WIDGET_ID, SeverityIconPipe, SortingDescriptionPopoverMessagePipe };
//# sourceMappingURL=c8y-ngx-components-widgets-implementations-alarms.mjs.map