UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

929 lines (908 loc) 80.3 kB
import * as i0 from '@angular/core'; import { Injectable, Component, ElementRef, HostListener, ViewChild, EventEmitter, forwardRef, Output, Input, NgModule } from '@angular/core'; import { gettext } from '@c8y/ngx-components/gettext'; import * as i1$1 from '@c8y/ngx-components'; import { IconDirective, C8yTranslatePipe, BaseColumn, C8yTranslateDirective, getBasicInputArrayFormFieldConfig, DatePipe, DeviceStatusComponent, SendStatus, PushStatus, DataGridService, Status, alertOnError, FilteringActionType, DataGridComponent, ProductExperienceDirective, EmptyStateContextDirective, EmptyStateComponent, 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 } 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 { 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: "20.3.19", ngImport: i0, type: ColumnUtilService, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColumnUtilService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", ngImport: i0, type: AlarmsHeaderCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", 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: "20.3.19", 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 = 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", ngImport: i0, type: GroupFilteringFormRendererComponent, deps: [{ token: i1$1.FilteringFormRendererContext }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", ngImport: i0, type: RegistrationDateCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", 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: "20.3.19", ngImport: i0, type: DeviceStatusCellRendererComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", 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: "20.3.19", 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: 'c8y_MQTTDevice' }), 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: "20.3.19", ngImport: i0, type: IconDeviceGridColumnComponent, deps: [{ token: i1$1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareCompon