UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

1,459 lines 80 kB
import * as i0 from '@angular/core';
import { Injectable, Component, ElementRef, HostListener, ViewChild, EventEmitter, forwardRef, Output, Input, NgModule } from '@angular/core';
import * as i1$1 from '@c8y/ngx-components';
import { gettext, IconDirective, C8yTranslatePipe, BaseColumn, C8yTranslateDirective, getBasicInputArrayFormFieldConfig, DatePipe, DeviceStatusComponent, SendStatus, PushStatus, DataGridService, Status, alertOnError, FilteringActionType, DataGridComponent, ProductExperienceDirective, EmptyStateContextDirective, EmptyStateComponent, ColumnDirective, PRODUCT_EXPERIENCE_EVENT_SOURCE, CommonModule, FormsModule, DeviceStatusModule, DataGridModule, DynamicFormsModule, ProductExperienceModule } from '@c8y/ngx-components';
import * as i1 from '@ngx-translate/core';
import { map, sortBy, remove, cloneDeep } from 'lodash-es';
import { NgIf, NgFor } from '@angular/common';
import { FormGroup } from '@angular/forms';
import { PopoverDirective, PopoverModule } from 'ngx-bootstrap/popover';
import { AssetSelectorComponent, AssetSelectorModule } from '@c8y/ngx-components/assets-navigator';
import { gettext as gettext$1 } from '@c8y/ngx-components/gettext';
import { Subject } from 'rxjs';
import * as i1$2 from '@c8y/client';
import { RouterModule } from '@angular/router';

/**
 * Service contains logic extracted from the device-grid service to avoid circular dependency MTM-40239.
 */
class ColumnUtilService {
    constructor(translateService) {
        this.translateService = translateService;
    }
    getAlarmsHref(device) {
        return `${this.getHref(device)}/alarms`;
    }
    getHref(groupOrDevice, prefix = '#/') {
        if (groupOrDevice.c8y_IsDeviceGroup || groupOrDevice.c8y_IsDynamicGroup) {
            return `${prefix}group/${groupOrDevice.id}`;
        }
        return `${prefix}device/${groupOrDevice.id}`;
    }
    getParentsNames(device, featuredParentId) {
        const assetParentsReferences = device.assetParents.references;
        const assetParents = map(assetParentsReferences, 'managedObject');
        const sortedByName = sortBy(assetParents, ['name']);
        const featuredItems = remove(sortedByName, { id: featuredParentId });
        const items = featuredItems.concat(sortedByName);
        const names = map(items, 'name');
        return names.join(', ');
    }
    getModel(device) {
        const hardware = this.getHardware(device);
        return hardware && hardware.model;
    }
    getProperName(device) {
        const { id, name } = device;
        return name ? name : this.translateService.instant('Device {{id}}', { id });
    }
    getSerialNumber(device) {
        const hardware = this.getHardware(device);
        return hardware && hardware['serialNumber'];
    }
    getHardware(device) {
        return device && device['c8y_Hardware'];
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ColumnUtilService, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ColumnUtilService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ColumnUtilService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.TranslateService }] });

class AlarmsCellRendererComponent {
    constructor(context, columnUtilService) {
        this.context = context;
        this.columnUtilService = columnUtilService;
        this.linkAriaLabel = gettext('See alarms for device "{{ name }}"');
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AlarmsCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }, { token: ColumnUtilService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AlarmsCellRendererComponent, isStandalone: true, selector: "c8y-alarms-cell-renderer", ngImport: i0, template: "<a\n  class=\"d-flex a-i-center flex-wrap gap-4 no-decoration\"\n  [href]=\"columnUtilService.getAlarmsHref(context.item)\"\n  [attr.aria-label]=\"\n    linkAriaLabel | translate: { name: columnUtilService.getProperName(context.item) }\n  \"\n  *ngIf=\"\n    context.item.c8y_ActiveAlarmsStatus?.critical ||\n    context.item.c8y_ActiveAlarmsStatus?.major ||\n    context.item.c8y_ActiveAlarmsStatus?.minor ||\n    context.item.c8y_ActiveAlarmsStatus?.warning\n  \"\n>\n  <span\n    class=\"c8y-icon-badge\"\n    data-cy=\"alarms.cell-renderer--critical-alarm-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.critical }} {{ 'Critical alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.critical\"\n  >\n    <i [c8yIcon]=\"'exclamation-circle'\" class=\"status critical stroked-icon\" data-cy=\"alarms.cell-renderer--critical-alarm-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.critical }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.major }} {{ 'Major alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.major\"\n  >\n    <i [c8yIcon]=\"'warning'\" class=\"status major stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.major }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.minor }} {{ 'Minor alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.minor\"\n  >\n    <i [c8yIcon]=\"'high-priority'\" class=\"status minor stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.minor }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.warning }} {{ 'Warning alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.warning\"\n  >\n    <i [c8yIcon]=\"'info-circle'\" class=\"status warning stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.warning }}</span>\n  </span>\n</a>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AlarmsCellRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-alarms-cell-renderer', imports: [NgIf, IconDirective, C8yTranslatePipe], template: "<a\n  class=\"d-flex a-i-center flex-wrap gap-4 no-decoration\"\n  [href]=\"columnUtilService.getAlarmsHref(context.item)\"\n  [attr.aria-label]=\"\n    linkAriaLabel | translate: { name: columnUtilService.getProperName(context.item) }\n  \"\n  *ngIf=\"\n    context.item.c8y_ActiveAlarmsStatus?.critical ||\n    context.item.c8y_ActiveAlarmsStatus?.major ||\n    context.item.c8y_ActiveAlarmsStatus?.minor ||\n    context.item.c8y_ActiveAlarmsStatus?.warning\n  \"\n>\n  <span\n    class=\"c8y-icon-badge\"\n    data-cy=\"alarms.cell-renderer--critical-alarm-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.critical }} {{ 'Critical alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.critical\"\n  >\n    <i [c8yIcon]=\"'exclamation-circle'\" class=\"status critical stroked-icon\" data-cy=\"alarms.cell-renderer--critical-alarm-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.critical }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.major }} {{ 'Major alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.major\"\n  >\n    <i [c8yIcon]=\"'warning'\" class=\"status major stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.major }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.minor }} {{ 'Minor alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.minor\"\n  >\n    <i [c8yIcon]=\"'high-priority'\" class=\"status minor stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.minor }}</span>\n  </span>\n  <span\n    class=\"c8y-icon-badge\"\n    title=\"{{ context.item.c8y_ActiveAlarmsStatus?.warning }} {{ 'Warning alarms' | translate }}\"\n    *ngIf=\"context.item.c8y_ActiveAlarmsStatus?.warning\"\n  >\n    <i [c8yIcon]=\"'info-circle'\" class=\"status warning stroked-icon\"></i>\n    <span class=\"badge badge-info\">{{ context.item.c8y_ActiveAlarmsStatus?.warning }}</span>\n  </span>\n</a>\n" }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }, { type: ColumnUtilService }] });

class AlarmsHeaderCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AlarmsHeaderCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AlarmsHeaderCellRendererComponent, isStandalone: true, selector: "c8y-alarms-header-cell-renderer", ngImport: i0, template: `
    <div class="d-flex">
      <span class="text-truncate" [title]="context.property.header | translate">
        {{ context.property.header | translate }}
      </span>
      <button
        class="btn-help btn-help--sm a-s-center"
        [attr.aria-label]="'Help' | translate"
        [popover]="'Only includes alarms for the parent device.' | translate"
        placement="bottom"
        triggers="focus"
        container="body"
        type="button"
        (click)="$event.stopPropagation()"
      >
        <i c8yIcon="question-circle-o"></i>
      </button>
    </div>
  `, isInline: true, dependencies: [{ 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: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AlarmsHeaderCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: `
    <div class="d-flex">
      <span class="text-truncate" [title]="context.property.header | translate">
        {{ context.property.header | translate }}
      </span>
      <button
        class="btn-help btn-help--sm a-s-center"
        [attr.aria-label]="'Help' | translate"
        [popover]="'Only includes alarms for the parent device.' | translate"
        placement="bottom"
        triggers="focus"
        container="body"
        type="button"
        (click)="$event.stopPropagation()"
      >
        <i c8yIcon="question-circle-o"></i>
      </button>
    </div>
  `,
                    selector: 'c8y-alarms-header-cell-renderer',
                    imports: [PopoverDirective, IconDirective, C8yTranslatePipe]
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }] });

class AlarmsDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'alarms';
        this.header = gettext('Alarms');
        this.headerCellRendererComponent = AlarmsHeaderCellRendererComponent;
        this.cellRendererComponent = AlarmsCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: [
                {
                    type: 'object',
                    key: 'alarm',
                    templateOptions: {
                        label: 'Show items'
                    },
                    fieldGroup: [
                        {
                            key: 'critical',
                            type: 'switch',
                            props: {
                                label: gettext('With active critical alarms')
                            }
                        },
                        {
                            key: 'major',
                            type: 'switch',
                            props: {
                                label: gettext('With active major alarms')
                            }
                        },
                        {
                            key: 'minor',
                            type: 'switch',
                            props: {
                                label: gettext('With active minor alarms')
                            }
                        },
                        {
                            key: 'warning',
                            type: 'switch',
                            props: {
                                label: gettext('With active warnings')
                            }
                        },
                        {
                            key: 'none',
                            type: 'switch',
                            props: {
                                label: gettext('With no active alarms or warnings')
                            }
                        }
                    ],
                    validators: {
                        atLeastOneSelected: {
                            expression: control => {
                                const alarmGroup = control.value;
                                return (alarmGroup.critical ||
                                    alarmGroup.major ||
                                    alarmGroup.minor ||
                                    alarmGroup.warning ||
                                    alarmGroup.none);
                            }
                        }
                    }
                }
            ],
            formGroup: new FormGroup({}),
            getFilter: model => {
                const filter = {};
                const ors = [];
                if (model.alarm.critical) {
                    ors.push({ 'c8y_ActiveAlarmsStatus.critical': { __gt: 0 } });
                }
                if (model.alarm.major) {
                    ors.push({ 'c8y_ActiveAlarmsStatus.major': { __gt: 0 } });
                }
                if (model.alarm.minor) {
                    ors.push({ 'c8y_ActiveAlarmsStatus.minor': { __gt: 0 } });
                }
                if (model.alarm.warning) {
                    ors.push({ 'c8y_ActiveAlarmsStatus.warning': { __gt: 0 } });
                }
                if (model.alarm.none) {
                    ors.push({ __not: { __has: 'c8y_ActiveAlarmsStatus' } });
                    ors.push({
                        __and: map(['critical', 'major', 'minor', 'warning'], sev => {
                            const zero = {};
                            const has = { __not: { __has: undefined } };
                            const key = `c8y_ActiveAlarmsStatus.${sev}`;
                            zero[key] = 0;
                            has.__not.__has = key;
                            return { __or: [zero, has] };
                        })
                    });
                }
                if (ors.length) {
                    filter.__or = ors;
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [
                { path: 'c8y_ActiveAlarmsStatus.critical' },
                { path: 'c8y_ActiveAlarmsStatus.major' },
                { path: 'c8y_ActiveAlarmsStatus.minor' },
                { path: 'c8y_ActiveAlarmsStatus.warning' }
            ]
        };
    }
}

class GroupCellRendererComponent {
    constructor(context, columnUtilService) {
        this.context = context;
        this.columnUtilService = columnUtilService;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GroupCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }, { token: ColumnUtilService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: GroupCellRendererComponent, isStandalone: true, selector: "c8y-group-cell-renderer", ngImport: i0, template: "<span\n  title=\"{{\n    columnUtilService.getParentsNames(\n      context.item,\n      context.property.externalFilterQuery?.deviceGroupId\n    )\n  }}\"\n>\n  {{\n    columnUtilService.getParentsNames(\n      context.item,\n      context.property.externalFilterQuery?.deviceGroupId\n    )\n  }}\n</span>\n" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GroupCellRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-group-cell-renderer', template: "<span\n  title=\"{{\n    columnUtilService.getParentsNames(\n      context.item,\n      context.property.externalFilterQuery?.deviceGroupId\n    )\n  }}\"\n>\n  {{\n    columnUtilService.getParentsNames(\n      context.item,\n      context.property.externalFilterQuery?.deviceGroupId\n    )\n  }}\n</span>\n" }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }, { type: ColumnUtilService }] });

class GroupFilteringFormRendererComponent {
    constructor(context) {
        this.context = context;
        this.preselected = [];
        this.initialSelection = [];
        this.isApplyDisabled = true;
    }
    onEnterKeyUp(event) {
        event.stopPropagation();
        this.applyFilter();
    }
    onEscapeKeyDown(event) {
        event.stopPropagation();
        this.resetFilter();
    }
    ngOnInit() {
        const column = this.context.property;
        this.model = cloneDeep(column.externalFilterQuery || {});
        this.preselected = this.model.selectedNodes || [];
        this.initialSelection = [...this.preselected];
    }
    ngAfterViewInit() {
        setTimeout(() => {
            try {
                this.assetSelector.nativeElement.querySelector('input').focus();
            }
            catch (ex) {
                // intended empty
            }
        }, 250);
    }
    applyFilter() {
        this.context.applyFilter({
            externalFilterQuery: this.model
        });
        this.isApplyDisabled = true; // Disable button after applying the filter
        this.initialSelection = [...this.model.selectedNodes]; // Update initial selection
    }
    resetFilter() {
        this.context.resetFilter();
        this.model.selectedNodes = [];
        this.preselected = [];
        this.isApplyDisabled = true; // Disable button after resetting the filter
    }
    selectionChanged(nodes) {
        this.model.selectedNodes = nodes.items;
        this.isApplyDisabled = !this.isSelectionChanged();
    }
    isSelectionChanged() {
        if (this.model.selectedNodes.length !== this.initialSelection.length) {
            return true;
        }
        const currentSelectionSet = new Set(this.model.selectedNodes);
        for (const item of this.initialSelection) {
            if (!currentSelectionSet.has(item)) {
                return true;
            }
        }
        return false;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GroupFilteringFormRendererComponent, deps: [{ token: i1$1.FilteringFormRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: GroupFilteringFormRendererComponent, isStandalone: true, selector: "ng-component", host: { listeners: { "keyup.enter": "onEnterKeyUp($event)", "keydown.escape": "onEscapeKeyDown($event)" } }, viewQueries: [{ propertyName: "assetSelector", first: true, predicate: ["assetSelector"], descendants: true, read: ElementRef }], ngImport: i0, template: "<c8y-asset-selector\n  class=\"bg-component\"\n  #assetSelector\n  [config]=\"{\n    groupsOnly: true,\n    multi: true,\n    groupsSelectable: true,\n    search: true,\n    label: ''\n  }\"\n  [selected]=\"preselected\"\n  (onSelected)=\"selectionChanged($event)\"\n></c8y-asset-selector>\n\n<div class=\"data-grid__dropdown__footer d-flex separator-top\">\n  <button\n    class=\"btn btn-default btn-sm m-r-8 flex-grow\"\n    title=\"{{ 'Reset' | translate }}\"\n    (click)=\"resetFilter()\"\n    translate\n  >\n    Reset\n  </button>\n\n  <button\n    class=\"btn btn-primary btn-sm flex-grow\"\n    title=\"{{ 'Apply' | translate }}\"\n    (click)=\"applyFilter()\"\n    [disabled]=\"isApplyDisabled\"\n    translate\n  >\n    Apply\n  </button>\n</div>\n", dependencies: [{ kind: "component", type: AssetSelectorComponent, selector: "c8y-asset-selector", inputs: ["config", "active", "index", "asset", "selectedDevice", "selected", "rootNode", "selectedItems", "container", "isNodeSelectable", "disabled"], outputs: ["onSelected", "onClearSelected", "onRowSelected", "onLoad"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GroupFilteringFormRendererComponent, decorators: [{
            type: Component,
            args: [{ imports: [AssetSelectorComponent, C8yTranslateDirective, C8yTranslatePipe], template: "<c8y-asset-selector\n  class=\"bg-component\"\n  #assetSelector\n  [config]=\"{\n    groupsOnly: true,\n    multi: true,\n    groupsSelectable: true,\n    search: true,\n    label: ''\n  }\"\n  [selected]=\"preselected\"\n  (onSelected)=\"selectionChanged($event)\"\n></c8y-asset-selector>\n\n<div class=\"data-grid__dropdown__footer d-flex separator-top\">\n  <button\n    class=\"btn btn-default btn-sm m-r-8 flex-grow\"\n    title=\"{{ 'Reset' | translate }}\"\n    (click)=\"resetFilter()\"\n    translate\n  >\n    Reset\n  </button>\n\n  <button\n    class=\"btn btn-primary btn-sm flex-grow\"\n    title=\"{{ 'Apply' | translate }}\"\n    (click)=\"applyFilter()\"\n    [disabled]=\"isApplyDisabled\"\n    translate\n  >\n    Apply\n  </button>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1$1.FilteringFormRendererContext }], propDecorators: { assetSelector: [{
                type: ViewChild,
                args: ['assetSelector', { static: false, read: ElementRef }]
            }], onEnterKeyUp: [{
                type: HostListener,
                args: ['keyup.enter', ['$event']]
            }], onEscapeKeyDown: [{
                type: HostListener,
                args: ['keydown.escape', ['$event']]
            }] } });

class GroupDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'group';
        this.header = gettext('Group');
        this.cellRendererComponent = GroupCellRendererComponent;
        this.filteringFormRendererComponent = GroupFilteringFormRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            generateChips(model) {
                if (model.selectedNodes) {
                    return model.selectedNodes.map(mo => ({
                        displayValue: mo.name,
                        value: mo,
                        remove() {
                            const { externalFilterQuery, columnName, value } = this;
                            const nodes = externalFilterQuery.selectedNodes.filter(node => node.id !== value.id);
                            return {
                                externalFilterQuery: { selectedNodes: nodes },
                                columnName: columnName
                            };
                        }
                    }));
                }
            },
            getFilter(model) {
                const filter = {};
                if (model.selectedNodes) {
                    filter.__or = model.selectedNodes.map((mo) => {
                        if (mo.c8y_DeviceQueryString) {
                            return { __useFilterQueryString: mo.c8y_DeviceQueryString };
                        }
                        return { __bygroupid: mo.id };
                    });
                }
                return filter;
            }
        };
        this.sortable = false;
    }
}

class ImeiDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.path = 'c8y_Mobile.imei';
        this.name = 'imei';
        this.header = gettext('IMEI');
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'imeis',
                label: gettext('Show items with IMEI'),
                addText: gettext('Add next`IMEI`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: '46543432321'
            }),
            getFilter: (model) => {
                const filter = {};
                if (model.imeis.length) {
                    filter[this.path] = { __in: model.imeis };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class ModelCellRendererComponent {
    constructor(context, columnUtilService) {
        this.context = context;
        this.columnUtilService = columnUtilService;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModelCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }, { token: ColumnUtilService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: ModelCellRendererComponent, isStandalone: true, selector: "c8y-model-cell-renderer", ngImport: i0, template: ` {{ columnUtilService.getModel(context.item) }} `, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ModelCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: ` {{ columnUtilService.getModel(context.item) }} `,
                    selector: 'c8y-model-cell-renderer'
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }, { type: ColumnUtilService }] });

class ModelDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        const hardwareModelPath = 'c8y_Hardware.model';
        this.name = 'model';
        this.header = gettext('Model');
        this.cellRendererComponent = ModelCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'models',
                label: gettext('Show items with model'),
                addText: gettext('Add next`model`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: 'NTC-220'
            }),
            getFilter(model) {
                const filter = {};
                if (model.models.length) {
                    filter.push = {
                        [hardwareModelPath]: { __in: model.models }
                    };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: hardwareModelPath }]
        };
    }
}

class NameCellRendererComponent {
    constructor(context, columnUtilService) {
        this.context = context;
        this.columnUtilService = columnUtilService;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NameCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }, { token: ColumnUtilService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: NameCellRendererComponent, isStandalone: true, selector: "c8y-name-cell-renderer", ngImport: i0, template: `
    <a
      class="interact"
      title="{{ columnUtilService.getProperName(context.item) }}"
      [href]="columnUtilService.getHref(context.item)"
    >
      {{ columnUtilService.getProperName(context.item) }}
    </a>
  `, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NameCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: `
    <a
      class="interact"
      title="{{ columnUtilService.getProperName(context.item) }}"
      [href]="columnUtilService.getHref(context.item)"
    >
      {{ columnUtilService.getProperName(context.item) }}
    </a>
  `,
                    selector: 'c8y-name-cell-renderer'
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }, { type: ColumnUtilService }] });

class NameDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'name';
        this.path = 'name';
        this.header = gettext('Name');
        this.cellCSSClassName = "data-record-header" /* ColumnDataRecordClassName.Header */;
        this.cellRendererComponent = NameCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'names',
                label: gettext('Show items with name'),
                addText: gettext('Add next`name`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: gettext('My device`DEVICE_NAME`')
            }),
            getFilter(model) {
                const filter = {};
                if (model.names.length) {
                    filter.name = { __in: model.names };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class RegistrationDateCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RegistrationDateCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: RegistrationDateCellRendererComponent, isStandalone: true, selector: "c8y-registration-date-cell-renderer", ngImport: i0, template: ` {{ context.value | c8yDate }} `, isInline: true, dependencies: [{ kind: "pipe", type: DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RegistrationDateCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: ` {{ context.value | c8yDate }} `,
                    selector: 'c8y-registration-date-cell-renderer',
                    imports: [DatePipe]
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }] });

class RegistrationDateDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.path = 'creationTime';
        this.name = 'registrationDate';
        this.header = gettext('Registration date');
        this.cellRendererComponent = RegistrationDateCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: [
                {
                    type: 'object',
                    key: 'registrationDate',
                    templateOptions: {
                        label: gettext('Show items registered`between dates`')
                    },
                    fieldGroup: [
                        {
                            type: 'date-time',
                            key: 'after',
                            templateOptions: {
                                label: gettext('from`date`')
                            },
                            expressionProperties: {
                                'templateOptions.maxDate': (model) => model?.before
                            }
                        },
                        {
                            type: 'date-time',
                            key: 'before',
                            templateOptions: {
                                label: gettext('to`date`')
                            },
                            expressionProperties: {
                                'templateOptions.minDate': (model) => model?.after
                            }
                        }
                    ],
                    validators: {
                        atLeastOneFilled: {
                            expression: (formGroup) => {
                                const after = formGroup.get('after').value;
                                const before = formGroup.get('before').value;
                                return after || before;
                            }
                        }
                    }
                }
            ],
            formGroup: new FormGroup({}),
            getFilter: model => {
                const filter = {};
                const dates = model && model.registrationDate;
                if (dates && (dates.after || dates.before)) {
                    filter.__and = [];
                    if (dates.after) {
                        const after = this.formatDate(dates.after);
                        filter.__and.push({
                            'creationTime.date': { __gt: after }
                        });
                    }
                    if (dates.before) {
                        const before = this.formatDate(dates.before);
                        filter.__and.push({
                            'creationTime.date': { __lt: before }
                        });
                    }
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: 'creationTime.date' }]
        };
    }
    formatDate(dateToFormat) {
        return new Date(dateToFormat).toISOString();
    }
}

class SerialNumberCellRendererComponent {
    constructor(context, columnUtilService) {
        this.context = context;
        this.columnUtilService = columnUtilService;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SerialNumberCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }, { token: ColumnUtilService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SerialNumberCellRendererComponent, isStandalone: true, selector: "c8y-serial-number-cell-renderer", ngImport: i0, template: ` {{ columnUtilService.getSerialNumber(context.item) }} `, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SerialNumberCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: ` {{ columnUtilService.getSerialNumber(context.item) }} `,
                    selector: 'c8y-serial-number-cell-renderer'
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }, { type: ColumnUtilService }] });

class SerialNumberDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        const hardwareSerialNumberPath = 'c8y_Hardware.serialNumber';
        this.name = 'serialNumber';
        this.header = gettext('Serial number');
        this.cellRendererComponent = SerialNumberCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'serialNumbers',
                label: gettext('Show items with serial number'),
                addText: gettext('Add next`serial number`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: '54321-123'
            }),
            getFilter(model) {
                const filter = {};
                if (model.serialNumbers.length) {
                    filter.push = {
                        [hardwareSerialNumberPath]: { __in: model.serialNumbers }
                    };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: hardwareSerialNumberPath }]
        };
    }
}

class DeviceStatusCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceStatusCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DeviceStatusCellRendererComponent, isStandalone: true, selector: "c8y-device-status-cell-renderer", ngImport: i0, template: ` <device-status [mo]="context.item"></device-status> `, isInline: true, dependencies: [{ kind: "component", type: DeviceStatusComponent, selector: "device-status, c8y-device-status", inputs: ["mo", "size"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceStatusCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: ` <device-status [mo]="context.item"></device-status> `,
                    selector: 'c8y-device-status-cell-renderer',
                    imports: [DeviceStatusComponent]
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }] });

class StatusDeviceGridColumn extends BaseColumn {
    constructor() {
        super();
        const responseIntervalPath = 'c8y_RequiredAvailability.responseInterval';
        const responseIntervalLessThanOrEqualTo0 = { [responseIntervalPath]: { __le: 0 } };
        const responseIntervalNotDefined = { __not: { __has: responseIntervalPath } };
        const availabilityStatusPath = 'c8y_Availability.status';
        const availabilityStatusAvailable = { [availabilityStatusPath]: SendStatus.AVAILABLE };
        const availabilityStatusUnavailable = { [availabilityStatusPath]: SendStatus.UNAVAILABLE };
        const availabilityStatusMaintenance = { [availabilityStatusPath]: SendStatus.MAINTENANCE };
        const availabilityStatusNotDefined = { __not: { __has: availabilityStatusPath } };
        const connectionStatusPath = 'c8y_Connection.status';
        const connectionStatusConnected = { [connectionStatusPath]: PushStatus.CONNECTED };
        const connectionStatusDisconnected = { [connectionStatusPath]: PushStatus.DISCONNECTED };
        const connectionStatusMaintenance = { [connectionStatusPath]: PushStatus.MAINTENANCE };
        const deviceUnderMaintenance = {
            __or: [
                responseIntervalLessThanOrEqualTo0,
                availabilityStatusMaintenance,
                connectionStatusMaintenance
            ]
        };
        const deviceNotUnderMaintenance = {
            // using __and of __nots because backend does not support __not with __ors
            __and: [
                { __not: responseIntervalLessThanOrEqualTo0 },
                { __not: availabilityStatusMaintenance },
                { __not: connectionStatusMaintenance }
            ]
        };
        this.name = 'status';
        this.header = gettext('Status');
        this.dataType = "icon" /* ColumnDataType.Icon */;
        this.cellRendererComponent = DeviceStatusCellRendererComponent;
        this.resizable = false;
        this.filterable = true;
        this.filteringConfig = {
            fields: [
                {
                    type: 'object',
                    templateOptions: {
                        label: 'Show items with status'
                    },
                    fieldGroup: [
                        {
                            key: 'sendStatus',
                            type: 'object',
                            props: {
                                label: gettext('Send status')
                            },
                            fieldGroup: [
                                {
                                    key: 'sendOnline',
                                    type: 'switch',
                                    props: { label: gettext('Online') }
                                },
                                {
                                    key: 'sendOffline',
                                    type: 'switch',
                                    props: { label: gettext('Offline') }
                                },
                                {
                                    key: 'sendUnknown',
                                    type: 'switch',
                                    props: { label: gettext('Unknown') }
                                },
                                {
                                    key: 'sendNotMonitored',
                                    type: 'switch',
                                    props: { label: gettext('Not monitored') }
                                }
                            ]
                        },
                        {
                            key: 'pushStatus',
                            type: 'object',
                            props: {
                                label: gettext('Push status')
                            },
                            fieldGroup: [
                                {
                                    key: 'pushOnline',
                                    type: 'switch',
                                    props: { label: gettext('Online') }
                                },
                                {
                                    key: 'pushOffline',
                                    type: 'switch',
                                    props: { label: gettext('Offline') }
                                },
                                {
                                    key: 'pushNotMonitored',
                                    type: 'switch',
                                    props: { label: gettext('Not monitored') }
                                }
                            ]
                        },
                        {
                            key: 'maintenanceStatus',
                            type: 'object',
                            props: {
                                label: gettext('Maintenance status')
                            },
                            fieldGroup: [
                                {
                                    key: 'maintenance',
                                    type: 'switch',
                                    props: { label: gettext('Device is under maintenance') }
                                }
                            ]
                        }
                    ],
                    validators: {
                        atLeastOneFilled: {
                            expression: (formGroup) => {
                                const sendStatus = formGroup.get('sendStatus').value || {};
                                const pushStatus = formGroup.get('pushStatus').value || {};
                                const maintenanceStatus = formGroup.get('maintenanceStatus').value || {};
                                return (sendStatus.sendOnline ||
                                    sendStatus.sendOffline ||
                                    sendStatus.sendUnknown ||
                                    sendStatus.sendNotMonitored ||
                                    pushStatus.pushOnline ||
                                    pushStatus.pushOffline ||
                                    pushStatus.pushNotMonitored ||
                                    maintenanceStatus.maintenance);
                            }
                        }
                    }
                }
            ],
            formGroup: new FormGroup({}),
            getFilter(model) {
                const filter = {};
                const ors = [];
                if (model?.sendStatus?.sendOnline) {
                    ors.push({
                        __and: [deviceNotUnderMaintenance, availabilityStatusAvailable]
                    });
                }
                if (model?.sendStatus?.sendOffline) {
                    ors.push({
                        __and: [deviceNotUnderMaintenance, availabilityStatusUnavailable]
                    });
                }
                if (model?.sendStatus?.sendUnknown) {
                    ors.push({
                        __and: [deviceNotUnderMaintenance, availabilityStatusNotDefined]
                    });
                }
                if (model?.sendStatus?.sendNotMonitored || model?.pushStatus?.pushNotMonitored) {
                    ors.push(responseIntervalNotDefined);
                }
                if (model?.pushStatus?.pushOnline) {
                    ors.push({
                        __and: [deviceNotUnderMaintenance, connectionStatusConnected]
                    });
                }
                if (model?.pushStatus?.pushOffline) {
                    ors.push({
                        __and: [deviceNotUnderMaintenance, connectionStatusDisconnected]
                    });
                }
                if (model?.maintenanceStatus?.maintenance) {
                    ors.push(deviceUnderMaintenance);
                }
                if (ors.length) {
                    filter.__or = ors;
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: availabilityStatusPath }]
        };
    }
}

class SystemIdDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.path = 'id';
        this.name = 'systemId';
        this.header = gettext('System ID');
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'ids',
                label: gettext('Show items with system ID'),
                addText: gettext('Add next`id`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: '10300'
            }),
            getFilter: (model) => {
                const filter = {};
                if (model.ids.length) {
                    filter[this.path] = { __in: model.ids };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class TypeDeviceGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'type';
        this.path = 'type';
        this.header = gettext('Type');
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'types',
                label: gettext('Show devices with type'),
                addText: gettext('Add next`type`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: gettext('MyType`DEVICE_TYPE`')
            }),
            getFilter(model) {
                const filter = {};
                if (model.types.length) {
                    filter.type = { __in: model.types };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = { pathSortingConfigs: [{ path: 'type' }] };
    }
}

class IconDeviceGridColumnComponent {
    constructor(context) {
        const propertyAsIconColumn = context.property;
        if (propertyAsIconColumn && typeof propertyAsIconColumn.iconRetriever === 'function') {
            this.icon = propertyAsIconColumn.iconRetriever(context);
        }
        else {
            this.icon = context.value;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: IconDeviceGridColumnComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: IconDeviceGridColumnComponent, isStandalone: true, selector: "c8y-icon-device-grid-column", ngImport: i0, template: `<i [c8yIcon]="icon"></i>`, isInline: true, dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: IconDeviceGridColumnComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'c8y-icon-device-grid-column',
                    standalone: true,
                    imports: [IconDirective],
                    template: `<i [c8yIcon]="icon"></i>`
                }]
        }], ctorParameters: () => [{ type: i1$1.CellRendererContext }] });
class IconDeviceGridColumn extends BaseColumn {
    constructor(options = {}, iconRetriever) {
        super(options);
        this.iconRetriever = iconRetriever;
        this.dataType = "icon" /* ColumnDataType.Icon */;
        this.name = 'icon';
        this.path = 'icon';
        this.filterable = false;
        this.resizable = false;
        this.header = gettext$1('Icon');
        this.cellRendererComponent = IconDeviceGridColumnComponent;
        Object.assign(this, options);
    }
}

class DeviceGridService extends DataGridService {
    constructor(inventoryService, userService, translateService, alertService, modal, columnUtilService, userPreferencesService) {
        super(userPreferencesService);
        this.inventoryService = inventoryService;
        this.userService = userService;
        this.translateService = translateService;
        this.alertService = alertService;
        this.modal = modal;
        this.columnUtilService = columnUtilService;
        this.userPreferencesService = userPreferencesService;
        this.GRID_CONFIG_DEFAULT_STORAGE_KEY = 'device-grid-config';
    }
    getDefaultColumns() {
        const defaultColumns = [
            new StatusDeviceGridColumn(),
            new NameDeviceGridColumn(),
            new ModelDeviceGridColumn(),
            new SerialNumberDeviceGridColumn(),
            new GroupDeviceGridColumn(),
            new RegistrationDateDeviceGridColumn(),
            new SystemIdDeviceGridColumn(),
            new ImeiDeviceGridColumn(),
            new AlarmsDeviceGridColumn()
        ];
        return defaultColumns;
    }
    getChildDeviceGridColumns() {
        const childDeviceGridColumn = [
            new StatusDeviceGridColumn(),
            new NameDeviceGridColumn(),
            new ModelDeviceGridColumn(),
            new SerialNumberDeviceGridColumn(),
            new RegistrationDateDeviceGridColumn(),
            new SystemIdDeviceGridColumn(),
            new ImeiDeviceGridColumn(),
            new AlarmsDeviceGridColumn()
        ];
        return childDeviceGridColumn;
    }
    getDefaultPagination() {
        return {
            pageSize: 25,
            currentPage: 1
        };
    }
    getInfiniteScrollPagination() {
        return {
            pageSize: 50,
            currentPage: 1
        };
    }
    getDefaultBulkActionControls() {
        return [];
    }
    getDefaultHeaderActionControls() {
        return [];
    }
    getProperName(device) {
        return this.columnUtilService.getProperName(device);
    }
    getModel(device) {
        return this.columnUtilService.getModel(device);
    }
    getSerialNumber(device) {
        return this.columnUtilService.getSerialNumber(device);
    }
    getParentsNames(device, featuredParentId) {
        return this.columnUtilService.getParentsNames(device, featuredParentId);
    }
    getHref(groupOrDevice, prefix = '#/') {
        return this.columnUtilService.getHref(groupOrDevice, prefix);
    }
    getAlarmsHref(device) {
        return this.columnUtilService.getAlarmsHref(device);
    }
    async delete(device) {
        try {
            const deviceWithChildren = await (await this.inventoryService.detail(device, { withChildren: true })).data;
            const hasChildDevices = deviceWithChildren.childDevices?.references?.length > 0;
            const hasChildAdditions = deviceWithChildren.childAdditions?.references?.length > 0;
            const hasChildAssets = deviceWithChildren.childAssets?.references?.length > 0;
            const showDeleteChildren = () => hasChildAdditions || hasChildDevices || hasChildAssets;
            const modalResult = await this.modal.confirm(gettext('Delete device'), this.translateService.instant(gettext(`You are about to delete device "{{ name }}". Do you want to proceed?`), device), Status.DANGER, { ok: gettext('Delete'), cancel: gettext('Cancel') }, {
                cascade: {
                    text: gettext('Also delete child hierarchy of this device.'),
                    checked: showDeleteChildren(),
                    showIf: showDeleteChildren,
                    disabledByKey: 'withDeviceUser'
                },
                withDeviceUser: {
                    text: this.translateService.instant(gettext('Also delete associated device owner "{{ owner }}".'), device),
                    checked: false,
                    showIf: () => {
                        const isRootDevice = device.c8y_IsDevice;
                        const hasDeviceUserAsOwner = device.owner &&
                            this.userService.isDeviceUser({ id: device.owner });
                        return Boolean(isRootDevice && hasDeviceUserAsOwner);
                    },
                    disabledByKey: 'cascade'
                }
            });
            await this.inventoryService.delete(device, modalResult.confirmOptions);
            this.alertService.success(gettext('Device deleted.'));
            return Promise.resolve();
        }
        catch (ex) {
            // only if not cancel from modal
            if (ex) {
                this.alertService.addServerFailure(ex);
            }
            return Promise.reject();
        }
    }
    async getData(columns, pagination, query = {}, withChildren = false, text = null) {
        const filters = {
            ...this.getDevicesFilters(columns, pagination, query, false, text),
            withGroups: true,
            withChildren,
            withTotalElements: true
        };
        return this.inventoryService.list(filters);
    }
    async getChildDeviceData(columns, pagination, query = {}, withChildren = false, id) {
        const childDeviceFilters = true;
        const filters = {
            ...this.getDevicesFilters(columns, pagination, query, childDeviceFilters),
            withGroups: true,
            withChildren
        };
        return this.inventoryService.childDevicesList(id, filters);
    }
    async getCount(columns, pagination, query = {}, text = null) {
        const filters = {
            ...this.getDevicesFilters(columns, pagination, query, false, text),
            withTotalElements: true
        };
        return (await this.inventoryService.list(filters)).paging.totalElements;
    }
    async getCountChildDevices(columns, pagination, query = {}, id) {
        const childDeviceFilters = true;
        const filters = {
            ...this.getDevicesFilters(columns, pagination, query, childDeviceFilters),
            withTotalElements: true
        };
        return (await this.inventoryService.childDevicesList(id, filters)).paging.totalElements;
    }
    async getTotalChildDevices(query = {}, id) {
        const filters = {
            q: this.queriesUtil.buildQuery(query),
            withTotalElements: true
        };
        return (await this.inventoryService.childDevicesList(id, filters)).paging.totalElements;
    }
    async getTotal(query = {}) {
        const filters = {
            q: this.queriesUtil.buildQuery(query),
            withTotalElements: true
        };
        return (await this.inventoryService.list(filters)).paging.totalElements;
    }
    getDeviceQueryString(columns, query) {
        let fullQuery = this.getQueryObj(columns);
        fullQuery = this.queriesUtil.addAndFilter(fullQuery, query);
        return this.queriesUtil.buildQuery(fullQuery);
    }
    clearConfig(key = this.GRID_CONFIG_DEFAULT_STORAGE_KEY) {
        super.clearConfig(key);
    }
    getConfig$(key = this.GRID_CONFIG_DEFAULT_STORAGE_KEY) {
        return super.getConfig$(key);
    }
    saveConfig$(config, key = this.GRID_CONFIG_DEFAULT_STORAGE_KEY) {
        return super.saveConfig$(config, key);
    }
    getDevicesFilters(columns, pagination, query, childDeviceFilters, text) {
        return {
            ...(childDeviceFilters
                ? { query: this.getDeviceQueryString(columns, query) }
                : { q: this.getDeviceQueryString(columns, query) }),
            ...(text && { text }),
            pageSize: pagination.pageSize,
            currentPage: pagination.currentPage,
            withChildren: false,
            withTotalPages: true
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridService, deps: [{ token: i1$2.InventoryService }, { token: i1$2.UserService }, { token: i1.TranslateService }, { token: i1$1.AlertService }, { token: i1$1.ModalService }, { token: ColumnUtilService }, { token: i1$1.UserPreferencesService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [{ type: i1$2.InventoryService }, { type: i1$2.UserService }, { type: i1.TranslateService }, { type: i1$1.AlertService }, { type: i1$1.ModalService }, { type: ColumnUtilService }, { type: i1$1.UserPreferencesService }] });

class DeviceGridComponent {
    /** Pagination settings, e.g. allows for setting current page or page size. If not given, defaults to standard settings. */
    set _pagination(value) {
        if (value) {
            this.pagination = value;
        }
    }
    /** Sets load more mode. */
    set _infiniteScroll(infiniteScroll) {
        this.infiniteScroll = infiniteScroll;
        if (infiniteScroll) {
            this.pagination = this.deviceGridService.getInfiniteScrollPagination();
        }
    }
    /** Sets action controls (actions available for individual items). If not given, it defaults to standard actions. */
    set _actionControls(value) {
        this.actionControls = value;
    }
    /** Sets bulk action controls (actions available for items selected by user). If not given, it defaults to standard bulk actions. */
    set _bulkActionControls(value) {
        if (value) {
            this.bulkActionControls = value;
        }
        else {
            this.bulkActionControls = this.deviceGridService.getDefaultBulkActionControls();
        }
    }
    /** Sets header action controls (actions available from the grid header). If not given, it defaults to empty list of actions. */
    set _headerActionControls(value) {
        if (value) {
            this.headerActionControls = value;
        }
        else {
            this.headerActionControls = this.deviceGridService.getDefaultHeaderActionControls();
        }
    }
    constructor(deviceGridService) {
        this.deviceGridService = deviceGridService;
        /** Takes an event emitter. When an event is emitted, the grid will be reloaded. */
        this.refresh = new EventEmitter();
        /** The title for the data grid, it's displayed in the grid's header. */
        this.title = gettext('Devices');
        /** The label for load more button. */
        this.loadMoreItemsLabel = gettext('Load more devices');
        /** The label for loading indicator. */
        this.loadingItemsLabel = gettext('Loading devices…');
        /** The list of columns to be displayed in the grid. If not given, it defaults to standard columns. */
        this.columns = this.deviceGridService.getDefaultColumns();
        /** Determines whether items can be selected by clicking a checkbox in the first column. */
        this.selectable = false;
        /** Restricts selection to a single row only. Selection column displays radio button instead of checkboxes */
        this.singleSelection = false;
        /** Sets the base query which is appended to the request for data. */
        this.baseQuery = {};
        this.childDeviceGrid = false;
        /** Sets the withChildren query which is appended to the request. */
        this.withChildren = false;
        /**
         * Enables the search for devices where any device propery is matched agains the search term.
         * Enabled by default. This input does not take effect if the <code>childDeviceGrid</code> input is set to <code>true</code>
         */
        this.showSearch = true;
        /**
         * Sets the class name used for active rows (last clicked).
         * Set empty string to disable appending active class to grid rows.
         */
        this.activeClassName = 'active';
        /** Emits an event when columns configuration changes. */
        this.onColumnsChange = new EventEmitter();
        this.onFilterChange = new EventEmitter();
        this.onDeviceQueryStringChange = new EventEmitter();
        /** Emits an event when items selection changes. The array contains ids of selected items. */
        this.itemsSelect = new EventEmitter();
        this.actionControls = [];
        this.appliedFilters = [];
        this.pagination = this.deviceGridService.getDefaultPagination();
        this.bulkActionControls = this.deviceGridService.getDefaultBulkActionControls();
        this.headerActionControls = this.deviceGridService.getDefaultHeaderActionControls();
        this.noResultsMessage = gettext('No matching devices.');
        this.noDataMessage = gettext('No devices to display.');
        this.noResultsSubtitle = gettext('Refine your search terms');
        this.destroyed$ = new Subject();
        this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
    }
    ngOnDestroy() {
        this.destroyed$.next();
        this.destroyed$.complete();
    }
    trackByName(_index, column) {
        return column.name;
    }
    async onDataSourceModifier(dataSourceModifier) {
        let serverSideDataResult;
        let filteredSize;
        let size;
        if (this.childDeviceGrid) {
            const { res, data, paging } = await alertOnError(this.deviceGridService.getChildDeviceData(dataSourceModifier.columns, dataSourceModifier.pagination, this.baseQuery, this.withChildren, this.parentDeviceId));
            filteredSize = await alertOnError(this.deviceGridService.getCountChildDevices(dataSourceModifier.columns, dataSourceModifier.pagination, this.baseQuery, this.parentDeviceId));
            size = await alertOnError(this.deviceGridService.getTotalChildDevices(this.baseQuery, this.parentDeviceId));
            serverSideDataResult = {
                res,
                data,
                paging,
                filteredSize,
                size
            };
        }
        else {
            const { res, data, paging } = await alertOnError(this.deviceGridService.getData(dataSourceModifier.columns, dataSourceModifier.pagination, this.baseQuery, this.withChildren, dataSourceModifier.searchText));
            filteredSize = await alertOnError(this.deviceGridService.getCount(dataSourceModifier.columns, dataSourceModifier.pagination, this.baseQuery, dataSourceModifier.searchText));
            size = await alertOnError(this.deviceGridService.getTotal(this.baseQuery));
            serverSideDataResult = {
                res,
                data,
                paging,
                filteredSize,
                size
            };
        }
        this.onColumnsChange.emit(dataSourceModifier.columns);
        this.onDeviceQueryStringChange.emit(this.deviceGridService.getDeviceQueryString(dataSourceModifier.columns, this.baseQuery));
        if (this.dataCallback) {
            serverSideDataResult = this.dataCallback(serverSideDataResult);
        }
        return serverSideDataResult;
    }
    updateFiltering(columnNames, action) {
        const { type } = action;
        if (type === FilteringActionType.ResetFilter) {
            this.dataGrid.clearFilters();
        }
        else {
            this.dataGrid.updateFiltering(columnNames, action);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridComponent, deps: [{ token: DeviceGridService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DeviceGridComponent, isStandalone: true, selector: "c8y-device-grid", inputs: { dataCallback: "dataCallback", refresh: "refresh", title: "title", loadMoreItemsLabel: "loadMoreItemsLabel", loadingItemsLabel: "loadingItemsLabel", legacyConfigKey: "legacyConfigKey", legacyFilterKey: "legacyFilterKey", columns: "columns", _pagination: ["pagination", "_pagination"], _infiniteScroll: ["infiniteScroll", "_infiniteScroll"], _actionControls: ["actionControls", "_actionControls"], selectable: "selectable", singleSelection: "singleSelection", baseQuery: "baseQuery", _bulkActionControls: ["bulkActionControls", "_bulkActionControls"], _headerActionControls: ["headerActionControls", "_headerActionControls"], childDeviceGrid: "childDeviceGrid", parentDeviceId: "parentDeviceId", withChildren: "withChildren", showSearch: "showSearch", activeClassName: "activeClassName" }, outputs: { onColumnsChange: "onColumnsChange", onFilterChange: "onFilterChange", onDeviceQueryStringChange: "onDeviceQueryStringChange", itemsSelect: "itemsSelect" }, providers: [
            {
                provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
                useExisting: forwardRef(() => DeviceGridComponent)
            }
        ], viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-data-grid\n  [title]=\"title\"\n  [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n  [loadingItemsLabel]=\"loadingItemsLabel\"\n  [columns]=\"columns\"\n  [pagination]=\"pagination\"\n  [infiniteScroll]=\"infiniteScroll\"\n  [actionControls]=\"actionControls\"\n  [selectable]=\"selectable\"\n  [singleSelection]=\"singleSelection\"\n  [bulkActionControls]=\"bulkActionControls\"\n  [serverSideDataCallback]=\"serverSideDataCallback\"\n  (itemsSelect)=\"itemsSelect.emit($event)\"\n  [refresh]=\"refresh\"\n  [showSearch]=\"showSearch && !childDeviceGrid\"\n  [headerActionControls]=\"headerActionControls\"\n  [activeClassName]=\"activeClassName\"\n  c8yProductExperience\n  inherit\n>\n  <c8y-ui-empty-state\n    [icon]=\"stats?.size > 0 ? 'search' : 'c8y-device-management'\"\n    [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n    [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : null\"\n    *emptyStateContext=\"let stats\"\n    [horizontal]=\"stats?.size > 0\"\n  ></c8y-ui-empty-state>\n\n  <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n    <c8y-column [name]=\"column.name\"></c8y-column>\n  </ng-container>\n</c8y-data-grid>\n", dependencies: [{ kind: "component", type: DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "childNodePagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "treeGrid", "hideReload", "childNodesProperty", "parentNodeLabelProperty"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "directive", type: ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "directive", type: EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-device-grid', providers: [
                        {
                            provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
                            useExisting: forwardRef(() => DeviceGridComponent)
                        }
                    ], imports: [
                        DataGridComponent,
                        ProductExperienceDirective,
                        EmptyStateContextDirective,
                        EmptyStateComponent,
                        NgFor,
                        ColumnDirective,
                        C8yTranslatePipe
                    ], template: "<c8y-data-grid\n  [title]=\"title\"\n  [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n  [loadingItemsLabel]=\"loadingItemsLabel\"\n  [columns]=\"columns\"\n  [pagination]=\"pagination\"\n  [infiniteScroll]=\"infiniteScroll\"\n  [actionControls]=\"actionControls\"\n  [selectable]=\"selectable\"\n  [singleSelection]=\"singleSelection\"\n  [bulkActionControls]=\"bulkActionControls\"\n  [serverSideDataCallback]=\"serverSideDataCallback\"\n  (itemsSelect)=\"itemsSelect.emit($event)\"\n  [refresh]=\"refresh\"\n  [showSearch]=\"showSearch && !childDeviceGrid\"\n  [headerActionControls]=\"headerActionControls\"\n  [activeClassName]=\"activeClassName\"\n  c8yProductExperience\n  inherit\n>\n  <c8y-ui-empty-state\n    [icon]=\"stats?.size > 0 ? 'search' : 'c8y-device-management'\"\n    [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n    [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : null\"\n    *emptyStateContext=\"let stats\"\n    [horizontal]=\"stats?.size > 0\"\n  ></c8y-ui-empty-state>\n\n  <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n    <c8y-column [name]=\"column.name\"></c8y-column>\n  </ng-container>\n</c8y-data-grid>\n" }]
        }], ctorParameters: () => [{ type: DeviceGridService }], propDecorators: { dataCallback: [{
                type: Input
            }], refresh: [{
                type: Input
            }], title: [{
                type: Input
            }], loadMoreItemsLabel: [{
                type: Input
            }], loadingItemsLabel: [{
                type: Input
            }], legacyConfigKey: [{
                type: Input
            }], legacyFilterKey: [{
                type: Input
            }], columns: [{
                type: Input,
                args: ['columns']
            }], _pagination: [{
                type: Input,
                args: ['pagination']
            }], _infiniteScroll: [{
                type: Input,
                args: ['infiniteScroll']
            }], _actionControls: [{
                type: Input,
                args: ['actionControls']
            }], selectable: [{
                type: Input
            }], singleSelection: [{
                type: Input
            }], baseQuery: [{
                type: Input
            }], _bulkActionControls: [{
                type: Input,
                args: ['bulkActionControls']
            }], _headerActionControls: [{
                type: Input,
                args: ['headerActionControls']
            }], childDeviceGrid: [{
                type: Input
            }], parentDeviceId: [{
                type: Input
            }], withChildren: [{
                type: Input
            }], showSearch: [{
                type: Input
            }], activeClassName: [{
                type: Input
            }], onColumnsChange: [{
                type: Output
            }], onFilterChange: [{
                type: Output
            }], onDeviceQueryStringChange: [{
                type: Output
            }], itemsSelect: [{
                type: Output
            }], dataGrid: [{
                type: ViewChild,
                args: [DataGridComponent, { static: true }]
            }] } });

class DeviceGridModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridModule, imports: [CommonModule,
            FormsModule,
            DeviceStatusModule,
            DataGridModule,
            AssetSelectorModule,
            DynamicFormsModule,
            PopoverModule,
            RouterModule,
            ProductExperienceModule,
            DeviceGridComponent,
            GroupFilteringFormRendererComponent,
            DeviceStatusCellRendererComponent,
            NameCellRendererComponent,
            ModelCellRendererComponent,
            SerialNumberCellRendererComponent,
            GroupCellRendererComponent,
            RegistrationDateCellRendererComponent,
            AlarmsCellRendererComponent,
            AlarmsHeaderCellRendererComponent], exports: [DeviceGridComponent,
            GroupFilteringFormRendererComponent,
            DeviceStatusCellRendererComponent,
            NameCellRendererComponent,
            ModelCellRendererComponent,
            SerialNumberCellRendererComponent,
            GroupCellRendererComponent,
            RegistrationDateCellRendererComponent,
            AlarmsCellRendererComponent,
            AlarmsHeaderCellRendererComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridModule, imports: [CommonModule,
            FormsModule,
            DeviceStatusModule,
            DataGridModule,
            AssetSelectorModule,
            DynamicFormsModule,
            PopoverModule,
            RouterModule,
            ProductExperienceModule,
            DeviceGridComponent,
            GroupFilteringFormRendererComponent,
            DeviceStatusCellRendererComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceGridModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CommonModule,
                        FormsModule,
                        DeviceStatusModule,
                        DataGridModule,
                        AssetSelectorModule,
                        DynamicFormsModule,
                        PopoverModule,
                        RouterModule,
                        ProductExperienceModule,
                        DeviceGridComponent,
                        GroupFilteringFormRendererComponent,
                        DeviceStatusCellRendererComponent,
                        NameCellRendererComponent,
                        ModelCellRendererComponent,
                        SerialNumberCellRendererComponent,
                        GroupCellRendererComponent,
                        RegistrationDateCellRendererComponent,
                        AlarmsCellRendererComponent,
                        AlarmsHeaderCellRendererComponent
                    ],
                    exports: [
                        DeviceGridComponent,
                        GroupFilteringFormRendererComponent,
                        DeviceStatusCellRendererComponent,
                        NameCellRendererComponent,
                        ModelCellRendererComponent,
                        SerialNumberCellRendererComponent,
                        GroupCellRendererComponent,
                        RegistrationDateCellRendererComponent,
                        AlarmsCellRendererComponent,
                        AlarmsHeaderCellRendererComponent
                    ]
                }]
        }] });

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

export { AlarmsCellRendererComponent, AlarmsDeviceGridColumn, AlarmsHeaderCellRendererComponent, ColumnUtilService, DeviceGridComponent, DeviceGridModule, DeviceGridService, DeviceStatusCellRendererComponent, GroupCellRendererComponent, GroupDeviceGridColumn, GroupFilteringFormRendererComponent, IconDeviceGridColumn, IconDeviceGridColumnComponent, ImeiDeviceGridColumn, ModelCellRendererComponent, ModelDeviceGridColumn, NameCellRendererComponent, NameDeviceGridColumn, RegistrationDateCellRendererComponent, RegistrationDateDeviceGridColumn, SerialNumberCellRendererComponent, SerialNumberDeviceGridColumn, StatusDeviceGridColumn, SystemIdDeviceGridColumn, TypeDeviceGridColumn };
//# sourceMappingURL=c8y-ngx-components-device-grid.mjs.map