UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

2,654 lines 245 kB
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Output, Input, Component, forwardRef, Directive, signal, inject, DestroyRef, ViewChild, ViewChildren, Optional, NgModule } from '@angular/core';
import * as i1 from '@c8y/client';
import { OperationStatus } from '@c8y/client';
import { BehaviorSubject, merge, Subject, debounceTime } from 'rxjs';
import { omit, isEmpty, some, isEqual, reject, isNil, get, assign, cloneDeep, unset as unset$1, set as set$1, find, findIndex, pick, has } from 'lodash-es';
import { NgClass, NgFor, NgIf, JsonPipe, KeyValuePipe } from '@angular/common';
import * as i2$1 from '@c8y/ngx-components';
import { C8yTranslatePipe, IconDirective, LoadingComponent, C8yTranslateDirective, FormGroupComponent, SelectLegacyComponent, ListItemComponent, FilterInputComponent, ListItemBodyComponent, ListItemCheckboxComponent, InputGroupListContainerDirective, InputGroupListComponent, RequiredInputPlaceholderDirective, MinValidationDirective, DatePipe, MessagesComponent, MessageDirective, TitleComponent, BreadcrumbComponent, BreadcrumbItemComponent, EmptyStateComponent, Status, DeviceStatusComponent, DefaultValidationDirective, DropAreaComponent, ViewContext, CoreModule, FormsModule as FormsModule$1, DropAreaModule, DeviceStatusModule, DynamicFormsModule, hookRoute } from '@c8y/ngx-components';
import * as i2 from '@angular/router';
import { RouterModule } from '@angular/router';
import * as i2$2 from '@angular/forms';
import { NG_VALIDATORS, FormsModule, NgModelGroup, ControlContainer, NgForm, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { NestedTreeControl, CdkTree, CdkTreeNodeDef, CdkNestedTreeNode, CdkTreeNodeToggle, CdkTreeNodeOutlet, CdkTreeModule } from '@angular/cdk/tree';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { gettext } from '@c8y/ngx-components/gettext';
import { BaseObjectMapping, MeasurementObjectMapping, EventObjectMapping, AlarmObjectMapping, ALARM_SEVERITY, ObjectMappingComponent } from '@c8y/ngx-components/device-protocol-object-mappings';
import { OperationDetailsComponent, OperationDetailsModule } from '@c8y/ngx-components/operations/operation-details';
import { ButtonCheckboxDirective, ButtonsModule } from 'ngx-bootstrap/buttons';
import * as i4$1 from 'ngx-bootstrap/collapse';
import { CollapseDirective, CollapseModule } from 'ngx-bootstrap/collapse';
import * as i5 from 'ngx-bootstrap/dropdown';
import { BsDropdownDirective, BsDropdownToggleDirective, BsDropdownMenuDirective, BsDropdownModule } from 'ngx-bootstrap/dropdown';
import * as i3$1 from 'ngx-bootstrap/popover';
import { PopoverDirective, PopoverModule } from 'ngx-bootstrap/popover';
import * as i2$3 from 'ngx-bootstrap/tooltip';
import { TooltipDirective, TooltipModule } from 'ngx-bootstrap/tooltip';
import { clone, toInteger, unset, set, cloneDeep as cloneDeep$1 } from 'lodash';
import { map, takeUntil, filter } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { UpgradeComponent, downgradeComponent } from '@angular/upgrade/static';
import * as i4 from '@ngx-formly/core';
import { FormlyModule } from '@ngx-formly/core';
import * as i3 from '@ngx-translate/core';
import * as angular from 'angular';
import { registerNgModule } from '@c8y/ng1-modules';

class AddressSpaceService {
    constructor(fetchClient) {
        this.client = fetchClient;
        this.microserviceUrl = '/service/opcua-mgmt-service/address-space';
        this.header = { 'Content-Type': 'application/json' };
        this.nodeNavigationData$ = new BehaviorSubject({
            node: undefined,
            selectedAncestorIds: []
        });
    }
    resetTreeToRootNode() {
        this.triggerNodeToOpen({ node: undefined, selectedAncestorIds: [] });
    }
    triggerNodeToOpen(nodeNavigationData) {
        this.nodeNavigationData$.next(nodeNavigationData);
    }
    getNodeNavData$() {
        return this.nodeNavigationData$.asObservable();
    }
    getNode(serverId, nodeId) {
        if (serverId && serverId.length > 0) {
            if (nodeId && nodeId.length > 0) {
                return this.getNodeById(serverId, nodeId);
            }
            return this.getRootNode(serverId);
        }
    }
    getRootNode(serverId) {
        if (serverId && serverId.length > 0) {
            const options = {
                method: 'GET',
                headers: this.header
            };
            return this.client.fetch(`${this.microserviceUrl}/${serverId}`, options);
        }
    }
    getNodeById(serverId, nodeId) {
        if (serverId && nodeId && serverId.length > 0 && nodeId.length > 0) {
            const options = {
                method: 'GET',
                headers: this.header
            };
            const param = encodeURIComponent(nodeId);
            return this.client.fetch(`${this.microserviceUrl}/${serverId}?nodeId=${param}`, options);
        }
    }
    getChildrenOf(node, serverId) {
        if (serverId && node.nodeId && serverId.length > 0 && node.nodeId.length > 0) {
            const options = {
                method: 'GET',
                headers: this.header
            };
            const param = encodeURIComponent(node.nodeId);
            return this.client.fetch(`${this.microserviceUrl}/${serverId}/children?nodeId=${param}`, options);
        }
    }
    childrenAvailable(nodeReferences) {
        if (!nodeReferences || nodeReferences.length === 0) {
            return false;
        }
        return nodeReferences.some(ref => !ref.inverse && ref.hierarchical);
    }
    async getSearchedNodes(searchKey, serverId) {
        const url = `service/opcua-mgmt-service/search/${serverId}/`;
        const options = {
            headers: this.header,
            params: {
                searchString: '*' + searchKey + '*'
            }
        };
        const res = await this.client.fetch(url, options);
        return res.json();
    }
    getIcon(nodeClassName) {
        const iconList = {
            Object: 'cube',
            Variable: 'th-list',
            Method: 'random',
            View: 'window-maximize',
            ObjectType: 'c8y-group',
            VariableType: 'c8y-group',
            ReferenceType: 'c8y-group',
            DataType: 'c8y-group'
        };
        return iconList[nodeClassName] || 'circle';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressSpaceService, deps: [{ token: i1.FetchClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressSpaceService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressSpaceService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.FetchClient }] });

class OpcuaAddressSpaceDetailComponent {
    set node(n) {
        this._node = n;
        if (n) {
            this.setNodeData(n);
        }
        else {
            // remove details from current view
            this.showDetails = false;
        }
    }
    constructor(addressSpaceService) {
        this.addressSpaceService = addressSpaceService;
        this.selected = false;
        this.showDetails = false;
        this.toggleAttrDetail = new EventEmitter();
    }
    setNodeData(nodeData) {
        this.showDetails = true;
        const { attributes, references } = nodeData;
        this.nodeDataRef = references;
        const omitList = [
            'attributes',
            'references',
            'children',
            'currentlyLoadingChildren',
            'expanded',
            'browsePath',
            'relativePath',
            'parentNode'
        ];
        this.nodeDataAttr = Object.assign({}, attributes, omit(nodeData, omitList));
    }
    toggleDetail(node) {
        this.showDetails = !this.showDetails;
        this.toggleAttrDetail.emit(node);
    }
    navigateTo(ancestors) {
        const nodeNavData = {
            node: this._node,
            selectedAncestorIds: ancestors
        };
        this.toggleDetail(this._node);
        this.addressSpaceService.triggerNodeToOpen(nodeNavData);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceDetailComponent, deps: [{ token: AddressSpaceService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaAddressSpaceDetailComponent, isStandalone: true, selector: "opcua-address-space-detail", inputs: { node: "node" }, outputs: { toggleAttrDetail: "toggleAttrDetail" }, ngImport: i0, template: "<div\n  class=\"card m-b-4 split-row-2 animated fast pointer-all\"\n  [ngClass]=\"{ fadeInRightBig: showDetails, fadeOutRightBig: !showDetails }\"\n>\n  <div class=\"card-header separator\">\n    <h4>{{ 'Attributes' | translate }}</h4>\n    <button\n      class=\"close m-l-auto visible-sm visible-xs\"\n      title=\"{{ 'Close' | translate }}\"\n      (click)=\"toggleDetail(nodeDataAttr)\"\n    >\n      &times;\n    </button>\n  </div>\n  <div\n    class=\"card-inner-scroll\"\n    tabindex=\"0\"\n  >\n    <div\n      class=\"card-block\"\n      tabindex=\"-1\"\n    >\n      <table class=\"table table-striped table-condensed\">\n        <colgroup>\n          <col width=\"50%\" />\n          <col width=\"50%\" />\n        </colgroup>\n        <thead>\n          <tr>\n            <th>{{ 'Attribute' | translate }}</th>\n            <th>{{ 'Value' | translate }}</th>\n          </tr>\n        </thead>\n        <tbody>\n          <tr *ngFor=\"let item of nodeDataAttr | keyvalue\">\n            <td>{{ item.key }}</td>\n            <td\n              class=\"text-break-word\"\n              *ngIf=\"item.key === 'absolutePaths'\"\n            >\n              {{ item.value | json }}\n            </td>\n            <td\n              class=\"text-break-word\"\n              *ngIf=\"item.key === 'ancestorNodeIds'\"\n            >\n              <a\n                *ngFor=\"let value of item.value\"\n                (click)=\"navigateTo(value)\"\n              >\n                {{ value | json }}\n              </a>\n            </td>\n            <td *ngIf=\"item.key !== 'absolutePaths' && item.key !== 'ancestorNodeIds'\">\n              {{ item.value }}\n            </td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </div>\n</div>\n<div\n  class=\"card split-row-2 animated fast pointer-all\"\n  style=\"height: calc(50% - 4px)\"\n  [ngClass]=\"{ fadeInRightBig: showDetails, fadeOutRightBig: !showDetails }\"\n>\n  <div class=\"card-header separator\">\n    <h4>{{ 'References' | translate }}</h4>\n  </div>\n  <div\n    class=\"card-inner-scroll\"\n    tabindex=\"0\"\n  >\n    <div\n      class=\"card-block\"\n      tabindex=\"-1\"\n    >\n      <table class=\"table table-striped table-condensed\">\n        <colgroup>\n          <col width=\"50%\" />\n          <col width=\"50%\" />\n        </colgroup>\n        <thead>\n          <tr>\n            <th>{{ 'Attribute' | translate }}</th>\n            <th>{{ 'Value' | translate }}</th>\n          </tr>\n        </thead>\n        <tbody>\n          <tr *ngFor=\"let item of nodeDataRef\">\n            <td>{{ item.referenceLabel }}</td>\n            <td class=\"text-break-word\">{{ item.targetLabel }}</td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceDetailComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-address-space-detail', imports: [NgClass, NgFor, NgIf, C8yTranslatePipe, JsonPipe, KeyValuePipe], template: "<div\n  class=\"card m-b-4 split-row-2 animated fast pointer-all\"\n  [ngClass]=\"{ fadeInRightBig: showDetails, fadeOutRightBig: !showDetails }\"\n>\n  <div class=\"card-header separator\">\n    <h4>{{ 'Attributes' | translate }}</h4>\n    <button\n      class=\"close m-l-auto visible-sm visible-xs\"\n      title=\"{{ 'Close' | translate }}\"\n      (click)=\"toggleDetail(nodeDataAttr)\"\n    >\n      &times;\n    </button>\n  </div>\n  <div\n    class=\"card-inner-scroll\"\n    tabindex=\"0\"\n  >\n    <div\n      class=\"card-block\"\n      tabindex=\"-1\"\n    >\n      <table class=\"table table-striped table-condensed\">\n        <colgroup>\n          <col width=\"50%\" />\n          <col width=\"50%\" />\n        </colgroup>\n        <thead>\n          <tr>\n            <th>{{ 'Attribute' | translate }}</th>\n            <th>{{ 'Value' | translate }}</th>\n          </tr>\n        </thead>\n        <tbody>\n          <tr *ngFor=\"let item of nodeDataAttr | keyvalue\">\n            <td>{{ item.key }}</td>\n            <td\n              class=\"text-break-word\"\n              *ngIf=\"item.key === 'absolutePaths'\"\n            >\n              {{ item.value | json }}\n            </td>\n            <td\n              class=\"text-break-word\"\n              *ngIf=\"item.key === 'ancestorNodeIds'\"\n            >\n              <a\n                *ngFor=\"let value of item.value\"\n                (click)=\"navigateTo(value)\"\n              >\n                {{ value | json }}\n              </a>\n            </td>\n            <td *ngIf=\"item.key !== 'absolutePaths' && item.key !== 'ancestorNodeIds'\">\n              {{ item.value }}\n            </td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </div>\n</div>\n<div\n  class=\"card split-row-2 animated fast pointer-all\"\n  style=\"height: calc(50% - 4px)\"\n  [ngClass]=\"{ fadeInRightBig: showDetails, fadeOutRightBig: !showDetails }\"\n>\n  <div class=\"card-header separator\">\n    <h4>{{ 'References' | translate }}</h4>\n  </div>\n  <div\n    class=\"card-inner-scroll\"\n    tabindex=\"0\"\n  >\n    <div\n      class=\"card-block\"\n      tabindex=\"-1\"\n    >\n      <table class=\"table table-striped table-condensed\">\n        <colgroup>\n          <col width=\"50%\" />\n          <col width=\"50%\" />\n        </colgroup>\n        <thead>\n          <tr>\n            <th>{{ 'Attribute' | translate }}</th>\n            <th>{{ 'Value' | translate }}</th>\n          </tr>\n        </thead>\n        <tbody>\n          <tr *ngFor=\"let item of nodeDataRef\">\n            <td>{{ item.referenceLabel }}</td>\n            <td class=\"text-break-word\">{{ item.targetLabel }}</td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: AddressSpaceService }], propDecorators: { node: [{
                type: Input
            }], toggleAttrDetail: [{
                type: Output
            }] } });

class OpcuaService {
    constructor(client, inventoryService, router, alertService) {
        this.client = client;
        this.inventoryService = inventoryService;
        this.router = router;
        this.alertService = alertService;
        this.microserviceUrl = '/service/opcua-mgmt-service';
        this.microserviceUrlDepr = '/service/opcua-mgmt-service/server';
        this.deviceTypeProtocolUrl = '/service/opcua-mgmt-service/deviceTypes';
        this.header = { 'Content-Type': 'application/json' };
        this.binaryService = inventoryService.binary;
    }
    createServer(data) {
        if (this.doesGatewayIdExist(data)) {
            this.cleanUpPayload(data);
            const options = {
                method: 'POST',
                headers: this.header,
                body: JSON.stringify(data)
            };
            return this.client.fetch(`${this.microserviceUrlDepr}`, options);
        }
    }
    async updateServer(server) {
        if (this.doesGatewayIdExist(server) && this.doesIdExist(server)) {
            this.cleanUpPayload(server);
            const options = {
                method: 'POST',
                headers: this.header,
                body: JSON.stringify(server)
            };
            const res = await this.client.fetch(`${this.microserviceUrlDepr}`, options);
            let data;
            try {
                data = await res.json();
            }
            catch (e) {
                // nothing
            }
            if (res.status !== 200) {
                this.alertService.addServerFailure({ data, res });
            }
            else {
                return data;
            }
        }
    }
    removeServer(data) {
        if (this.doesGatewayIdExist(data) && this.doesIdExist(data)) {
            const options = {
                method: 'DELETE'
            };
            return this.client.fetch(`${this.microserviceUrlDepr}/${data.gatewayId}/${data.id}`, options);
        }
    }
    getKeystore(binaryId) {
        if (binaryId && binaryId.length > 0) {
            return this.inventoryService.detail(binaryId);
        }
        return null;
    }
    uploadKeystore(file) {
        if (file && file.size > 0) {
            return this.binaryService.create(file);
        }
        return Promise.reject('Invalid file');
    }
    async updateKeystore(id, file) {
        if (id && id.length > 0 && file && file.size > 0) {
            const { res } = await this.removeKeystore(id);
            if (res && res.status === 204) {
                return this.uploadKeystore(file);
            }
        }
        return Promise.reject('Invalid file');
    }
    removeKeystore(id) {
        if (id && id.length > 0) {
            return this.binaryService.delete(id);
        }
    }
    getMoId() {
        const currentUrl = this.router.routerState.snapshot.url;
        const isDevice = new RegExp(/device\/\d+/).test(currentUrl);
        if (isDevice) {
            return currentUrl.match(/\d+/)[0];
        }
        return '';
    }
    getId() {
        const currentUrl = this.router.routerState.snapshot.url;
        const isDeviceprotocol = new RegExp(/deviceprotocols/).test(currentUrl);
        if (isDeviceprotocol && RegExp(/\d+$/).test(currentUrl)) {
            return currentUrl.match(/\d+$/)[0];
        }
    }
    async getDeviceProtocol(id) {
        const options = {
            method: 'GET',
            headers: this.header
        };
        return this.client.fetch(`${this.deviceTypeProtocolUrl}/${id}`, options);
    }
    async updateDeviceProtocol(data) {
        const options = {
            method: 'PUT',
            headers: this.header,
            body: JSON.stringify(data)
        };
        return this.client.fetch(`${this.deviceTypeProtocolUrl}/${data.id}`, options);
    }
    async createDeviceProtocol(data) {
        const options = {
            method: 'POST',
            headers: this.header,
            body: JSON.stringify(data)
        };
        return this.client.fetch(`${this.deviceTypeProtocolUrl}`, options);
    }
    getServers(id) {
        if (id && id.length > 0) {
            const options = {
                method: 'GET',
                headers: this.header
            };
            return this.client.fetch(`${this.microserviceUrlDepr}/${id}`, options);
        }
    }
    getServer(id) {
        if (id && id.length > 0) {
            const options = {
                method: 'GET',
                headers: this.header
            };
            return this.client
                .fetch(`${this.microserviceUrl}/servers/${id}`, options)
                .then(this.handleErrorStatusCodes);
        }
    }
    /**
     * Checks the response for errors and throws exceptions, otherwise returns the response as is.
     *
     * @param response The response from server.
     *
     * @returns If no errors are detected, it returns the same response.
     *
     * @throws If an error is detected, it throws `{ res, data }`, where `data` contains error details from server.
     */
    async handleErrorStatusCodes(response) {
        if (response.status >= 400) {
            let data = null;
            try {
                data = await response.json();
            }
            catch (ex) {
                try {
                    data = await response.text();
                }
                catch (ex) {
                    // do nothing
                }
            }
            throw { res: response, data };
        }
        return response;
    }
    doesGatewayIdExist(data) {
        return data && data.gatewayId && data.gatewayId.length > 0;
    }
    doesIdExist(data) {
        return data && data.id && data.id.length > 0 && data.id !== 'new';
    }
    cleanUpPayload(data) {
        if (data) {
            if (data.id && data.id === 'new') {
                delete data.id;
            }
            if (data.quickInfo) {
                delete data.quickInfo;
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaService, deps: [{ token: i1.FetchClient }, { token: i1.InventoryService }, { token: i2.Router }, { token: i2$1.AlertService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.FetchClient }, { type: i1.InventoryService }, { type: i2.Router }, { type: i2$1.AlertService }] });

class OpcuaAgentGuard {
    constructor() {
        this.type = 'c8y_OPCUA_Device_Agent';
    }
    canActivate({ data }) {
        const { contextData } = data;
        return contextData && contextData.type === this.type;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAgentGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAgentGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAgentGuard, decorators: [{
            type: Injectable
        }] });

class OpcuaDeviceProtocolBrowsePathValidation {
    constructor(el) {
        this.el = el;
    }
    validate(control) {
        if (control.value) {
            if (!this.isValidJson(control.value)) {
                return { invalidBrowsePathNotation: true };
            }
            else {
                if (this.isBrowsePathUnique(control.value)) {
                    return { browsePathNotUnique: true };
                }
            }
        }
        return null;
    }
    isValidJson(value) {
        try {
            const browsePath = JSON.parse(value);
            return !isEmpty(browsePath);
        }
        catch (error) {
            return false;
        }
    }
    toArray(str) {
        return JSON.parse(str);
    }
    isBrowsePathUnique(value) {
        const mappings = this.getMappings();
        const found = some(mappings, item => {
            if (isEqual(item.browsePath, this.toArray(value)) && item.id !== this.model.id) {
                return item;
            }
        });
        return found ? true : false;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolBrowsePathValidation, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolBrowsePathValidation, isStandalone: true, selector: "[c8yBrowsePathValidator][ngModel]", inputs: { getMappings: "getMappings", model: "model" }, providers: [
            {
                provide: NG_VALIDATORS,
                useExisting: forwardRef(() => OpcuaDeviceProtocolBrowsePathValidation),
                multi: true
            }
        ], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolBrowsePathValidation, decorators: [{
            type: Directive,
            args: [{
                    selector: '[c8yBrowsePathValidator][ngModel]',
                    providers: [
                        {
                            provide: NG_VALIDATORS,
                            useExisting: forwardRef(() => OpcuaDeviceProtocolBrowsePathValidation),
                            multi: true
                        }
                    ]
                }]
        }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { getMappings: [{
                type: Input
            }], model: [{
                type: Input
            }] } });

class DynamicDataSource {
    get data() {
        return this.dataChange.value;
    }
    set data(value) {
        this.treeControl.dataNodes = value;
        this.dataChange.next(value);
    }
    constructor(treeControl, addressSpaceService, serverId) {
        this.treeControl = treeControl;
        this.addressSpaceService = addressSpaceService;
        this.serverId = serverId;
        this.dataChange = new BehaviorSubject([]);
        this.treeControl.isExpanded = (node) => node.expanded;
    }
    connect(collectionViewer) {
        this.treeControl.expansionModel.changed.subscribe((change) => {
            if (change.added || change.removed) {
                this.handleTreeControl(change);
            }
        });
        return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
    }
    /** Handle expand/collapse behaviors */
    handleTreeControl(change) {
        if (change.added) {
            change.added.forEach(node => this.toggleNode(node, true));
        }
        if (change.removed) {
            change.removed
                .slice()
                .reverse()
                .forEach(node => this.toggleNode(node, false));
        }
    }
    /**
     * Toggle the node, remove from display list
     */
    async toggleNode(addressSpaceNode, expand) {
        if (!addressSpaceNode.children || addressSpaceNode.children.length === 0) {
            addressSpaceNode.currentlyLoadingChildren = true;
            const res = await this.addressSpaceService.getChildrenOf(addressSpaceNode, this.serverId);
            const children = (await res.json());
            addressSpaceNode.children = children || [];
            addressSpaceNode.children = addressSpaceNode.children.map((node) => {
                node.parentNode = addressSpaceNode;
                return node;
            });
            addressSpaceNode.currentlyLoadingChildren = false;
            this.treeControl.expand(addressSpaceNode);
        }
        addressSpaceNode.expanded = expand && addressSpaceNode.children.length > 0;
        this.refreshNestedTree(this.data);
        return Promise.resolve(addressSpaceNode);
    }
    catch() {
        // do nothing
    }
    refreshNestedTree(treeData) {
        // necessary to rerender tree, otherwise new nodes will not
        // appear, but they are added to the list.
        this.data = [];
        this.dataChange.next(treeData);
        this.triggerResize(); // to resize the modal window when creating a new device protocol
    }
    triggerResize() {
        setTimeout(() => {
            try {
                window.dispatchEvent(new Event('resize'));
            }
            catch (error) {
                // do nothing
            }
        }, 200);
    }
}

class OpcuaAddressSpaceTreeComponent {
    set moId(id) {
        this._moId = id || undefined;
    }
    constructor(addressSpaceService, opcuaService, alertService) {
        this.addressSpaceService = addressSpaceService;
        this.opcuaService = opcuaService;
        this.alertService = alertService;
        this.focusEmitter = new EventEmitter();
        this.selectedNode = new EventEmitter();
        this.dataSource = null;
        this.loading = false;
        this.destroy$ = new Subject();
        this.getChildren = (node) => (node.expanded ? node.children : []);
        this.hasChild = (_, _nodeData) => this.addressSpaceService.childrenAvailable(_nodeData.references);
    }
    ngOnInit() {
        this.initializeDataSet();
    }
    ngOnChanges(changes) {
        if (changes.moId &&
            changes.moId.previousValue &&
            changes.moId.currentValue !== changes.moId.previousValue) {
            this.initializeDataSet();
        }
    }
    initializeDataSet() {
        this.nodeNavDataSubscription = this.addressSpaceService
            .getNodeNavData$()
            .pipe(takeUntil(this.destroy$))
            .subscribe(nodeNavData => this.openNode(nodeNavData));
        this.subscriptionRef = this.focusEmitter.subscribe(node => {
            this.focused = this.isFocusedNode(node) ? undefined : node;
        });
    }
    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
        // clean up the address-space-tree
        this.addressSpaceService.resetTreeToRootNode();
        if (this.nodeNavDataSubscription && !this.nodeNavDataSubscription.closed) {
            this.nodeNavDataSubscription.unsubscribe();
        }
        if (this.subscriptionRef && !this.subscriptionRef.closed) {
            this.subscriptionRef.unsubscribe();
        }
    }
    async openNode(nodeNavData) {
        const { node, selectedAncestorIds } = nodeNavData;
        let nodeId;
        // We just set the nodeId when the selectedAncestorIds variable an empty array.
        // If selectedAncestorIds contain any id we assume that the tree should be travsersed beginning
        // from the root node.
        if (node && node.nodeId && selectedAncestorIds && selectedAncestorIds.length === 0) {
            nodeId = node.nodeId;
        }
        // Always recreate the tree when routing to a specific nested node,
        // because previous modifications to the tree-structure could cause errors
        // while traversing with 'old' tree-data
        // -----------------
        // setupTree is able to handle nodeId = undefined
        await this.setupTree(nodeId);
        if (!selectedAncestorIds || selectedAncestorIds.length === 0) {
            return;
        }
        if (nodeNavData && this.dataSource) {
            const clonedAncestors = clone(selectedAncestorIds);
            clonedAncestors.shift();
            const n = await this.dataSource.toggleNode(this.dataSource.data[0], true);
            this.setChildNodes(n.children, clonedAncestors);
            this.toggleFocusedNode(node);
        }
    }
    setChildNodes(nodes, ids) {
        if (nodes) {
            ids.forEach(async (id) => {
                const match = nodes.find(n => n.nodeId === id);
                if (match && ids.length > 0) {
                    const idx = ids.findIndex(value => value === id);
                    if (idx >= 0) {
                        ids.splice(idx, 1);
                    }
                    const toggledNode = await this.dataSource.toggleNode(match, true);
                    this.setChildNodes(toggledNode.children, ids);
                }
            });
        }
    }
    async setupTree(nodeId) {
        this.loading = true;
        if (!this._moId || this._moId.length === 0) {
            this._moId = this.opcuaService.getMoId();
        }
        // addressSpaceService.getNode returns either the root node of the server (moId)
        // or if nodeId !== undefined the node with given nodeId
        const res = await this.addressSpaceService.getNode(this._moId, nodeId);
        if (res) {
            if (res.status !== 200) {
                const data = res.json ? await res.json() : undefined;
                this.alertService.addServerFailure({ data, res });
                this.dataSource = undefined;
            }
            else {
                const rootNode = (await res.json());
                this.nestedTreeControl = new NestedTreeControl(this.getChildren);
                this.dataSource = new DynamicDataSource(this.nestedTreeControl, this.addressSpaceService, this._moId);
                this.dataSource.data = [rootNode];
            }
            this.loading = false;
        }
        else {
            this.loading = false;
        }
    }
    getMoId() {
        if (!this._moId || this._moId.length === 0) {
            return this.opcuaService.getMoId();
        }
        return this._moId;
    }
    getIcon(nodeClassName) {
        return this.addressSpaceService.getIcon(nodeClassName);
    }
    toggleFocusedNode(node) {
        const relativePath = [];
        this.getRelativePath(node, relativePath);
        node.relativePath = relativePath;
        this.selectedNode.emit(node);
        this.focused = this.isFocusedNode(node) ? undefined : node;
    }
    isFocusedNode(node) {
        if (this.focused) {
            return node.nodeId === this.focused.nodeId;
        }
        return false;
    }
    getRelativePath(node, relativePath) {
        if (node.parentNode) {
            relativePath.unshift(node.browseName);
            this.getRelativePath(node.parentNode, relativePath);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceTreeComponent, deps: [{ token: AddressSpaceService }, { token: OpcuaService }, { token: i2$1.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaAddressSpaceTreeComponent, isStandalone: true, selector: "opcua-address-space-tree", inputs: { moId: "moId", node: "node", focusEmitter: "focusEmitter" }, outputs: { selectedNode: "selectedNode" }, usesOnChanges: true, ngImport: i0, template: "<div\n  class=\"card-block\"\n  *ngIf=\"dataSource && !loading\"\n>\n  <cdk-tree\n    [dataSource]=\"dataSource\"\n    [treeControl]=\"nestedTreeControl\"\n  >\n    <!-- This is the tree node template for leaf nodes -->\n    <cdk-nested-tree-node\n      class=\"interact\"\n      *cdkTreeNodeDef=\"let node\"\n      (click)=\"toggleFocusedNode(node)\"\n      [ngClass]=\"{ strong: isFocusedNode(node) }\"\n    >\n      <span>\n        <i\n          class=\"m-r-4 interact\"\n          [c8yIcon]=\"getIcon(node.nodeClassName)\"\n          [ngClass]=\"{ strong: isFocusedNode(node) }\"\n        ></i>\n        {{ node.displayName }}\n      </span>\n    </cdk-nested-tree-node>\n    <!-- This is the tree node template for expandable nodes -->\n    <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\">\n      <div role=\"group\">\n        <div class=\"d-flex a-i-center\">\n          <button\n            class=\"btn-clean text-primary m-r-4\"\n            title=\"{{ 'Expand node' | translate }}\"\n            cdkTreeNodeToggle\n            [disabled]=\"node.currentlyLoadingChildren\"\n          >\n            <i\n              [ngClass]=\"{\n                'dlt-c8y-icon-plus-square': !node.expanded,\n                'dlt-c8y-icon-minus-square': node.expanded\n              }\"\n            ></i>\n          </button>\n          <i\n            class=\"m-r-4 interact\"\n            [c8yIcon]=\"getIcon(node.nodeClassName)\"\n          ></i>\n          <span\n            class=\"interact\"\n            (click)=\"toggleFocusedNode(node)\"\n            [ngClass]=\"{ strong: isFocusedNode(node) }\"\n          >\n            {{ node.displayName }}\n          </span>\n          <span\n            class=\"m-l-4\"\n            [style.visibility]=\"node.currentlyLoadingChildren ? 'visible' : 'hidden'\"\n          >\n            <i class=\"dlt-c8y-icon-circle-o-notch icon-spin\"></i>\n          </span>\n        </div>\n        <ng-container cdkTreeNodeOutlet></ng-container>\n      </div>\n    </cdk-nested-tree-node>\n  </cdk-tree>\n</div>\n<div\n  class=\"p-t-8\"\n  *ngIf=\"loading\"\n>\n  <c8y-loading></c8y-loading>\n</div>\n<div\n  class=\"alert alert-info m-t-16\"\n  *ngIf=\"!dataSource && !loading\"\n  translate\n>\n  No source data available to fetch address space.\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CdkTree, selector: "cdk-tree", inputs: ["dataSource", "treeControl", "levelAccessor", "childrenAccessor", "trackBy", "expansionKey"], exportAs: ["cdkTree"] }, { kind: "directive", type: CdkTreeNodeDef, selector: "[cdkTreeNodeDef]", inputs: ["cdkTreeNodeDefWhen"] }, { kind: "directive", type: CdkNestedTreeNode, selector: "cdk-nested-tree-node", exportAs: ["cdkNestedTreeNode"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: CdkTreeNodeToggle, selector: "[cdkTreeNodeToggle]", inputs: ["cdkTreeNodeToggleRecursive"] }, { kind: "directive", type: CdkTreeNodeOutlet, selector: "[cdkTreeNodeOutlet]" }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceTreeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-address-space-tree', imports: [
                        NgIf,
                        CdkTree,
                        CdkTreeNodeDef,
                        CdkNestedTreeNode,
                        NgClass,
                        IconDirective,
                        CdkTreeNodeToggle,
                        CdkTreeNodeOutlet,
                        LoadingComponent,
                        C8yTranslateDirective,
                        C8yTranslatePipe
                    ], template: "<div\n  class=\"card-block\"\n  *ngIf=\"dataSource && !loading\"\n>\n  <cdk-tree\n    [dataSource]=\"dataSource\"\n    [treeControl]=\"nestedTreeControl\"\n  >\n    <!-- This is the tree node template for leaf nodes -->\n    <cdk-nested-tree-node\n      class=\"interact\"\n      *cdkTreeNodeDef=\"let node\"\n      (click)=\"toggleFocusedNode(node)\"\n      [ngClass]=\"{ strong: isFocusedNode(node) }\"\n    >\n      <span>\n        <i\n          class=\"m-r-4 interact\"\n          [c8yIcon]=\"getIcon(node.nodeClassName)\"\n          [ngClass]=\"{ strong: isFocusedNode(node) }\"\n        ></i>\n        {{ node.displayName }}\n      </span>\n    </cdk-nested-tree-node>\n    <!-- This is the tree node template for expandable nodes -->\n    <cdk-nested-tree-node *cdkTreeNodeDef=\"let node; when: hasChild\">\n      <div role=\"group\">\n        <div class=\"d-flex a-i-center\">\n          <button\n            class=\"btn-clean text-primary m-r-4\"\n            title=\"{{ 'Expand node' | translate }}\"\n            cdkTreeNodeToggle\n            [disabled]=\"node.currentlyLoadingChildren\"\n          >\n            <i\n              [ngClass]=\"{\n                'dlt-c8y-icon-plus-square': !node.expanded,\n                'dlt-c8y-icon-minus-square': node.expanded\n              }\"\n            ></i>\n          </button>\n          <i\n            class=\"m-r-4 interact\"\n            [c8yIcon]=\"getIcon(node.nodeClassName)\"\n          ></i>\n          <span\n            class=\"interact\"\n            (click)=\"toggleFocusedNode(node)\"\n            [ngClass]=\"{ strong: isFocusedNode(node) }\"\n          >\n            {{ node.displayName }}\n          </span>\n          <span\n            class=\"m-l-4\"\n            [style.visibility]=\"node.currentlyLoadingChildren ? 'visible' : 'hidden'\"\n          >\n            <i class=\"dlt-c8y-icon-circle-o-notch icon-spin\"></i>\n          </span>\n        </div>\n        <ng-container cdkTreeNodeOutlet></ng-container>\n      </div>\n    </cdk-nested-tree-node>\n  </cdk-tree>\n</div>\n<div\n  class=\"p-t-8\"\n  *ngIf=\"loading\"\n>\n  <c8y-loading></c8y-loading>\n</div>\n<div\n  class=\"alert alert-info m-t-16\"\n  *ngIf=\"!dataSource && !loading\"\n  translate\n>\n  No source data available to fetch address space.\n</div>\n" }]
        }], ctorParameters: () => [{ type: AddressSpaceService }, { type: OpcuaService }, { type: i2$1.AlertService }], propDecorators: { moId: [{
                type: Input
            }], node: [{
                type: Input
            }], focusEmitter: [{
                type: Input
            }], selectedNode: [{
                type: Output
            }] } });

class OpcuaAddressSpaceComponent {
    constructor(addressSpaceService, opcuaService, operationService, operationRealtimeService, alert, modalService) {
        this.addressSpaceService = addressSpaceService;
        this.opcuaService = opcuaService;
        this.operationService = operationService;
        this.operationRealtimeService = operationRealtimeService;
        this.alert = alert;
        this.modalService = modalService;
        this.selectednode = false;
        this.loading = false;
        this.searchInProgress = false;
        this.isOperationRunning = signal(false, ...(ngDevMode ? [{ debugName: "isOperationRunning" }] : []));
        this.destroyRef = inject(DestroyRef);
        this.focusStatus = new EventEmitter();
        this.moId = '';
    }
    async ngOnInit() {
        this.filterLabel = gettext('Filter…');
        this.moId = this.opcuaService.getMoId();
        this.operation = await this.getRunningScanAddressSpaceOperation();
        this.isOperationRunning.set(!!this.operation);
        this.operationRealtimeService
            .onAll$(this.moId)
            .pipe(map(({ data }) => data), filter(operation => operation.c8y_ua_command_ScanAddressSpace), takeUntilDestroyed(this.destroyRef))
            .subscribe(operation => {
            this.operation = operation;
            this.isOperationRunning.set(operation.status == OperationStatus.EXECUTING ||
                operation.status == OperationStatus.PENDING);
            if (operation.status == OperationStatus.SUCCESSFUL) {
                this.addressSpaceService.resetTreeToRootNode();
            }
        });
    }
    async getRunningScanAddressSpaceOperation() {
        const filter = {
            deviceId: this.moId,
            fragmentType: 'c8y_ua_command_ScanAddressSpace',
            dateFrom: new Date(0).toISOString(),
            revert: true,
            pageSize: 1
        };
        const [operation] = (await this.operationService.list(filter)).data ?? [];
        return operation?.status == OperationStatus.EXECUTING ||
            operation?.status == OperationStatus.PENDING
            ? operation
            : undefined;
    }
    ngOnDestroy() {
        // The BehaviourSubject will store the last array of ancestorNodes from the previous search
        // this would cause the component while subscribing in the init-phase to the subject to travers
        // to the last searched node again. From user perspective it does not make sense, because the user
        // left the Address space (tab) and should loose the context and just request a new search or
        // browse the tree manually.
        this.addressSpaceService.resetTreeToRootNode();
    }
    async searchNodes() {
        this.searchInProgress = true;
        this.clearNodeListAndCheckSearchString();
        if (this.isSearch) {
            this.currentNode = undefined;
            this.nodeList = await this.addressSpaceService.getSearchedNodes(this.searchKey, this.moId);
            this.searchInProgress = false;
            this.nodeList.resultLabel = gettext('Results found');
        }
    }
    clearNodeListAndCheckSearchString() {
        this.isSearch = this.searchKey !== undefined && this.searchKey !== '' ? true : false;
        if (!this.isSearch) {
            this.searchInProgress = false;
        }
    }
    clearSearch() {
        this.isSearch = false;
        this.searchKey = '';
        this.currentNode = undefined;
    }
    getIcon(nodeClassName) {
        return this.addressSpaceService.getIcon(nodeClassName);
    }
    async selectNode(node) {
        if (node && node.nodeId && node.nodeId.length > 0) {
            const res = await this.addressSpaceService.getNodeById(this.moId, node.nodeId);
            this.toggleCurrentNode((await res.json()));
        }
    }
    toggleCurrentNode(node) {
        this.currentNode = this.isNodeSet(node) ? undefined : node;
    }
    backHandler(node) {
        this.isSearch = false;
        this.focusStatus.emit(node);
        this.toggleCurrentNode(node);
    }
    isNodeSet(node) {
        if (this.currentNode !== undefined && this.currentNode.nodeId === node.nodeId) {
            return true;
        }
        return false;
    }
    async rescanAddressSpace() {
        const serverResponse = await this.opcuaService.getServer(this.moId);
        const server = (await serverResponse.json());
        let warning = gettext('Rescanning address space from root node might take several hours. Do you want to proceed?');
        if (server) {
            if (server.config.partialAddressScan && !isEmpty(server.config.partialAddressScanNodeIds)) {
                warning = gettext('Rescanning from nodes ' +
                    server.config.partialAddressScanNodeIds?.join(';') +
                    '. Address space rescan might take several hours. Do you want to proceed?');
            }
        }
        const doit = await this.modalService.confirm(gettext('Rescan address space'), warning, 'warning', { ok: gettext('Rescan'), cancel: gettext('Cancel') });
        if (!doit) {
            return;
        }
        const operation = await this.createConfigurationAwareScanAdressSpaceOperation(server.config);
        try {
            this.operation = (await this.operationService.create(operation)).data;
            this.isOperationRunning.set(true);
        }
        catch (error) {
            this.alert.add({
                text: gettext('Error creating rescan operation'),
                detailedData: error,
                type: 'danger',
                timeout: 8000
            });
            this.isOperationRunning.set(false);
        }
    }
    async createConfigurationAwareScanAdressSpaceOperation(config) {
        const result = {
            deviceId: this.moId,
            description: gettext('[RESCAN] Address space import from Root node'),
            c8y_ua_command_ScanAddressSpace: {
                skipSync: false
            }
        };
        if (config) {
            if (config.partialAddressScan && config.partialAddressScanNodeIds) {
                const nodeIds = config.partialAddressScanNodeIds;
                result.c8y_ua_command_ScanAddressSpace.nodeIds = config.partialAddressScanNodeIds;
                result.description = gettext(`[RESCAN] Address space from node[s] ${nodeIds.join(';')}`);
            }
        }
        return result;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceComponent, deps: [{ token: AddressSpaceService }, { token: OpcuaService }, { token: i1.OperationService }, { token: i2$1.OperationRealtimeService }, { token: i2$1.AlertService }, { token: i2$1.ModalService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaAddressSpaceComponent, isStandalone: true, selector: "opcua-address-space", outputs: { focusStatus: "focusStatus" }, ngImport: i0, template: "<div class=\"row split-scroll\">\n  <div class=\"col-md-5 col-xs-12 scroll-column no-gutter-r\">\n    <div class=\"card bg-level-2 split-scroll overflow-auto\">\n      <div class=\"flex-grow\">\n        <fieldset\n          class=\"card-block large-padding bg-level-2 p-0\"\n          id=\"operation-block\"\n          *ngIf=\"!!operation\"\n        >\n          <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n        </fieldset>\n      </div>\n      <div class=\"card-block separator sticky-top\">\n        <div class=\"input-group input-group-search\">\n          <input\n            class=\"form-control\"\n            placeholder=\"{{ filterLabel | translate }}\"\n            type=\"search\"\n            (keydown.enter)=\"searchNodes()\"\n            [(ngModel)]=\"searchKey\"\n          />\n          <span class=\"input-group-btn\">\n            <button\n              class=\"btn btn-dot\"\n              title=\"{{ 'Search' | translate }}\"\n              type=\"submit\"\n              *ngIf=\"!isSearch\"\n              (click)=\"searchNodes()\"\n            >\n              <i c8yIcon=\"search\"></i>\n            </button>\n            <button\n              class=\"btn btn-dot\"\n              title=\"{{ 'Clear`input`' | translate }}\"\n              type=\"button\"\n              *ngIf=\"isSearch\"\n              (click)=\"clearSearch()\"\n            >\n              <i c8yIcon=\"times\"></i>\n            </button>\n          </span>\n        </div>\n        <div\n          class=\"p-t-16\"\n          *ngIf=\"isSearch && !loading\"\n        >\n          <p *ngIf=\"!searchInProgress\">\n            <em>{{ nodeList.resultLabel | translate }}</em>\n            &nbsp;\n            <span class=\"badge badge-info\">{{ nodeList?.length }}</span>\n          </p>\n        </div>\n      </div>\n\n      <div\n        class=\"p-t-8\"\n        *ngIf=\"(isSearch && loading) || searchInProgress\"\n      >\n        <c8y-loading></c8y-loading>\n      </div>\n\n      <div\n        class=\"inner-scroll\"\n        *ngIf=\"isSearch && !loading && !searchInProgress\"\n      >\n        <div\n          class=\"list-group list-group-links\"\n          *ngIf=\"isSearch && !loading\"\n        >\n          <button\n            *ngFor=\"let nodeItem of nodeList\"\n            (click)=\"selectNode(nodeItem)\"\n            [ngClass]=\"{ 'list-group-item d-flex': true }\"\n          >\n            <div class=\"list-group-icon m-r-4\">\n              <i\n                class=\"m-r-4\"\n                [c8yIcon]=\"getIcon(nodeItem.nodeClassName)\"\n              ></i>\n            </div>\n            <div class=\"list-item-body text-truncate\">\n              <span tile=\"nodeId\">{{ nodeItem.nodeId }}</span>\n              {{ nodeItem.displayName }}\n            </div>\n          </button>\n        </div>\n      </div>\n      <div\n        class=\"inner-scroll\"\n        *ngIf=\"!isSearch\"\n      >\n        <opcua-address-space-tree\n          (selectedNode)=\"toggleCurrentNode($event)\"\n          [focusEmitter]=\"focusStatus\"\n        ></opcua-address-space-tree>\n      </div>\n      <div class=\"card-footer separator-top\">\n        <button\n          class=\"btn btn-default\"\n          [class.btn-pending]=\"isOperationRunning()\"\n          type=\"button\"\n          (click)=\"rescanAddressSpace()\"\n          [disabled]=\"isOperationRunning()\"\n        >\n          {{ 'Rescan' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n  <opcua-address-space-detail\n    class=\"col-md-7 col-xs-12 scroll-column no-gutter-l no-pointer\"\n    [node]=\"currentNode\"\n    (toggleAttrDetail)=\"backHandler($event)\"\n  ></opcua-address-space-detail>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: OpcuaAddressSpaceTreeComponent, selector: "opcua-address-space-tree", inputs: ["moId", "node", "focusEmitter"], outputs: ["selectedNode"] }, { kind: "component", type: OpcuaAddressSpaceDetailComponent, selector: "opcua-address-space-detail", inputs: ["node"], outputs: ["toggleAttrDetail"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAddressSpaceComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-address-space', imports: [
                        NgIf,
                        OperationDetailsComponent,
                        FormsModule,
                        IconDirective,
                        LoadingComponent,
                        NgFor,
                        NgClass,
                        OpcuaAddressSpaceTreeComponent,
                        OpcuaAddressSpaceDetailComponent,
                        C8yTranslatePipe
                    ], template: "<div class=\"row split-scroll\">\n  <div class=\"col-md-5 col-xs-12 scroll-column no-gutter-r\">\n    <div class=\"card bg-level-2 split-scroll overflow-auto\">\n      <div class=\"flex-grow\">\n        <fieldset\n          class=\"card-block large-padding bg-level-2 p-0\"\n          id=\"operation-block\"\n          *ngIf=\"!!operation\"\n        >\n          <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n        </fieldset>\n      </div>\n      <div class=\"card-block separator sticky-top\">\n        <div class=\"input-group input-group-search\">\n          <input\n            class=\"form-control\"\n            placeholder=\"{{ filterLabel | translate }}\"\n            type=\"search\"\n            (keydown.enter)=\"searchNodes()\"\n            [(ngModel)]=\"searchKey\"\n          />\n          <span class=\"input-group-btn\">\n            <button\n              class=\"btn btn-dot\"\n              title=\"{{ 'Search' | translate }}\"\n              type=\"submit\"\n              *ngIf=\"!isSearch\"\n              (click)=\"searchNodes()\"\n            >\n              <i c8yIcon=\"search\"></i>\n            </button>\n            <button\n              class=\"btn btn-dot\"\n              title=\"{{ 'Clear`input`' | translate }}\"\n              type=\"button\"\n              *ngIf=\"isSearch\"\n              (click)=\"clearSearch()\"\n            >\n              <i c8yIcon=\"times\"></i>\n            </button>\n          </span>\n        </div>\n        <div\n          class=\"p-t-16\"\n          *ngIf=\"isSearch && !loading\"\n        >\n          <p *ngIf=\"!searchInProgress\">\n            <em>{{ nodeList.resultLabel | translate }}</em>\n            &nbsp;\n            <span class=\"badge badge-info\">{{ nodeList?.length }}</span>\n          </p>\n        </div>\n      </div>\n\n      <div\n        class=\"p-t-8\"\n        *ngIf=\"(isSearch && loading) || searchInProgress\"\n      >\n        <c8y-loading></c8y-loading>\n      </div>\n\n      <div\n        class=\"inner-scroll\"\n        *ngIf=\"isSearch && !loading && !searchInProgress\"\n      >\n        <div\n          class=\"list-group list-group-links\"\n          *ngIf=\"isSearch && !loading\"\n        >\n          <button\n            *ngFor=\"let nodeItem of nodeList\"\n            (click)=\"selectNode(nodeItem)\"\n            [ngClass]=\"{ 'list-group-item d-flex': true }\"\n          >\n            <div class=\"list-group-icon m-r-4\">\n              <i\n                class=\"m-r-4\"\n                [c8yIcon]=\"getIcon(nodeItem.nodeClassName)\"\n              ></i>\n            </div>\n            <div class=\"list-item-body text-truncate\">\n              <span tile=\"nodeId\">{{ nodeItem.nodeId }}</span>\n              {{ nodeItem.displayName }}\n            </div>\n          </button>\n        </div>\n      </div>\n      <div\n        class=\"inner-scroll\"\n        *ngIf=\"!isSearch\"\n      >\n        <opcua-address-space-tree\n          (selectedNode)=\"toggleCurrentNode($event)\"\n          [focusEmitter]=\"focusStatus\"\n        ></opcua-address-space-tree>\n      </div>\n      <div class=\"card-footer separator-top\">\n        <button\n          class=\"btn btn-default\"\n          [class.btn-pending]=\"isOperationRunning()\"\n          type=\"button\"\n          (click)=\"rescanAddressSpace()\"\n          [disabled]=\"isOperationRunning()\"\n        >\n          {{ 'Rescan' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n  <opcua-address-space-detail\n    class=\"col-md-7 col-xs-12 scroll-column no-gutter-l no-pointer\"\n    [node]=\"currentNode\"\n    (toggleAttrDetail)=\"backHandler($event)\"\n  ></opcua-address-space-detail>\n</div>\n" }]
        }], ctorParameters: () => [{ type: AddressSpaceService }, { type: OpcuaService }, { type: i1.OperationService }, { type: i2$1.OperationRealtimeService }, { type: i2$1.AlertService }, { type: i2$1.ModalService }], propDecorators: { focusStatus: [{
                type: Output
            }] } });

class OpcuaAutoApplySettingsComponent {
    constructor(inventoryService) {
        this.inventoryService = inventoryService;
        this.opcuaServers = [];
        this.selectedItems = [];
        this.filteredList = [];
        this.checked = {};
        this.sizeToShowFilter = 5;
        this.constraints = {
            browsePathMatchesRegex: '',
            matchesNodeIds: [],
            serverObjectHasFragment: '',
            matchesServerIds: []
        };
        this.placeholderSelectServerIds = gettext('Select server IDs from list');
        this.updateSelectedItem = new EventEmitter();
    }
    async ngOnInit() {
        const { data } = await this.inventoryService.list({
            pageSize: 1000,
            withTotalPages: true,
            type: 'c8y_OpcuaServer'
        });
        this.opcuaServers = data;
        this.filteredList = data;
        this.selectedItems = [];
        const { matchesServerIds } = this.constraints;
        data.forEach(server => {
            if (matchesServerIds &&
                matchesServerIds.length > 0 &&
                matchesServerIds.find(itemId => itemId === server.id)) {
                this.selectedItems.push(server);
                this.checked[server.id] = true;
                this.showServerIds = true;
            }
        });
    }
    set model(model) {
        if (model && model.applyConstraints) {
            this.constraints = model.applyConstraints;
        }
        this._model = model;
    }
    get model() {
        return this._model;
    }
    serverIdsSelected(items) {
        if (this.constraints) {
            this.constraints.matchesServerIds = items.map((item) => item.id);
        }
        this.selectedItems = items;
    }
    onChangeNodeId(event) {
        if (event.target.checked) {
            this.showRootNodes = true;
            this.add();
        }
        else {
            this.showRootNodes = false;
            this.constraints.matchesNodeIds = [];
        }
    }
    onChangeShowServerIds(event) {
        if (!event.target.checked) {
            this.constraints.matchesServerIds = [];
            this.showServerIds = false;
            this.selectedItems = [];
            this.checked = {};
        }
        else {
            this.showServerIds = true;
        }
    }
    onChangeShowBrowsePath(event) {
        if (!event.target.checked) {
            this.constraints.browsePathMatchesRegex = '';
            this.showBrowsePath = false;
        }
        else {
            this.showBrowsePath = true;
        }
    }
    onChangeShowServerFragment(event) {
        if (!event.target.checked) {
            this.constraints.serverObjectHasFragment = '';
            this.showServerFragment = false;
        }
        else {
            this.showServerFragment = true;
        }
    }
    add() {
        this.constraints.matchesNodeIds.push('');
    }
    remove(index) {
        this.constraints.matchesNodeIds.splice(index, 1);
    }
    trackByFn(index, _item) {
        return index;
    }
    updateConstraints(items) {
        if (this.constraints) {
            this.constraints.matchesServerIds = items.map((item) => item.id);
        }
    }
    filterItems(filterText) {
        if (filterText.length !== 0) {
            const search = new RegExp(filterText, 'i');
            this.filteredList = this.opcuaServers.filter(({ name, id }) => {
                return search.test(name) || search.test(id);
            });
        }
        else {
            this.filteredList = this.opcuaServers;
        }
    }
    isChecked(item) {
        return this.checked[item.id];
    }
    onSelect(selected, item) {
        if (!selected) {
            this.selectedItems = reject(this.selectedItems, { id: item.id });
            delete this.checked[item.id];
        }
        else {
            this.selectedItems.push(item);
            this.checked[item.id] = selected;
        }
        this.updateSelectedItem.emit(true);
        this.updateConstraints(this.selectedItems);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAutoApplySettingsComponent, deps: [{ token: i1.InventoryService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaAutoApplySettingsComponent, isStandalone: true, selector: "opcua-auto-apply", inputs: { model: "model" }, ngImport: i0, template: "<div class=\"row\">\n  <div class=\"col-md-4\">\n    <p translate>\n      Specifying auto-apply constraints allows you to limit the scope where the device protocols are\n      applied, for example by specifying a set of possible servers or node IDs.\n    </p>\n    <p translate>\n      If no constraints are set, device protocols are applied at any fitting location on the OPC UA\n      server.\n    </p>\n  </div>\n\n  <div class=\"col-md-6\">\n    <ul class=\"list-group\" style=\"box-shadow: none;\">\n      <!-- Limit device type to a set of servers -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to a set of servers' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"\n              constraints.matchesServerIds !== null && constraints.matchesServerIds.length > 0\n            \"\n            (change)=\"onChangeShowServerIds($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to a set of servers' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [collapse]=\"\n            (!showServerIds &&\n              (constraints.matchesServerIds !== null && constraints.matchesServerIds.length < 1)) ||\n            (!showServerIds && constraints.matchesServerIds === null)\n          \"\n          [isAnimated]=\"true\"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <c8y-select-legacy\n              [items]=\"opcuaServers\"\n              [selected]=\"selectedItems\"\n              [placeholder]=\"placeholderSelectServerIds\"\n              (onChange)=\"serverIdsSelected($event)\"\n              [updateItems]=\"updateSelectedItem\"\n            >\n            \n              <c8y-li *ngIf=\"opcuaServers.length > sizeToShowFilter\" class=\"sticky-top\">\n                <c8y-filter [icon]=\"'search'\"  (onSearch)=\"filterItems($event)\"></c8y-filter>\n              </c8y-li>\n              <c8y-li *ngIf=\"filteredList && filteredList.length === 0\">\n                <c8y-li-body> \n                  <div class=\"c8y-empty-state text-left\">\n                  <p>{{ 'No items to display.' | translate }}</p>\n                </div>\n                </c8y-li-body>\n              </c8y-li>\n              <c8y-li *ngFor=\"let item of filteredList\">\n                <c8y-li-checkbox\n                  [selected]=\"isChecked(item)\"\n                  (onSelect)=\"onSelect($event, item)\"\n                ></c8y-li-checkbox>\n                <c8y-li-body>{{ item.name | translate }}<br>\n                  <span class=\"text-label-small m-r-4\" translate>ID</span> <small>{{ item.id }}</small>\n                </c8y-li-body>\n              </c8y-li>\n            </c8y-select-legacy>\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type scope in the address space -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol scope in the address space' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"\n              constraints.browsePathMatchesRegex !== null &&\n              constraints.browsePathMatchesRegex.length > 0\n            \"\n            (change)=\"onChangeShowBrowsePath($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol scope in the address space' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"\n            (!showBrowsePath &&\n              constraints.browsePathMatchesRegex !== null &&\n              constraints.browsePathMatchesRegex.length < 1) ||\n            (!showBrowsePath && constraints.browsePathMatchesRegex === null)\n          \"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <input\n              name=\"browsePath\"\n              type=\"text\"\n              class=\"form-control\"\n              placeholder=\"{{ 'e.g.' | translate }} /objects/devices/.*\"\n              [(ngModel)]=\"constraints.browsePathMatchesRegex\"\n              ngDefaultControl\n            />\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type to servers with a certain fragment-->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to servers with a certain fragment' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"constraints.serverObjectHasFragment !== null && constraints.serverObjectHasFragment.length > 0\"\n            (change)=\"onChangeShowServerFragment($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to servers with a certain fragment' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"(!showServerFragment && constraints.serverObjectHasFragment !== null && constraints.serverObjectHasFragment.length < 1) || (!showServerFragment && constraints.serverObjectHasFragment === null)\"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <input\n              name=\"serverFragment\"\n              type=\"text\"\n              class=\"form-control\"\n              placeholder=\"{{ 'e.g.' | translate }} c8y_SomeServerMarker\"\n              [(ngModel)]=\"constraints.serverObjectHasFragment\"\n              ngDefaultControl\n            />\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type to a specific root node ID -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to specific root nodes ID' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"constraints.matchesNodeIds !== null && constraints.matchesNodeIds.length > 0\"\n            (change)=\"onChangeNodeId($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to specific root nodes ID' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"(!showRootNodes && constraints.matchesNodeIds !== null && constraints.matchesNodeIds.length < 1) || ( !showRootNodes && constraints.matchesNodeIds === null)\"\n        >\n            <ul c8yInputGroupListContainer class=\"list-unstyled p-t-16\">\n              <li\n                class=\"m-b-8\"\n                *ngFor=\"let item of constraints.matchesNodeIds; let i = index; trackBy: trackByFn\"\n              >\n                <c8y-input-group-list [index]=\"i\" (onAdd)=\"add()\" (onRemove)=\"remove($event)\">\n                  <c8y-form-group class=\"form-group--tooltip-validation\">\n                    <input\n                      type=\"text\"\n                      class=\"form-control\"\n                      placeholder=\"{{ 'e.g.' | translate }} nodeId\"\n                      [(ngModel)]=\"constraints.matchesNodeIds[i]\"\n                      [required]=\"true\"\n                    />\n                  </c8y-form-group>\n                </c8y-input-group-list>\n              </li>\n            </ul> \n        </div>\n      </li>\n    </ul>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: SelectLegacyComponent, selector: "c8y-select-legacy", inputs: ["placeholder", "selectedLabel", "applyLabel", "items", "selected", "updateItems", "disableApplyOnNoSelection", "addDropdownContainerToBody"], outputs: ["onChange"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: FilterInputComponent, selector: "c8y-filter", inputs: ["icon", "filterTerm"], outputs: ["onSearch"] }, { kind: "component", type: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: InputGroupListContainerDirective, selector: "[c8yInputGroupListContainer]" }, { kind: "component", type: InputGroupListComponent, selector: "c8y-input-group-list", inputs: ["plus", "minus", "index"], outputs: ["onRemove", "onAdd"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaAutoApplySettingsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-auto-apply', imports: [
                        C8yTranslateDirective,
                        CollapseDirective,
                        FormGroupComponent,
                        SelectLegacyComponent,
                        NgIf,
                        ListItemComponent,
                        FilterInputComponent,
                        ListItemBodyComponent,
                        NgFor,
                        ListItemCheckboxComponent,
                        FormsModule,
                        InputGroupListContainerDirective,
                        InputGroupListComponent,
                        RequiredInputPlaceholderDirective,
                        C8yTranslatePipe
                    ], template: "<div class=\"row\">\n  <div class=\"col-md-4\">\n    <p translate>\n      Specifying auto-apply constraints allows you to limit the scope where the device protocols are\n      applied, for example by specifying a set of possible servers or node IDs.\n    </p>\n    <p translate>\n      If no constraints are set, device protocols are applied at any fitting location on the OPC UA\n      server.\n    </p>\n  </div>\n\n  <div class=\"col-md-6\">\n    <ul class=\"list-group\" style=\"box-shadow: none;\">\n      <!-- Limit device type to a set of servers -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to a set of servers' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"\n              constraints.matchesServerIds !== null && constraints.matchesServerIds.length > 0\n            \"\n            (change)=\"onChangeShowServerIds($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to a set of servers' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [collapse]=\"\n            (!showServerIds &&\n              (constraints.matchesServerIds !== null && constraints.matchesServerIds.length < 1)) ||\n            (!showServerIds && constraints.matchesServerIds === null)\n          \"\n          [isAnimated]=\"true\"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <c8y-select-legacy\n              [items]=\"opcuaServers\"\n              [selected]=\"selectedItems\"\n              [placeholder]=\"placeholderSelectServerIds\"\n              (onChange)=\"serverIdsSelected($event)\"\n              [updateItems]=\"updateSelectedItem\"\n            >\n            \n              <c8y-li *ngIf=\"opcuaServers.length > sizeToShowFilter\" class=\"sticky-top\">\n                <c8y-filter [icon]=\"'search'\"  (onSearch)=\"filterItems($event)\"></c8y-filter>\n              </c8y-li>\n              <c8y-li *ngIf=\"filteredList && filteredList.length === 0\">\n                <c8y-li-body> \n                  <div class=\"c8y-empty-state text-left\">\n                  <p>{{ 'No items to display.' | translate }}</p>\n                </div>\n                </c8y-li-body>\n              </c8y-li>\n              <c8y-li *ngFor=\"let item of filteredList\">\n                <c8y-li-checkbox\n                  [selected]=\"isChecked(item)\"\n                  (onSelect)=\"onSelect($event, item)\"\n                ></c8y-li-checkbox>\n                <c8y-li-body>{{ item.name | translate }}<br>\n                  <span class=\"text-label-small m-r-4\" translate>ID</span> <small>{{ item.id }}</small>\n                </c8y-li-body>\n              </c8y-li>\n            </c8y-select-legacy>\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type scope in the address space -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol scope in the address space' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"\n              constraints.browsePathMatchesRegex !== null &&\n              constraints.browsePathMatchesRegex.length > 0\n            \"\n            (change)=\"onChangeShowBrowsePath($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol scope in the address space' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"\n            (!showBrowsePath &&\n              constraints.browsePathMatchesRegex !== null &&\n              constraints.browsePathMatchesRegex.length < 1) ||\n            (!showBrowsePath && constraints.browsePathMatchesRegex === null)\n          \"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <input\n              name=\"browsePath\"\n              type=\"text\"\n              class=\"form-control\"\n              placeholder=\"{{ 'e.g.' | translate }} /objects/devices/.*\"\n              [(ngModel)]=\"constraints.browsePathMatchesRegex\"\n              ngDefaultControl\n            />\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type to servers with a certain fragment-->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to servers with a certain fragment' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"constraints.serverObjectHasFragment !== null && constraints.serverObjectHasFragment.length > 0\"\n            (change)=\"onChangeShowServerFragment($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to servers with a certain fragment' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"(!showServerFragment && constraints.serverObjectHasFragment !== null && constraints.serverObjectHasFragment.length < 1) || (!showServerFragment && constraints.serverObjectHasFragment === null)\"\n        >\n          <c8y-form-group class=\"m-t-8 m-b-8\">\n            <input\n              name=\"serverFragment\"\n              type=\"text\"\n              class=\"form-control\"\n              placeholder=\"{{ 'e.g.' | translate }} c8y_SomeServerMarker\"\n              [(ngModel)]=\"constraints.serverObjectHasFragment\"\n              ngDefaultControl\n            />\n          </c8y-form-group>\n        </div>\n      </li>\n      <!-- Limit device type to a specific root node ID -->\n      <li class=\"list-group-item\">\n        <label\n          title=\"{{ 'Limit device protocol to specific root nodes ID' | translate }}\"\n          class=\"c8y-checkbox\"\n        >\n          <input\n            type=\"checkbox\"\n            [checked]=\"constraints.matchesNodeIds !== null && constraints.matchesNodeIds.length > 0\"\n            (change)=\"onChangeNodeId($event)\"\n          />\n          <span></span>\n          <span class=\"m-l-8\">\n            {{ 'Limit device protocol to specific root nodes ID' | translate }}\n          </span>\n        </label>\n        <div\n          class=\"collapse\"\n          [isAnimated]=\"true\"\n          [collapse]=\"(!showRootNodes && constraints.matchesNodeIds !== null && constraints.matchesNodeIds.length < 1) || ( !showRootNodes && constraints.matchesNodeIds === null)\"\n        >\n            <ul c8yInputGroupListContainer class=\"list-unstyled p-t-16\">\n              <li\n                class=\"m-b-8\"\n                *ngFor=\"let item of constraints.matchesNodeIds; let i = index; trackBy: trackByFn\"\n              >\n                <c8y-input-group-list [index]=\"i\" (onAdd)=\"add()\" (onRemove)=\"remove($event)\">\n                  <c8y-form-group class=\"form-group--tooltip-validation\">\n                    <input\n                      type=\"text\"\n                      class=\"form-control\"\n                      placeholder=\"{{ 'e.g.' | translate }} nodeId\"\n                      [(ngModel)]=\"constraints.matchesNodeIds[i]\"\n                      [required]=\"true\"\n                    />\n                  </c8y-form-group>\n                </c8y-input-group-list>\n              </li>\n            </ul> \n        </div>\n      </li>\n    </ul>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1.InventoryService }], propDecorators: { model: [{
                type: Input
            }] } });

class OpcuaDeviceProtocolDataReportingComponent {
    constructor() {
        this.onSubscriptionChange = new EventEmitter();
        this.subscription = {
            type: 'None'
        };
        this.subscriptionParameters = {
            samplingRate: undefined,
            deadbandType: 'None',
            deadbandValue: undefined,
            ranges: '',
            queueSize: undefined,
            dataChangeTrigger: 'Status',
            discardOldest: true
        };
        this.cyclicReadParameters = {
            rate: undefined
        };
        this.types = [
            { value: 'None', label: gettext('None') },
            { value: 'CyclicRead', label: gettext('Cyclic read') },
            { value: 'Subscription', label: gettext('Subscription') }
        ];
        this.filters = [
            { value: 'None', label: gettext('None') },
            { value: 'Absolute', label: gettext('Absolute') },
            { value: 'Percent', label: gettext('Percent') }
        ];
        this.triggers = [
            { value: 'Status', label: gettext('Status') },
            { value: 'StatusValue', label: gettext('Status/Value') },
            { value: 'StatusValueTimestamp', label: gettext('Status/Value/Timestamp') }
        ];
        this.discard = [
            { value: true, label: gettext('oldest`data`') },
            { value: false, label: gettext('newest`data`') }
        ];
        this.requireCyclic = false;
        this.requireSubscription = false;
        this.subscriptionTypeName = 'subscriptionType';
        this.parseReadingInterval = $event => toInteger($event.target.value);
    }
    set model(_model) {
        if (_model.subscriptionType) {
            this.subscription = _model.subscriptionType;
            if (this.subscription.type === 'CyclicRead') {
                this.cyclicReadParameters = _model.subscriptionType.cyclicReadParameters;
                this.requireCyclic = true;
                this.requireSubscription = false;
            }
            if (this.subscription.type === 'Subscription') {
                this.subscriptionParameters = _model.subscriptionType.subscriptionParameters;
                this.requireCyclic = false;
                this.requireSubscription = true;
            }
            if (this.subscription.type === 'None') {
                this.requireCyclic = false;
                this.requireSubscription = false;
            }
        }
        this._model = _model;
        this.subscriptionTypeName = 'subscriptionType' + _model.id;
    }
    updateModel() {
        setTimeout(() => {
            unset(this.subscription, 'subscriptionParameters');
            unset(this.subscription, 'cyclicReadParameters');
            if (this.subscription.type === 'CyclicRead') {
                this.requireCyclic = true;
                this.requireSubscription = false;
                set(this.subscription, 'cyclicReadParameters', this.cyclicReadParameters);
            }
            else if (this.subscription.type === 'Subscription') {
                this.requireCyclic = false;
                this.requireSubscription = true;
                set(this.subscription, 'subscriptionParameters', this.subscriptionParameters);
            }
            else if (this.subscription.type === 'None') {
                this.requireCyclic = false;
                this.requireSubscription = false;
            }
            this.onSubscriptionChange.emit(this.subscription);
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDataReportingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolDataReportingComponent, isStandalone: true, selector: "opcua-device-protocol-data-reporting", inputs: { model: "model", groupName: "groupName" }, outputs: { onSubscriptionChange: "onSubscriptionChange" }, ngImport: i0, template: "<c8y-form-group>\n  <label translate>Mechanism</label>\n  <label\n    title=\"{{ mechanism.label | translate }}\"\n    class=\"c8y-radio radio-inline\"\n    *ngFor=\"let mechanism of types\"\n  >\n    <input\n      type=\"radio\"\n      name=\"{{subscriptionTypeName}}\"\n      [value]=\"mechanism.value\"\n      [(ngModel)]=\"subscription.type\"\n      (change)=\"updateModel()\"\n      required\n      [attr.data-cy]=\"mechanism.value\"\n    />\n    <span></span>\n    <span>{{ mechanism.label | translate }}</span>\n  </label>\n</c8y-form-group>\n\n<div class=\"row collapse\" [collapse]=\"subscription.type != 'CyclicRead'\" [isAnimated]=\"true\">\n  <div class=\"col-sm-6 col-md-4 col-lg-3\">\n    <c8y-form-group>\n      <label translate>Reading interval</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"rate\"\n          [(ngModel)]=\"cyclicReadParameters.rate\"\n          placeholder=\"{{ 'e.g.' | translate }} 50\"\n          [required]=\"requireCyclic\"\n          min=\"50\"\n          [attr.data-cy]=\"'cyclicReadRate'\"\n        />\n        <span class=\"input-group-addon units\" title=\"{{ 'Milliseconds' | translate }}\">\n          {{ 'msec' | translate }}\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n</div>\n\n<div class=\"row collapse\" [collapse]=\"subscription.type != 'Subscription'\" [isAnimated]=\"true\">\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Sampling interval</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"samplingRate\"\n          [(ngModel)]=\"subscriptionParameters.samplingRate\"\n          placeholder=\"{{ 'e.g.' | translate }} 500\"\n          [required]=\"requireSubscription\"\n          min=\"0\"\n          [attr.data-cy]=\"'subscriptionSamplingRate'\"\n        />\n        <span class=\"input-group-addon units\" title=\"{{ 'Milliseconds' | translate }}\" translate>\n          msec\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Queue size</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"queueSize\"\n          [(ngModel)]=\"subscriptionParameters.queueSize\"\n          placeholder=\"{{ 'e.g.' | translate }} 10\"\n          min=\"1\"\n          [attr.data-cy]=\"'subscriptionQueueSize'\"\n        />\n        <span class=\"input-group-addon\">\n          <strong translate>Discard</strong>&nbsp;\n          <label\n            *ngFor=\"let discardOption of discard\"\n            title=\"{{ discardOption.label | translate }}\"\n            class=\"c8y-radio radio-inline\"\n          >\n            <input\n              type=\"radio\"\n              name=\"discard{{ _model.id }}\"\n              [value]=\"discardOption.value\"\n              [(ngModel)]=\"subscriptionParameters.discardOldest\"\n              [required]=\"requireSubscription\"\n              [attr.data-cy]=\"discardOption.label\"\n              [attr.data-name]=\"'discard' + _model.id\"\n            />\n            <span></span>\n            <span>{{ discardOption.label | translate }}</span>\n          </label>\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n  <div class=\"clearfix\"></div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Data change trigger</label>\n      <label\n        *ngFor=\"let trigger of triggers\"\n        title=\"{{ trigger.label | translate }}\"\n        class=\"c8y-radio radio-inline\"\n      >\n        <input\n          type=\"radio\"\n          name=\"dataChangeTrigger{{ _model.id }}\"\n          [value]=\"trigger.value\"\n          [(ngModel)]=\"subscriptionParameters.dataChangeTrigger\"\n          [required]=\"requireSubscription\"\n          [attr.data-cy]=\"trigger.label\"\n          [attr.data-name]=\"'dataChangeTrigger' + _model.id\"\n        />\n        <span></span>\n        <span>{{ trigger.label | translate }}</span>\n      </label>\n    </c8y-form-group>\n  </div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Deadband filter</label>\n      <label\n        *ngFor=\"let deadbandFilter of filters\"\n        title=\"{{ deadbandFilter.label | translate }}\"\n        class=\"c8y-radio radio-inline\"\n      >\n        <input\n          type=\"radio\"\n          name=\"deadbandType{{ _model.id }}\"\n          [value]=\"deadbandFilter.value\"\n          [(ngModel)]=\"subscriptionParameters.deadbandType\"\n          [required]=\"requireSubscription\"\n          [attr.data-cy]=\"deadbandFilter.label\"\n          [attr.data-name]=\"'deadbandType' + _model.id\"\n        />\n        <span></span>\n        <span>{{ deadbandFilter.label | translate }}</span>\n      </label>\n    </c8y-form-group>\n    <div [collapse]=\"subscriptionParameters.deadbandType == 'None'\" [isAnimated]=\"true\">\n      <c8y-form-group>\n        <label translate>Deadband value</label>\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"deadbandValue\"\n          [(ngModel)]=\"subscriptionParameters.deadbandValue\"\n          placeholder=\"{{ 'e.g.' | translate }} 10\"\n          [required]=\"subscriptionParameters.deadbandType != 'None'\"\n          min=\"0\"\n          [attr.data-cy]=\"'deadbandValue'\"\n        />\n      </c8y-form-group>\n    </div>\n  </div>\n</div>\n", dependencies: [{ kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "directive", type: MinValidationDirective, selector: "[min]", inputs: ["min"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDataReportingComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-device-protocol-data-reporting', viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }], imports: [
                        FormGroupComponent,
                        C8yTranslateDirective,
                        NgFor,
                        FormsModule,
                        RequiredInputPlaceholderDirective,
                        CollapseDirective,
                        MinValidationDirective,
                        C8yTranslatePipe
                    ], template: "<c8y-form-group>\n  <label translate>Mechanism</label>\n  <label\n    title=\"{{ mechanism.label | translate }}\"\n    class=\"c8y-radio radio-inline\"\n    *ngFor=\"let mechanism of types\"\n  >\n    <input\n      type=\"radio\"\n      name=\"{{subscriptionTypeName}}\"\n      [value]=\"mechanism.value\"\n      [(ngModel)]=\"subscription.type\"\n      (change)=\"updateModel()\"\n      required\n      [attr.data-cy]=\"mechanism.value\"\n    />\n    <span></span>\n    <span>{{ mechanism.label | translate }}</span>\n  </label>\n</c8y-form-group>\n\n<div class=\"row collapse\" [collapse]=\"subscription.type != 'CyclicRead'\" [isAnimated]=\"true\">\n  <div class=\"col-sm-6 col-md-4 col-lg-3\">\n    <c8y-form-group>\n      <label translate>Reading interval</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"rate\"\n          [(ngModel)]=\"cyclicReadParameters.rate\"\n          placeholder=\"{{ 'e.g.' | translate }} 50\"\n          [required]=\"requireCyclic\"\n          min=\"50\"\n          [attr.data-cy]=\"'cyclicReadRate'\"\n        />\n        <span class=\"input-group-addon units\" title=\"{{ 'Milliseconds' | translate }}\">\n          {{ 'msec' | translate }}\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n</div>\n\n<div class=\"row collapse\" [collapse]=\"subscription.type != 'Subscription'\" [isAnimated]=\"true\">\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Sampling interval</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"samplingRate\"\n          [(ngModel)]=\"subscriptionParameters.samplingRate\"\n          placeholder=\"{{ 'e.g.' | translate }} 500\"\n          [required]=\"requireSubscription\"\n          min=\"0\"\n          [attr.data-cy]=\"'subscriptionSamplingRate'\"\n        />\n        <span class=\"input-group-addon units\" title=\"{{ 'Milliseconds' | translate }}\" translate>\n          msec\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Queue size</label>\n      <div class=\"input-group\">\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"queueSize\"\n          [(ngModel)]=\"subscriptionParameters.queueSize\"\n          placeholder=\"{{ 'e.g.' | translate }} 10\"\n          min=\"1\"\n          [attr.data-cy]=\"'subscriptionQueueSize'\"\n        />\n        <span class=\"input-group-addon\">\n          <strong translate>Discard</strong>&nbsp;\n          <label\n            *ngFor=\"let discardOption of discard\"\n            title=\"{{ discardOption.label | translate }}\"\n            class=\"c8y-radio radio-inline\"\n          >\n            <input\n              type=\"radio\"\n              name=\"discard{{ _model.id }}\"\n              [value]=\"discardOption.value\"\n              [(ngModel)]=\"subscriptionParameters.discardOldest\"\n              [required]=\"requireSubscription\"\n              [attr.data-cy]=\"discardOption.label\"\n              [attr.data-name]=\"'discard' + _model.id\"\n            />\n            <span></span>\n            <span>{{ discardOption.label | translate }}</span>\n          </label>\n        </span>\n      </div>\n    </c8y-form-group>\n  </div>\n  <div class=\"clearfix\"></div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Data change trigger</label>\n      <label\n        *ngFor=\"let trigger of triggers\"\n        title=\"{{ trigger.label | translate }}\"\n        class=\"c8y-radio radio-inline\"\n      >\n        <input\n          type=\"radio\"\n          name=\"dataChangeTrigger{{ _model.id }}\"\n          [value]=\"trigger.value\"\n          [(ngModel)]=\"subscriptionParameters.dataChangeTrigger\"\n          [required]=\"requireSubscription\"\n          [attr.data-cy]=\"trigger.label\"\n          [attr.data-name]=\"'dataChangeTrigger' + _model.id\"\n        />\n        <span></span>\n        <span>{{ trigger.label | translate }}</span>\n      </label>\n    </c8y-form-group>\n  </div>\n  <div class=\"col-sm-6 col-lg-4\">\n    <c8y-form-group>\n      <label translate>Deadband filter</label>\n      <label\n        *ngFor=\"let deadbandFilter of filters\"\n        title=\"{{ deadbandFilter.label | translate }}\"\n        class=\"c8y-radio radio-inline\"\n      >\n        <input\n          type=\"radio\"\n          name=\"deadbandType{{ _model.id }}\"\n          [value]=\"deadbandFilter.value\"\n          [(ngModel)]=\"subscriptionParameters.deadbandType\"\n          [required]=\"requireSubscription\"\n          [attr.data-cy]=\"deadbandFilter.label\"\n          [attr.data-name]=\"'deadbandType' + _model.id\"\n        />\n        <span></span>\n        <span>{{ deadbandFilter.label | translate }}</span>\n      </label>\n    </c8y-form-group>\n    <div [collapse]=\"subscriptionParameters.deadbandType == 'None'\" [isAnimated]=\"true\">\n      <c8y-form-group>\n        <label translate>Deadband value</label>\n        <input\n          class=\"form-control\"\n          type=\"number\"\n          name=\"deadbandValue\"\n          [(ngModel)]=\"subscriptionParameters.deadbandValue\"\n          placeholder=\"{{ 'e.g.' | translate }} 10\"\n          [required]=\"subscriptionParameters.deadbandType != 'None'\"\n          min=\"0\"\n          [attr.data-cy]=\"'deadbandValue'\"\n        />\n      </c8y-form-group>\n    </div>\n  </div>\n</div>\n" }]
        }], propDecorators: { model: [{
                type: Input
            }], groupName: [{
                type: Input
            }], onSubscriptionChange: [{
                type: Output
            }] } });

class OpcuaDeviceProtocolDescription {
    constructor() {
        this.moId = '';
    }
    set model(_model) {
        this.moId = _model.referencedServerId;
        this._model = _model;
        this.autoScan = _model.enabled ? '1' : '0';
    }
    setAutoScanOption(data) {
        this._model.enabled = data !== '0' ? true : false;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDescription, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolDescription, isStandalone: true, selector: "opcua-device-protocol-description", inputs: { model: "model" }, ngImport: i0, template: "<div class=\"card-block bg-level-1 flex-no-shrink p-t-24 p-b-24\">\n  <div class=\"content-flex-70\">\n    <div class=\"text-center\">\n      <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-device-protocols\"></i>\n      <p>\n        <small class=\"label label-info\">{{ _model.fieldbusType }}</small>\n      </p>\n    </div>\n    <div class=\"flex-grow col-10\">\n      <div class=\"content-flex-80\">\n        <div class=\"col-9\">\n          <div class=\"form-group form-group-lg m-b-0\">\n            <label class=\"sr-only\" translate>Name</label>\n            <label class=\"editable\" [ngClass]=\"{ updated: ctrlName.dirty }\">\n              <input\n                type=\"text\"\n                class=\"form-control\"\n                name=\"name\"\n                #ctrlName=\"ngModel\"\n                [(ngModel)]=\"_model.name\"\n                style=\"max-width:calc( {{ _model.name.length || 10 }} * 1ch + 14px)\"\n              />\n            </label>\n          </div>\n          <div class=\"form-group\">\n            <label class=\"sr-only\" translate>Description</label>\n            <label class=\"editable\" [ngClass]=\"{ updated: ctrlDescription.dirty }\">\n              <textarea\n                class=\"form-control\"\n                rows=\"1\"\n                name=\"description\"\n                placeholder=\"{{ 'e.g. My protocol description' | translate }}\"\n                #ctrlDescription=\"ngModel\"\n                [(ngModel)]=\"_model.description\"\n                style=\"max-width:calc( {{ _model.description?.length || 25 }} * 1ch + 14px)\"\n              ></textarea>\n              <span *ngIf=\"_model.description\">\n                {{ _model.description }}\n              </span>\n            </label>\n          </div>\n          <div class=\"d-flex\">\n            <div>\n              <button\n                type=\"button\"\n                class=\"btn\"\n                name=\"autoScanAddressSpace\"\n                [(ngModel)]=\"autoScan\"\n                (ngModelChange)=\"setAutoScanOption($event)\"\n                btnCheckbox\n                btnCheckboxTrue=\"1\"\n                btnCheckboxFalse=\"0\"\n                ngDefaultControl\n              >\n                <i *ngIf=\"autoScan === '1'\" c8yIcon=\"check\" class=\"text-success\"></i>\n                <span *ngIf=\"autoScan === '1'\">\n                  {{ 'Active`auto scanning`' | translate }}\n                </span>\n\n                <i *ngIf=\"autoScan === '0'\" c8yIcon=\"ban\" class=\"text-danger\"></i>\n                <span *ngIf=\"autoScan === '0'\">\n                  {{ 'Inactive`auto scanning`' | translate }}\n                </span>\n              </button>\n            </div>\n            <small class=\"m-l-16 text-muted\">\n              {{\n                'When active, the gateway scans the address space of all servers and automatically applies this device protocol to all nodes matching the criteria.'\n                  | translate\n              }}\n            </small>\n          </div>\n        </div>\n        <div class=\"flex-grow\">\n          <ul class=\"list-unstyled small\">\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>ID</label>\n              <span class=\"m-l-auto\">{{ _model.id }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Date created</label>\n              <span class=\"m-l-auto\">{{ _model.creationTime | c8yDate }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Last update</label>\n              <span class=\"m-l-auto\">{{ _model.lastUpdated | c8yDate }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Fieldbus version</label>\n              <span class=\"m-l-auto\">{{ _model.fieldbusVersion }}</span>\n            </li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ButtonCheckboxDirective, selector: "[btnCheckbox]", inputs: ["btnCheckboxTrue", "btnCheckboxFalse"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDescription, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-device-protocol-description', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], imports: [
                        C8yTranslateDirective,
                        NgClass,
                        FormsModule,
                        NgIf,
                        ButtonCheckboxDirective,
                        IconDirective,
                        C8yTranslatePipe,
                        DatePipe
                    ], template: "<div class=\"card-block bg-level-1 flex-no-shrink p-t-24 p-b-24\">\n  <div class=\"content-flex-70\">\n    <div class=\"text-center\">\n      <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-device-protocols\"></i>\n      <p>\n        <small class=\"label label-info\">{{ _model.fieldbusType }}</small>\n      </p>\n    </div>\n    <div class=\"flex-grow col-10\">\n      <div class=\"content-flex-80\">\n        <div class=\"col-9\">\n          <div class=\"form-group form-group-lg m-b-0\">\n            <label class=\"sr-only\" translate>Name</label>\n            <label class=\"editable\" [ngClass]=\"{ updated: ctrlName.dirty }\">\n              <input\n                type=\"text\"\n                class=\"form-control\"\n                name=\"name\"\n                #ctrlName=\"ngModel\"\n                [(ngModel)]=\"_model.name\"\n                style=\"max-width:calc( {{ _model.name.length || 10 }} * 1ch + 14px)\"\n              />\n            </label>\n          </div>\n          <div class=\"form-group\">\n            <label class=\"sr-only\" translate>Description</label>\n            <label class=\"editable\" [ngClass]=\"{ updated: ctrlDescription.dirty }\">\n              <textarea\n                class=\"form-control\"\n                rows=\"1\"\n                name=\"description\"\n                placeholder=\"{{ 'e.g. My protocol description' | translate }}\"\n                #ctrlDescription=\"ngModel\"\n                [(ngModel)]=\"_model.description\"\n                style=\"max-width:calc( {{ _model.description?.length || 25 }} * 1ch + 14px)\"\n              ></textarea>\n              <span *ngIf=\"_model.description\">\n                {{ _model.description }}\n              </span>\n            </label>\n          </div>\n          <div class=\"d-flex\">\n            <div>\n              <button\n                type=\"button\"\n                class=\"btn\"\n                name=\"autoScanAddressSpace\"\n                [(ngModel)]=\"autoScan\"\n                (ngModelChange)=\"setAutoScanOption($event)\"\n                btnCheckbox\n                btnCheckboxTrue=\"1\"\n                btnCheckboxFalse=\"0\"\n                ngDefaultControl\n              >\n                <i *ngIf=\"autoScan === '1'\" c8yIcon=\"check\" class=\"text-success\"></i>\n                <span *ngIf=\"autoScan === '1'\">\n                  {{ 'Active`auto scanning`' | translate }}\n                </span>\n\n                <i *ngIf=\"autoScan === '0'\" c8yIcon=\"ban\" class=\"text-danger\"></i>\n                <span *ngIf=\"autoScan === '0'\">\n                  {{ 'Inactive`auto scanning`' | translate }}\n                </span>\n              </button>\n            </div>\n            <small class=\"m-l-16 text-muted\">\n              {{\n                'When active, the gateway scans the address space of all servers and automatically applies this device protocol to all nodes matching the criteria.'\n                  | translate\n              }}\n            </small>\n          </div>\n        </div>\n        <div class=\"flex-grow\">\n          <ul class=\"list-unstyled small\">\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>ID</label>\n              <span class=\"m-l-auto\">{{ _model.id }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Date created</label>\n              <span class=\"m-l-auto\">{{ _model.creationTime | c8yDate }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Last update</label>\n              <span class=\"m-l-auto\">{{ _model.lastUpdated | c8yDate }}</span>\n            </li>\n            <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n              <label class=\"small m-b-0 m-r-8\" translate>Fieldbus version</label>\n              <span class=\"m-l-auto\">{{ _model.fieldbusVersion }}</span>\n            </li>\n          </ul>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n" }]
        }], propDecorators: { model: [{
                type: Input
            }] } });

class OpcuaCustomActionObjectMapping extends BaseObjectMapping {
    constructor() {
        super({
            icon: 'bell',
            label: gettext('Custom action'),
            formlyFieldConfig: {
                key: 'customAction',
                fieldGroup: [
                    {
                        type: 'array',
                        key: 'headers',
                        props: {
                            label: gettext('headers'),
                            addText: gettext('Add Header'),
                            required: true
                        },
                        className: 'formly-group-array-cols d-block min-height-fit',
                        fieldArray: {
                            fieldGroup: [
                                {
                                    key: 'key',
                                    type: 'string',
                                    focus: true,
                                    props: {
                                        placeholder: 'Authorization',
                                        label: gettext('Key'),
                                        required: true,
                                        smallFormGroup: true
                                    },
                                    wrappers: ['c8y-form-field']
                                },
                                {
                                    key: 'value',
                                    type: 'string',
                                    props: {
                                        placeholder: 'Basic <credentials>',
                                        label: gettext('Value'),
                                        required: true,
                                        smallFormGroup: true
                                    }
                                }
                            ]
                        }
                    },
                    {
                        className: 'row',
                        wrappers: ['c8y-legend-wrapper'],
                        props: {
                            label: gettext('Action')
                        },
                        fieldGroup: [
                            {
                                type: 'string',
                                key: 'endpoint',
                                props: {
                                    label: gettext('Endpoint'),
                                    smallFormGroup: true,
                                    required: true
                                },
                                className: 'col-md-6 p-0'
                            },
                            {
                                type: 'textarea',
                                key: 'bodyTemplate',
                                props: {
                                    label: gettext('Body template'),
                                    smallFormGroup: true,
                                    required: true,
                                    description: gettext('The following placeholders are available: ${value}`KEEP_ORIGINAL`, ${serverId}`KEEP_ORIGINAL`, ${nodeId}`KEEP_ORIGINAL`, ${deviceId}`KEEP_ORIGINAL`.')
                                },
                                className: 'col-md-6'
                            }
                        ]
                    }
                ]
            }
        });
    }
}

class OpcuaMeasurementObjectMapping extends MeasurementObjectMapping {
    constructor(smallFormGroup = true) {
        super(null, 'measurementCreation', smallFormGroup);
        this.smallFormGroup = smallFormGroup;
    }
}
class OpcuaEventObjectMapping extends EventObjectMapping {
    constructor(smallFormGroup = true) {
        super(null, 'eventCreation', smallFormGroup, undefined, [
            {
                key: 'type',
                type: 'string',
                props: {
                    label: gettext('Type'),
                    required: true,
                    smallFormGroup
                },
                className: 'col-md-3 col-sm-6'
            },
            {
                key: 'text',
                type: 'string',
                props: {
                    label: gettext('Text'),
                    required: true,
                    smallFormGroup
                },
                className: 'col-md-3 col-sm-6'
            }
        ]);
        this.smallFormGroup = smallFormGroup;
    }
}
class OpcuaAlarmObjectMapping extends AlarmObjectMapping {
    constructor(smallFormGroup = true) {
        super(null, 'alarmCreation', smallFormGroup, undefined, [
            {
                key: 'severity',
                type: 'select',
                props: {
                    label: gettext('Severity'),
                    options: [...Object.values(ALARM_SEVERITY).map(value => ({ label: value, value }))],
                    required: true,
                    smallFormGroup
                },
                className: 'col-md-3 col-sm-6'
            },
            {
                key: 'type',
                type: 'string',
                props: {
                    label: gettext('Type'),
                    smallFormGroup,
                    required: true
                },
                className: 'col-md-3 col-sm-6'
            },
            {
                key: 'text',
                type: 'string',
                props: {
                    label: gettext('Text'),
                    smallFormGroup,
                    required: true
                },
                className: 'col-md-3 col-sm-6'
            }
        ]);
        this.smallFormGroup = smallFormGroup;
    }
}

class OpcuaDeviceProtocolObjectMappingStatus extends UpgradeComponent {
    constructor(elementRef, injector) {
        super('c8yObjectMappingStatusIcons', elementRef, injector);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolObjectMappingStatus, deps: [{ token: i0.ElementRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolObjectMappingStatus, isStandalone: true, selector: "c8y-object-mapping-status-icons", inputs: { mapping: "mapping" }, usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolObjectMappingStatus, decorators: [{
            type: Directive,
            args: [{ selector: 'c8y-object-mapping-status-icons' }]
        }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Injector }], propDecorators: { mapping: [{
                type: Input
            }] } });

class OpcuaDeviceProtocolMapping {
    constructor(addressSpaceService) {
        this.addressSpaceService = addressSpaceService;
        this.onAction = new EventEmitter();
        this.isPathFocused = false;
        this.isBrowsePathUniq = true;
        this.dataReporting = 'default';
        this.isTreeOpen = false;
        this.isNew = false;
        this.resetModel = false;
        this.mappingTypes = [
            OpcuaMeasurementObjectMapping,
            OpcuaAlarmObjectMapping,
            OpcuaEventObjectMapping,
            OpcuaCustomActionObjectMapping
        ];
        this.objectMappingState = {
            valid: false,
            dirty: false
        };
        this.getMappings = () => this.getParentAttr('mappings');
    }
    toggleDetail() {
        this.isDetailOpen = !this.isDetailOpen;
        if (this.resetModel) {
            this.initialFormSetup();
        }
    }
    ngOnInit() {
        this.dataReportingName = 'ReportingMode' + this.index;
        this.initialFormSetup();
    }
    ngOnChanges(changes) {
        // this is done to keep the "onDelete" logic in
        // opcua-device-protocol-detail.component intact
        if (!isNil(get(changes, '_model.previousValue')) &&
            !isEqual(this._model, changes._model.previousValue)) {
            if (this.mapping && this.mapping.name === this._model.name) {
                this.mapping.id = this._model.id;
            }
        }
    }
    onMappingUpdate({ dirty, valid }) {
        this.objectMappingState = {
            valid,
            dirty
        };
    }
    initialFormSetup() {
        const mapping = {
            id: '',
            browsePath: [],
            name: '',
            subscriptionType: {
                type: 'None'
            }
        };
        this.mapping = assign({}, mapping, cloneDeep(this._model));
        if (isEmpty(this.mapping.browsePath)) {
            this.isNew = true;
            this.isDetailOpen = true;
        }
        else {
            this.browsePath = this.stringfyBrowsePath(this.mapping.browsePath);
            this.nodeDisplayName = this.mapping.name;
        }
        if (this.referencedRootNodeId) {
            this.referencedNode = { nodeId: this.referencedRootNodeId };
            this.addressSpaceService.triggerNodeToOpen({
                node: {
                    nodeId: this.referencedRootNodeId,
                    children: [],
                    expanded: false,
                    absolutePaths: [[]]
                },
                selectedAncestorIds: []
            });
        }
        else {
            this.referencedNode = { nodeId: '' };
        }
        if (this.mapping?.customAction) {
            Object.assign(this.mapping, {
                customAction: {
                    ...this.mapping.customAction,
                    headers: this.mapHeadersObjectToList(this.mapping?.customAction?.headers)
                }
            });
        }
        if (get(this._model, 'subscriptionType')) {
            this.dataReporting = 'custom';
        }
        else {
            this.dataReporting = 'default';
        }
        this.resetModel = false;
    }
    showAddressSpaceTree() {
        return !isEmpty(this.referencedServerId);
    }
    ngAfterViewInit() {
        if (get(this.mapping, 'subscriptionType') &&
            get(this.mapping, 'subscriptionType.type') !== 'None') {
            this.dataReporting = 'custom';
        }
    }
    mapHeadersObjectToList(headers) {
        if (Object.keys(headers).length > 0) {
            return Object.keys(headers).map(item => {
                return { key: item, value: headers[item] };
            });
        }
    }
    stringfyBrowsePath(path) {
        return JSON.stringify(path);
    }
    updateBrowsePath(node) {
        this.mapping.browsePath = node.relativePath;
        this.nodeDisplayName = node.displayName;
        this.mapping.name = this.nodeDisplayName;
        this.browsePath = this.stringfyBrowsePath(this.mapping.browsePath);
        this.browsePathModel.control.markAsDirty();
    }
    updateDisplayname() {
        this.mapping.name = this.nodeDisplayName;
    }
    updateBrowsePathInput() {
        if (this.browsePath) {
            try {
                this.mapping.browsePath = JSON.parse(this.browsePath);
            }
            catch (error) {
                return;
            }
        }
    }
    save() {
        if (this.dataReporting === 'default') {
            unset$1(this.mapping, 'subscriptionType');
        }
        if (get(this.mapping, 'measurementCreation')) {
            const { measurementCreation } = this.mapping;
            set$1(measurementCreation, 'fragmentName', get(measurementCreation, 'type'));
        }
        if (this.mapping.customAction) {
            this.mapping.customAction.headers = this.mapping.customAction.headers.reduce((result, item) => {
                result[item.key] = item.value;
                return result;
            }, {});
        }
        this.onAction.emit({
            action: 'save',
            data: this.mapping
        });
        this.isDetailOpen = false;
    }
    cancel() {
        this.isDetailOpen = false;
        this.resetModel = true;
        if (this.mapping.id === 'new') {
            this.onAction.emit({
                action: 'delete',
                data: assign({}, this.mapping)
            });
        }
    }
    onDelete() {
        this.onAction.emit({ action: 'delete', data: this.mapping });
    }
    canSave({ valid, dirty }) {
        const areValid = () => valid && this.objectMappingState.valid;
        const areDirty = () => dirty || this.objectMappingState.dirty;
        return areValid() && areDirty();
    }
    isActive() {
        return this.isDetailOpen;
    }
    setTreeFromRefNode() {
        if (this.referencedRootNodeId) {
            this.addressSpaceService.triggerNodeToOpen({
                node: {
                    nodeId: this.referencedRootNodeId,
                    children: [],
                    expanded: false,
                    absolutePaths: [[]]
                },
                selectedAncestorIds: []
            });
        }
    }
    updateSubscriptionType(value) {
        this.mapping.subscriptionType = value;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolMapping, deps: [{ token: AddressSpaceService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolMapping, isStandalone: true, selector: "opcua-device-protocol-mapping", inputs: { _model: ["resource", "_model"], index: "index", getParentAttr: "getParentAttr", referencedServerId: "referencedServerId", referencedRootNodeId: "referencedRootNodeId" }, outputs: { onAction: "onAction" }, viewQueries: [{ propertyName: "subFormRef", first: true, predicate: ["variableForm"], descendants: true }, { propertyName: "browsePathModel", first: true, predicate: ["browsePathModel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n  class=\"c8y-list__item\"\n  [ngClass]=\"{ expanded: isDetailOpen }\"\n  [attr.data-cy]=\"mapping.browsePath | json\"\n>\n  <div class=\"c8y-list__item__block\">\n    <div class=\"c8y-list__item__icon\">\n      <i c8yIcon=\"sliders\"></i>\n    </div>\n    <div class=\"c8y-list__item__body\">\n      <div class=\"content-flex-70\">\n        <div class=\"col-5\">\n          <p\n            class=\"text-truncate\"\n            title=\" {{ nodeDisplayName }} {{\n              mapping.browsePath.length > 0 ? (mapping.browsePath | json) : ''\n            }}\"\n            (click)=\"toggleDetail()\"\n          >\n            {{ nodeDisplayName }}\n            <small\n              class=\"text-muted\"\n              *ngIf=\"mapping.browsePath.length > 0\"\n            >\n              {{ mapping.browsePath | json }}\n            </small>\n          </p>\n        </div>\n        <div class=\"col-5\">\n          <div class=\"list-functionalities\">\n            <label class=\"small m-r-8 m-b-0 hidden-xs\">\n              {{ 'Functionalities' | translate }}\n            </label>\n            <c8y-object-mapping-status-icons [mapping]=\"mapping\"></c8y-object-mapping-status-icons>\n          </div>\n        </div>\n        <div class=\"flex-grow d-flex p-r-8\">\n          <button\n            class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n            [attr.aria-label]=\"'Remove' | translate\"\n            tooltip=\"{{ 'Remove' | translate }}\"\n            type=\"button\"\n            [delay]=\"500\"\n          >\n            <i\n              c8yIcon=\"minus-circle\"\n              (click)=\"onDelete()\"\n            ></i>\n          </button>\n        </div>\n      </div>\n    </div>\n    <div class=\"c8y-list__item__actions\">\n      <button\n        class=\"collapse-btn\"\n        title=\"{{ 'Expand' | translate }}\"\n        type=\"button\"\n        [ngClass]=\"{ active: isDetailOpen }\"\n        (click)=\"toggleDetail()\"\n        [attr.data-cy]=\"'toggleDetail'\"\n      >\n        <i c8yIcon=\"chevron-down\"></i>\n      </button>\n    </div>\n  </div>\n  <div\n    class=\"collapse\"\n    [collapse]=\"!isDetailOpen\"\n    [isAnimated]=\"true\"\n  >\n    <div class=\"c8y-list__item__collapse--container\">\n      <div\n        class=\"form\"\n        [ngModelGroup]=\"index\"\n        #variableForm=\"ngModelGroup\"\n        *ngIf=\"isDetailOpen\"\n      >\n        <div class=\"row p-t-8\">\n          <c8y-form-group\n            class=\"col-md-4\"\n            [status]=\"!isBrowsePathUniq ? 'error' : ''\"\n            *ngIf=\"showAddressSpaceTree(); else simpleInput\"\n          >\n            <label>{{ 'Path' | translate }}</label>\n            <div\n              class=\"dropdown fit-w\"\n              dropdown\n              #dropdown=\"bs-dropdown\"\n              [insideClick]=\"true\"\n            >\n              <div class=\"input-group\">\n                <input\n                  class=\"form-control\"\n                  placeholder=\"{{ 'e.g.' | translate }} {{ ['2:Node1', '2:SubNode1'] | json }}\"\n                  name=\"browsePath\"\n                  type=\"text\"\n                  autocomplete=\"off\"\n                  required\n                  c8yBrowsePathValidator\n                  [getMappings]=\"getMappings\"\n                  [model]=\"mapping\"\n                  [(ngModel)]=\"browsePath\"\n                  (change)=\"updateBrowsePathInput()\"\n                  (focus)=\"setTreeFromRefNode()\"\n                  #browsePathModel=\"ngModel\"\n                />\n                <span class=\"input-group-btn\">\n                  <button\n                    class=\"btn btn-default\"\n                    title=\"{{ 'Toggle address space' | translate }}\"\n                    type=\"button\"\n                    dropdownToggle\n                  >\n                    <i [c8yIcon]=\"'caret-down'\"></i>\n                  </button>\n                </span>\n              </div>\n              <div\n                class=\"dropdown-menu panel-inner-scroll fit-w\"\n                style=\"max-height: 240px\"\n                *dropdownMenu\n              >\n                <opcua-address-space-tree\n                  [node]=\"referencedNode\"\n                  [moId]=\"referencedServerId\"\n                  (selectedNode)=\"updateBrowsePath($event); dropdown.hide()\"\n                ></opcua-address-space-tree>\n              </div>\n            </div>\n            <c8y-messages>\n              <c8y-message\n                name=\"invalidBrowsePathNotation\"\n                text=\"{{ 'Must be a valid array of strings.' | translate }}\"\n              ></c8y-message>\n              <c8y-message\n                name=\"browsePathNotUnique\"\n                text=\"{{ 'Variable with this path is already added.' | translate }}\"\n              ></c8y-message>\n            </c8y-messages>\n          </c8y-form-group>\n\n          <ng-template #simpleInput>\n            <c8y-form-group class=\"col-md-4\">\n              <label>{{ 'Path' | translate }}</label>\n              <input\n                class=\"form-control\"\n                placeholder=\"{{ 'e.g.' | translate }} {{ ['2:Node1', '2:SubNode1'] | json }}\"\n                name=\"browsePath\"\n                type=\"text\"\n                autocomplete=\"off\"\n                required\n                c8yBrowsePathValidator\n                [getMappings]=\"getMappings\"\n                [model]=\"mapping\"\n                [(ngModel)]=\"browsePath\"\n                (change)=\"updateBrowsePathInput()\"\n                #browsePathModel=\"ngModel\"\n              />\n              <c8y-messages>\n                <c8y-message\n                  name=\"invalidBrowsePathNotation\"\n                  text=\"{{ 'Must be a valid array of strings.' | translate }}\"\n                ></c8y-message>\n                <c8y-message\n                  name=\"browsePathNotUnique\"\n                  text=\"{{ 'Variable with this path is already added.' | translate }}\"\n                ></c8y-message>\n              </c8y-messages>\n            </c8y-form-group>\n          </ng-template>\n\n          <c8y-form-group class=\"col-md-4\">\n            <label>{{ 'Name' | translate }}</label>\n            <div class=\"input-group\">\n              <input\n                class=\"form-control\"\n                placeholder=\"{{ 'e.g. childDevice2' | translate }} \"\n                name=\"displayName\"\n                type=\"text\"\n                autocomplete=\"off\"\n                required\n                [(ngModel)]=\"nodeDisplayName\"\n                (change)=\"updateDisplayname()\"\n              />\n            </div>\n          </c8y-form-group>\n        </div>\n        <div\n          class=\"row\"\n          ngModelGroup=\"dataReportingSection\"\n        >\n          <c8y-form-group class=\"col-sm-4 col-md-3 col-lg-2\">\n            <label>\n              <span>{{ 'Data reporting' | translate }}</span>\n            </label>\n            <div class=\"input-group\">\n              <label\n                class=\"c8y-radio radio-inline\"\n                title=\"{{ 'Default' | translate }}\"\n              >\n                <input\n                  name=\"{{ dataReportingName }}\"\n                  type=\"radio\"\n                  value=\"default\"\n                  [(ngModel)]=\"dataReporting\"\n                />\n                <span></span>\n                <span>{{ 'Default' | translate }}</span>\n              </label>\n              <label\n                class=\"c8y-radio radio-inline\"\n                title=\"{{ 'Custom' | translate }}\"\n              >\n                <input\n                  name=\"{{ dataReportingName }}\"\n                  type=\"radio\"\n                  value=\"custom\"\n                  [(ngModel)]=\"dataReporting\"\n                />\n                <span></span>\n                <span>{{ 'Custom' | translate }}</span>\n              </label>\n            </div>\n          </c8y-form-group>\n          <div\n            class=\"col-sm-8 col-md-9 col-lg-10\"\n            *ngIf=\"dataReporting === 'custom'\"\n            ngModelGroup=\"overriddenSubscription\"\n          >\n            <opcua-device-protocol-data-reporting\n              [model]=\"mapping\"\n              (onSubscriptionChange)=\"updateSubscriptionType($event)\"\n            ></opcua-device-protocol-data-reporting>\n          </div>\n        </div>\n\n        <c8y-device-protocol-object-mappings\n          [data]=\"mapping\"\n          [objectMappingTypes]=\"mappingTypes\"\n          (onUpdate)=\"onMappingUpdate($event)\">\n        </c8y-device-protocol-object-mappings>\n\n        <button\n          class=\"btn btn-default m-t-16 m-b-16\"\n          title=\"{{ 'Cancel' | translate }}\"\n          id=\"cancelBtn\"\n          type=\"button\"\n          (click)=\"cancel()\"\n        >\n          {{ 'Cancel' | translate }}\n        </button>\n        <button\n          class=\"btn btn-primary m-t-16 m-b-16\"\n          title=\"{{ 'Save' | translate }}\"\n          id=\"saveBtn\"\n          type=\"button\"\n          (click)=\"save()\"\n          [disabled]=\"!canSave(variableForm)\"\n        >\n          {{ 'Save' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: OpcuaDeviceProtocolObjectMappingStatus, selector: "c8y-object-mapping-status-icons", inputs: ["mapping"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2$2.NgModelGroup, selector: "[ngModelGroup]", inputs: ["ngModelGroup"], exportAs: ["ngModelGroup"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: OpcuaDeviceProtocolBrowsePathValidation, selector: "[c8yBrowsePathValidator][ngModel]", inputs: ["getMappings", "model"] }, { kind: "directive", type: BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "component", type: OpcuaAddressSpaceTreeComponent, selector: "opcua-address-space-tree", inputs: ["moId", "node", "focusEmitter"], outputs: ["selectedNode"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: OpcuaDeviceProtocolDataReportingComponent, selector: "opcua-device-protocol-data-reporting", inputs: ["model", "groupName"], outputs: ["onSubscriptionChange"] }, { kind: "component", type: ObjectMappingComponent, selector: "c8y-device-protocol-object-mappings", inputs: ["data", "objectMappingTypes"], outputs: ["onUpdate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: JsonPipe, name: "json" }], viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolMapping, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-device-protocol-mapping', viewProviders: [{ provide: ControlContainer, useExisting: NgModelGroup }], imports: [
                        NgClass,
                        IconDirective,
                        NgIf,
                        OpcuaDeviceProtocolObjectMappingStatus,
                        TooltipDirective,
                        CollapseDirective,
                        FormsModule,
                        FormGroupComponent,
                        BsDropdownDirective,
                        RequiredInputPlaceholderDirective,
                        OpcuaDeviceProtocolBrowsePathValidation,
                        BsDropdownToggleDirective,
                        BsDropdownMenuDirective,
                        OpcuaAddressSpaceTreeComponent,
                        MessagesComponent,
                        MessageDirective,
                        OpcuaDeviceProtocolDataReportingComponent,
                        ObjectMappingComponent,
                        C8yTranslatePipe,
                        JsonPipe
                    ], template: "<div\n  class=\"c8y-list__item\"\n  [ngClass]=\"{ expanded: isDetailOpen }\"\n  [attr.data-cy]=\"mapping.browsePath | json\"\n>\n  <div class=\"c8y-list__item__block\">\n    <div class=\"c8y-list__item__icon\">\n      <i c8yIcon=\"sliders\"></i>\n    </div>\n    <div class=\"c8y-list__item__body\">\n      <div class=\"content-flex-70\">\n        <div class=\"col-5\">\n          <p\n            class=\"text-truncate\"\n            title=\" {{ nodeDisplayName }} {{\n              mapping.browsePath.length > 0 ? (mapping.browsePath | json) : ''\n            }}\"\n            (click)=\"toggleDetail()\"\n          >\n            {{ nodeDisplayName }}\n            <small\n              class=\"text-muted\"\n              *ngIf=\"mapping.browsePath.length > 0\"\n            >\n              {{ mapping.browsePath | json }}\n            </small>\n          </p>\n        </div>\n        <div class=\"col-5\">\n          <div class=\"list-functionalities\">\n            <label class=\"small m-r-8 m-b-0 hidden-xs\">\n              {{ 'Functionalities' | translate }}\n            </label>\n            <c8y-object-mapping-status-icons [mapping]=\"mapping\"></c8y-object-mapping-status-icons>\n          </div>\n        </div>\n        <div class=\"flex-grow d-flex p-r-8\">\n          <button\n            class=\"btn btn-dot btn-dot--danger showOnHover m-l-auto\"\n            [attr.aria-label]=\"'Remove' | translate\"\n            tooltip=\"{{ 'Remove' | translate }}\"\n            type=\"button\"\n            [delay]=\"500\"\n          >\n            <i\n              c8yIcon=\"minus-circle\"\n              (click)=\"onDelete()\"\n            ></i>\n          </button>\n        </div>\n      </div>\n    </div>\n    <div class=\"c8y-list__item__actions\">\n      <button\n        class=\"collapse-btn\"\n        title=\"{{ 'Expand' | translate }}\"\n        type=\"button\"\n        [ngClass]=\"{ active: isDetailOpen }\"\n        (click)=\"toggleDetail()\"\n        [attr.data-cy]=\"'toggleDetail'\"\n      >\n        <i c8yIcon=\"chevron-down\"></i>\n      </button>\n    </div>\n  </div>\n  <div\n    class=\"collapse\"\n    [collapse]=\"!isDetailOpen\"\n    [isAnimated]=\"true\"\n  >\n    <div class=\"c8y-list__item__collapse--container\">\n      <div\n        class=\"form\"\n        [ngModelGroup]=\"index\"\n        #variableForm=\"ngModelGroup\"\n        *ngIf=\"isDetailOpen\"\n      >\n        <div class=\"row p-t-8\">\n          <c8y-form-group\n            class=\"col-md-4\"\n            [status]=\"!isBrowsePathUniq ? 'error' : ''\"\n            *ngIf=\"showAddressSpaceTree(); else simpleInput\"\n          >\n            <label>{{ 'Path' | translate }}</label>\n            <div\n              class=\"dropdown fit-w\"\n              dropdown\n              #dropdown=\"bs-dropdown\"\n              [insideClick]=\"true\"\n            >\n              <div class=\"input-group\">\n                <input\n                  class=\"form-control\"\n                  placeholder=\"{{ 'e.g.' | translate }} {{ ['2:Node1', '2:SubNode1'] | json }}\"\n                  name=\"browsePath\"\n                  type=\"text\"\n                  autocomplete=\"off\"\n                  required\n                  c8yBrowsePathValidator\n                  [getMappings]=\"getMappings\"\n                  [model]=\"mapping\"\n                  [(ngModel)]=\"browsePath\"\n                  (change)=\"updateBrowsePathInput()\"\n                  (focus)=\"setTreeFromRefNode()\"\n                  #browsePathModel=\"ngModel\"\n                />\n                <span class=\"input-group-btn\">\n                  <button\n                    class=\"btn btn-default\"\n                    title=\"{{ 'Toggle address space' | translate }}\"\n                    type=\"button\"\n                    dropdownToggle\n                  >\n                    <i [c8yIcon]=\"'caret-down'\"></i>\n                  </button>\n                </span>\n              </div>\n              <div\n                class=\"dropdown-menu panel-inner-scroll fit-w\"\n                style=\"max-height: 240px\"\n                *dropdownMenu\n              >\n                <opcua-address-space-tree\n                  [node]=\"referencedNode\"\n                  [moId]=\"referencedServerId\"\n                  (selectedNode)=\"updateBrowsePath($event); dropdown.hide()\"\n                ></opcua-address-space-tree>\n              </div>\n            </div>\n            <c8y-messages>\n              <c8y-message\n                name=\"invalidBrowsePathNotation\"\n                text=\"{{ 'Must be a valid array of strings.' | translate }}\"\n              ></c8y-message>\n              <c8y-message\n                name=\"browsePathNotUnique\"\n                text=\"{{ 'Variable with this path is already added.' | translate }}\"\n              ></c8y-message>\n            </c8y-messages>\n          </c8y-form-group>\n\n          <ng-template #simpleInput>\n            <c8y-form-group class=\"col-md-4\">\n              <label>{{ 'Path' | translate }}</label>\n              <input\n                class=\"form-control\"\n                placeholder=\"{{ 'e.g.' | translate }} {{ ['2:Node1', '2:SubNode1'] | json }}\"\n                name=\"browsePath\"\n                type=\"text\"\n                autocomplete=\"off\"\n                required\n                c8yBrowsePathValidator\n                [getMappings]=\"getMappings\"\n                [model]=\"mapping\"\n                [(ngModel)]=\"browsePath\"\n                (change)=\"updateBrowsePathInput()\"\n                #browsePathModel=\"ngModel\"\n              />\n              <c8y-messages>\n                <c8y-message\n                  name=\"invalidBrowsePathNotation\"\n                  text=\"{{ 'Must be a valid array of strings.' | translate }}\"\n                ></c8y-message>\n                <c8y-message\n                  name=\"browsePathNotUnique\"\n                  text=\"{{ 'Variable with this path is already added.' | translate }}\"\n                ></c8y-message>\n              </c8y-messages>\n            </c8y-form-group>\n          </ng-template>\n\n          <c8y-form-group class=\"col-md-4\">\n            <label>{{ 'Name' | translate }}</label>\n            <div class=\"input-group\">\n              <input\n                class=\"form-control\"\n                placeholder=\"{{ 'e.g. childDevice2' | translate }} \"\n                name=\"displayName\"\n                type=\"text\"\n                autocomplete=\"off\"\n                required\n                [(ngModel)]=\"nodeDisplayName\"\n                (change)=\"updateDisplayname()\"\n              />\n            </div>\n          </c8y-form-group>\n        </div>\n        <div\n          class=\"row\"\n          ngModelGroup=\"dataReportingSection\"\n        >\n          <c8y-form-group class=\"col-sm-4 col-md-3 col-lg-2\">\n            <label>\n              <span>{{ 'Data reporting' | translate }}</span>\n            </label>\n            <div class=\"input-group\">\n              <label\n                class=\"c8y-radio radio-inline\"\n                title=\"{{ 'Default' | translate }}\"\n              >\n                <input\n                  name=\"{{ dataReportingName }}\"\n                  type=\"radio\"\n                  value=\"default\"\n                  [(ngModel)]=\"dataReporting\"\n                />\n                <span></span>\n                <span>{{ 'Default' | translate }}</span>\n              </label>\n              <label\n                class=\"c8y-radio radio-inline\"\n                title=\"{{ 'Custom' | translate }}\"\n              >\n                <input\n                  name=\"{{ dataReportingName }}\"\n                  type=\"radio\"\n                  value=\"custom\"\n                  [(ngModel)]=\"dataReporting\"\n                />\n                <span></span>\n                <span>{{ 'Custom' | translate }}</span>\n              </label>\n            </div>\n          </c8y-form-group>\n          <div\n            class=\"col-sm-8 col-md-9 col-lg-10\"\n            *ngIf=\"dataReporting === 'custom'\"\n            ngModelGroup=\"overriddenSubscription\"\n          >\n            <opcua-device-protocol-data-reporting\n              [model]=\"mapping\"\n              (onSubscriptionChange)=\"updateSubscriptionType($event)\"\n            ></opcua-device-protocol-data-reporting>\n          </div>\n        </div>\n\n        <c8y-device-protocol-object-mappings\n          [data]=\"mapping\"\n          [objectMappingTypes]=\"mappingTypes\"\n          (onUpdate)=\"onMappingUpdate($event)\">\n        </c8y-device-protocol-object-mappings>\n\n        <button\n          class=\"btn btn-default m-t-16 m-b-16\"\n          title=\"{{ 'Cancel' | translate }}\"\n          id=\"cancelBtn\"\n          type=\"button\"\n          (click)=\"cancel()\"\n        >\n          {{ 'Cancel' | translate }}\n        </button>\n        <button\n          class=\"btn btn-primary m-t-16 m-b-16\"\n          title=\"{{ 'Save' | translate }}\"\n          id=\"saveBtn\"\n          type=\"button\"\n          (click)=\"save()\"\n          [disabled]=\"!canSave(variableForm)\"\n        >\n          {{ 'Save' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: AddressSpaceService }], propDecorators: { subFormRef: [{
                type: ViewChild,
                args: ['variableForm', { static: false }]
            }], browsePathModel: [{
                type: ViewChild,
                args: ['browsePathModel', { static: false }]
            }], _model: [{
                type: Input,
                args: ['resource']
            }], index: [{
                type: Input
            }], getParentAttr: [{
                type: Input
            }], referencedServerId: [{
                type: Input
            }], referencedRootNodeId: [{
                type: Input
            }], onAction: [{
                type: Output
            }] } });

class OpcuaDeviceProtocolDetailComponent {
    constructor(changeDetectorRef, opcuaService, alertService, router) {
        this.changeDetectorRef = changeDetectorRef;
        this.opcuaService = opcuaService;
        this.alertService = alertService;
        this.router = router;
        this.initialModel = {
            id: '',
            fieldbusType: 'opcuaV2',
            description: '',
            unit: '',
            fieldbusVersion: 4,
            name: '',
            referencedServerId: '',
            referencedRootNodeId: '',
            subscriptionType: {
                type: 'None'
            },
            mappings: [],
            overriddenSubscriptions: [],
            applyConstraints: {
                browsePathMatchesRegex: '',
                matchesNodeIds: [],
                serverObjectHasFragment: '',
                matchesServerIds: []
            },
            enabled: ''
        };
        this.isLoaded = true;
        this.getParentAttr = key => get(this.model, key);
    }
    ngAfterContentChecked() {
        this.changeDetectorRef.detectChanges();
    }
    getMapping() {
        return this.model.mappings;
    }
    getEmptyMappingObject() {
        const { mappings } = this.model;
        return {
            id: mappings.length > 0 ? Math.max(...mappings.map(m => m.id)) + 1 : 0,
            browsePath: []
        };
    }
    getOverriddenSubscriptionsByPath(browsePath) {
        if (isNil(browsePath) || browsePath.length === 0) {
            return undefined;
        }
        return find(this.model.overriddenSubscriptions, { browsePath });
    }
    getStructuredResource(resource) {
        const overriddenSubscriptions = this.getOverriddenSubscriptionsByPath(resource.browsePath);
        let result = assign({}, resource);
        if (overriddenSubscriptions) {
            result = assign({}, resource, { subscriptionType: overriddenSubscriptions.subscriptionType });
        }
        return result;
    }
    async ngOnInit() {
        const id = this.opcuaService.getId();
        if (id) {
            const res = await this.opcuaService.getDeviceProtocol(id);
            if (res && res.status !== 200) {
                const data = res.json ? await res.json() : undefined;
                this.alertService.addServerFailure({ data, res });
                this.isLoaded = false;
            }
            else {
                const data = await res.json();
                if (data && data.applyConstraints === null) {
                    delete data.applyConstraints;
                }
                if (data && data.subscriptionType === null) {
                    delete data.subscriptionType;
                }
                this.model = assign(this.initialModel, data);
                if (!this.model.mappings) {
                    this.model.mappings = [];
                }
                this.model = assign(this.initialModel, this.updateViableMapping(data));
                this.isLoaded = false;
            }
        }
    }
    updateViableMapping(model) {
        const { mappings } = model;
        let result = [];
        if (mappings) {
            result = mappings.map((item, i) => {
                return assign(this.getStructuredResource(item), { id: i });
            });
        }
        return assign(model, { mappings: result });
    }
    trackById(_index, el) {
        return get(el, 'id');
    }
    addVariable() {
        this.model.mappings.push(this.getEmptyMappingObject());
    }
    updateVariable(mappingObject) {
        const { mappings } = this.model;
        const { id } = mappingObject;
        const index = findIndex(mappings, { id });
        mappings[index > -1 ? index : 0] = mappingObject;
    }
    removeVariable(mappingObject) {
        const { mappings } = this.model;
        const { id } = mappingObject;
        let index = -1;
        // id typeof string || number
        if (!isNil(id) && (id.length > 0 || id > -1)) {
            index = findIndex(mappings, { id });
        }
        if (index > -1) {
            mappings.splice(index, 1);
        }
    }
    actionHandler(actionObject) {
        switch (actionObject.action) {
            case 'save':
                this.updateVariable(actionObject.data);
                break;
            case 'delete':
                this.removeVariable(actionObject.data);
                break;
        }
    }
    extractOverridSubscriptionType(_mapping) {
        const overriddenSubscriptions = [];
        const variableMapping = [];
        _mapping.forEach(element => {
            if (element.id !== 'new') {
                if (element.subscriptionType) {
                    overriddenSubscriptions.push(assign({ browsePath: element.browsePath }, { subscriptionType: element.subscriptionType }));
                }
                variableMapping.push(omit(element, ['subscriptionType']));
            }
        });
        return [variableMapping, overriddenSubscriptions];
    }
    prepareRequestJson(_model) {
        let requestJson = {};
        const [mappings, overriddenSubscriptions] = this.extractOverridSubscriptionType(_model.mappings);
        requestJson = assign(requestJson, pick(_model, Object.keys(this.initialModel)), {
            mappings,
            overriddenSubscriptions
        });
        return requestJson;
    }
    async save() {
        try {
            const res = await this.opcuaService.updateDeviceProtocol(this.prepareRequestJson(this.model));
            const data = await res.json();
            if (res && res.status === 200) {
                this.router.navigate(['deviceprotocols']);
                this.alertService.success(gettext('Device protocol saved.'));
            }
            else {
                const { details } = data;
                this.alertService.addServerFailure({ res, data: details });
            }
        }
        catch (ex) {
            this.alertService.danger(gettext('Failed to save. Try again.'));
        }
    }
    canSave(deviceTypeForm) {
        if (this.instanceList) {
            const activeInstances = this.instanceList.filter(item => item.isActive());
            if (activeInstances.length > 0) {
                return true;
            }
        }
        return !deviceTypeForm.form.valid;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: OpcuaService }, { token: i2$1.AlertService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaDeviceProtocolDetailComponent, isStandalone: true, selector: "opcua-device-protocol-detail", viewQueries: [{ propertyName: "instanceList", predicate: OpcuaDeviceProtocolMapping, descendants: true }], ngImport: i0, template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n  <c8y-breadcrumb-item\n    [icon]=\"'c8y-device-protocols'\"\n    [label]=\"'Device types' | translate\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    [icon]=\"'c8y-device-protocols'\"\n    [label]=\"'Device protocols' | translate\"\n    [path]=\"'deviceprotocols'\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n  <div class=\"col-lg-12 col-lg-max\">\n    <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n      <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n      <div class=\"inner-scroll\">\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n            <div class=\"h4\" translate>Variables</div>\n          </div>\n          <div class=\"p-l-16 p-r-16\">\n            <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n              <opcua-device-protocol-mapping\n                *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n                [index]=\"i\"\n                [referencedServerId]=\"model.referencedServerId\"\n                [referencedRootNodeId]=\"model.referencedRootNodeId\"\n                [resource]=\"getStructuredResource(resource)\"\n                [getParentAttr]=\"getParentAttr\"\n                (onAction)=\"actionHandler($event)\"\n              ></opcua-device-protocol-mapping>\n            </div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16\">\n            <c8y-ui-empty-state\n              *ngIf=\"model.mappings.length === 0\"\n              [icon]=\"'sliders'\"\n              [title]=\"'No variables to display.' | translate\"\n              [subtitle]=\"'Click below to add your first variable.' | translate\"\n            ></c8y-ui-empty-state>\n\n            <div class=\"card-footer\">\n              <button\n                type=\"button\"\n                title=\"{{ 'Add variable' | translate }}\"\n                class=\"btn btn-default addVariableBtn\"\n                (click)=\"addVariable()\"\n              >\n                <i c8yIcon=\"plus-circle\"></i>\n                {{ 'Add variable' | translate }}\n              </button>\n            </div>\n          </div>\n        </div>\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n            <div class=\"h4\" translate>Data reporting</div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n            <opcua-device-protocol-data-reporting\n              [groupName]=\"'subscription'\"\n              [model]=\"model\"\n            ></opcua-device-protocol-data-reporting>\n          </div>\n        </div>\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom sticky-top\">\n            <div class=\"h4\" translate>Auto apply constraints</div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n            <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n          </div>\n        </div>\n\n        <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n          <button\n            title=\"{{ 'Save' | translate }}\"\n            id=\"deviceTypeSave\"\n            class=\"btn btn-primary\"\n            (click)=\"save()\"\n            [disabled]=\"canSave(deviceTypeForm)\"\n            type=\"button\"\n          >\n            {{ 'Save' | translate }}\n          </button>\n        </div>\n      </div>\n    </form>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.NgModelGroup, selector: "[ngModelGroup]", inputs: ["ngModelGroup"], exportAs: ["ngModelGroup"] }, { kind: "directive", type: i2$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: OpcuaDeviceProtocolDescription, selector: "opcua-device-protocol-description", inputs: ["model"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: OpcuaDeviceProtocolMapping, selector: "opcua-device-protocol-mapping", inputs: ["resource", "index", "getParentAttr", "referencedServerId", "referencedRootNodeId"], outputs: ["onAction"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: OpcuaDeviceProtocolDataReportingComponent, selector: "opcua-device-protocol-data-reporting", inputs: ["model", "groupName"], outputs: ["onSubscriptionChange"] }, { kind: "component", type: OpcuaAutoApplySettingsComponent, selector: "opcua-auto-apply", inputs: ["model"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-device-protocol-detail', imports: [
                        NgIf,
                        TitleComponent,
                        BreadcrumbComponent,
                        BreadcrumbItemComponent,
                        FormsModule,
                        OpcuaDeviceProtocolDescription,
                        C8yTranslateDirective,
                        NgFor,
                        OpcuaDeviceProtocolMapping,
                        EmptyStateComponent,
                        IconDirective,
                        OpcuaDeviceProtocolDataReportingComponent,
                        OpcuaAutoApplySettingsComponent,
                        C8yTranslatePipe
                    ], template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n  <c8y-breadcrumb-item\n    [icon]=\"'c8y-device-protocols'\"\n    [label]=\"'Device types' | translate\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    [icon]=\"'c8y-device-protocols'\"\n    [label]=\"'Device protocols' | translate\"\n    [path]=\"'deviceprotocols'\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n  <div class=\"col-lg-12 col-lg-max\">\n    <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n      <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n      <div class=\"inner-scroll\">\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n            <div class=\"h4\" translate>Variables</div>\n          </div>\n          <div class=\"p-l-16 p-r-16\">\n            <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n              <opcua-device-protocol-mapping\n                *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n                [index]=\"i\"\n                [referencedServerId]=\"model.referencedServerId\"\n                [referencedRootNodeId]=\"model.referencedRootNodeId\"\n                [resource]=\"getStructuredResource(resource)\"\n                [getParentAttr]=\"getParentAttr\"\n                (onAction)=\"actionHandler($event)\"\n              ></opcua-device-protocol-mapping>\n            </div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16\">\n            <c8y-ui-empty-state\n              *ngIf=\"model.mappings.length === 0\"\n              [icon]=\"'sliders'\"\n              [title]=\"'No variables to display.' | translate\"\n              [subtitle]=\"'Click below to add your first variable.' | translate\"\n            ></c8y-ui-empty-state>\n\n            <div class=\"card-footer\">\n              <button\n                type=\"button\"\n                title=\"{{ 'Add variable' | translate }}\"\n                class=\"btn btn-default addVariableBtn\"\n                (click)=\"addVariable()\"\n              >\n                <i c8yIcon=\"plus-circle\"></i>\n                {{ 'Add variable' | translate }}\n              </button>\n            </div>\n          </div>\n        </div>\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n            <div class=\"h4\" translate>Data reporting</div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n            <opcua-device-protocol-data-reporting\n              [groupName]=\"'subscription'\"\n              [model]=\"model\"\n            ></opcua-device-protocol-data-reporting>\n          </div>\n        </div>\n        <div class=\"d-contents\">\n          <div class=\"card-header separator-top-bottom sticky-top\">\n            <div class=\"h4\" translate>Auto apply constraints</div>\n          </div>\n          <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n            <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n          </div>\n        </div>\n\n        <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n          <button\n            title=\"{{ 'Save' | translate }}\"\n            id=\"deviceTypeSave\"\n            class=\"btn btn-primary\"\n            (click)=\"save()\"\n            [disabled]=\"canSave(deviceTypeForm)\"\n            type=\"button\"\n          >\n            {{ 'Save' | translate }}\n          </button>\n        </div>\n      </div>\n    </form>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: OpcuaService }, { type: i2$1.AlertService }, { type: i2.Router }], propDecorators: { instanceList: [{
                type: ViewChildren,
                args: [OpcuaDeviceProtocolMapping]
            }] } });

class OpcuaMicroserviceGuard {
    constructor(app) {
        this.app = app;
        this.microserviceName = 'opcua-mgmt-service';
    }
    canActivate() {
        if (!this.checkApp) {
            this.checkApp = this.app.isApplicationAvailable(this.microserviceName);
        }
        return this.checkApp;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaMicroserviceGuard, deps: [{ token: i2$1.AppStateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaMicroserviceGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaMicroserviceGuard, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i2$1.AppStateService }] });

const NEW_SERVER_ID = 'new';

class OpcuaServerConfigComponent {
    set opcuaConfigForm(opcuaConfigForm) {
        if (opcuaConfigForm) {
            opcuaConfigForm.form.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(e => {
                this.opcuaConfigFormValueChange$.next(e);
            });
        }
    }
    set server(server) {
        this._server = cloneDeep(server);
        if (server) {
            this.isNew.set(server.id === NEW_SERVER_ID);
            this.model = cloneDeep(server);
            this.fileName = this.model.config.keystoreFilename;
            if (this.isNew()) {
                // enabled connection state
                this.targetConnectionState = this.targetConnectionState ?? '1';
                this.model.config.targetConnectionState =
                    this.model.config.targetConnectionState ?? 'enabled';
                this.model.config.statusCheckInterval = this.model.config.statusCheckInterval ?? 40;
                this.model.config.timeout = this.model.config.timeout ?? 30;
                this.model.config.autoScanAddressSpace = this.model.config.autoScanAddressSpace ?? true;
                this.model.config.partialAddressScan = this.model.config.partialAddressScan ?? false;
            }
            else {
                this.targetConnectionState =
                    this.model.config.targetConnectionState === 'enabled' ? '1' : '0';
            }
            this.updateConnectionStatusLabel(this._server);
            this.setNewPassword();
        }
    }
    get server() {
        return this._server;
    }
    constructor(opcuaService, modalService, alertService, changeDetectorRef) {
        this.opcuaService = opcuaService;
        this.modalService = modalService;
        this.alertService = alertService;
        this.changeDetectorRef = changeDetectorRef;
        this.fileName = '';
        this.targetConnectionState = '1';
        this.minIntervalNumber = 1;
        this.connectionStatusLabel = '';
        this.autoScanAddressSpace = '0';
        this.advancedSettings = false;
        this.advancedSettingsForm = new FormGroup({});
        this.advancedSettingsFields = [];
        this.isNew = signal(false, ...(ngDevMode ? [{ debugName: "isNew" }] : []));
        this.canceled = new EventEmitter();
        this.removed = new EventEmitter();
        this.saved = new EventEmitter();
        this.updated = new EventEmitter();
        this.changePassword = false;
        this.initialPasswordRequired = true;
        this.NONE = 'NONE';
        this.SIGN = 'SIGN';
        this.SIGN_ENC = 'SIGN_ENCRYPT';
        this.securityPolicies = {
            sign: [`BASIC256_${this.SIGN}`, `BASIC128RSA15_${this.SIGN}`, `BASIC256SHA256_${this.SIGN}`],
            sign_enc: [
                `BASIC256_${this.SIGN_ENC}`,
                `BASIC128RSA15_${this.SIGN_ENC}`,
                `BASIC256SHA256_${this.SIGN_ENC}`
            ]
        };
        this.ANONYM = {
            id: 1,
            value: gettext('Anonymous')
        };
        this.USER_PASSWORD = {
            id: 2,
            value: gettext('Username/Password')
        };
        this.KEY_BASED = {
            id: 3,
            value: gettext('Key-based Authentication')
        };
        this.initialKeystore = {
            lastModified: 0,
            name: '',
            type: '',
            slice: null,
            size: 0
        };
        this.keystore = this.initialKeystore;
        this.authSwitch = false;
        this.opcuaConfigFormValueChange$ = new Subject();
        this.opcuaConfigFormChangesSubscribed = false;
        this.destroyRef = inject(DestroyRef);
        this.advancedSettingsFields = this.getAdvancedSettingsFields();
    }
    async ngOnInit() {
        this.authSwitch = false;
        this.securityModes = [this.NONE, this.SIGN, this.SIGN_ENC];
        this.authenticationModes = [this.ANONYM, this.USER_PASSWORD, this.KEY_BASED];
        this.setCurrentAuthenticationMode();
        this.setCurrentSecurityMode();
    }
    ngOnChanges() {
        this.setCurrentSecurityMode();
        this.setCurrentAuthenticationMode();
    }
    ngAfterViewChecked() {
        this.changeDetectorRef.detectChanges();
        if (!this.opcuaConfigFormChangesSubscribed) {
            merge(this.opcuaConfigFormValueChange$, this.advancedSettingsForm.valueChanges)
                .pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef))
                .subscribe(() => this.updated.emit(this.model));
            this.opcuaConfigFormChangesSubscribed = true;
        }
    }
    cancel() {
        this.advancedSettingsForm.reset();
        this.canceled.emit(this.model);
        this._server = null;
    }
    async remove() {
        try {
            await this.modalService.confirm(gettext('Delete server'), gettext("You're about to delete server. Do you want to proceed?"), Status.DANGER, {
                ok: gettext('Delete'),
                cancel: gettext('Cancel')
            });
            await this.removeKeystore(this.model);
            this.removed.emit(this.model);
            this._server = null;
        }
        catch (ex) {
            if (ex) {
                this.alertService.addServerFailure(ex);
            }
        }
    }
    async save() {
        if (this.keystore &&
            this.keystore.size > 0 &&
            this.keystore.name &&
            this.keystore.name.length > 0) {
            const response = await this.uploadKeystore(this.model.config.keystoreBinaryId);
            if (response && response.data && response.data.id) {
                this.model.config.keystoreBinaryId = response.data.id;
            }
            // if the keystore was uploaded successful we can remove
            // the local keystore. This will prevent another request to binary api
            // when the user will edit other inputs in the form and hit save again.
            this.keystore = this.initialKeystore;
        }
        // will remove any empty or undefined strings from the UI before saving it to the config
        function notEmpty(value) {
            return value !== null && value !== undefined && value != '';
        }
        // clean up array of empty strings
        this.model.config.partialAddressScanNodeIds = (this.model.config.partialAddressScanNodeIds || []).filter(notEmpty);
        // will remove keystore (binary) when the user switched
        // authentication settings from key-based to anonymous or username/password
        if (this.authSwitch) {
            this.removeKeystore(this.server);
        }
        // when the user sets a new password, make sure to mark it as
        // "not encrypted" by setting passwordEncrypted to false
        const userPassword = this.getModelConfig('userPassword');
        if (userPassword && userPassword.length > 0) {
            this.model.config.passwordEncrypted = false;
        }
        this.saved.emit(this.model);
    }
    uploadFile(droppedFiles) {
        if (droppedFiles.length === 1) {
            this.keystore = droppedFiles[0].file;
            this.fileName = this.keystore.name;
        }
        else {
        }
    }
    setPolicy(data) {
        if (data === this.NONE) {
            this.model.config.securityMode = this.NONE;
        }
        else if (data === this.SIGN) {
            this.model.config.securityMode = this.securityPolicies.sign[0];
        }
        else if (data === this.SIGN_ENC) {
            this.model.config.securityMode = this.securityPolicies.sign_enc[0];
        }
    }
    setServerConnection(data) {
        this.model.config.targetConnectionState = data !== '0' ? 'enabled' : 'disabled';
    }
    updateAuthentication(data) {
        if (data && data.id) {
            switch (data.id) {
                // Anonymous
                case 1:
                    this.resetUserAuthentication();
                    this.resetKeyBasedAuthentication();
                    break;
                // User/Password
                case 2:
                    this.resetKeyBasedAuthentication();
                    this.restoreUserData();
                    this.setNewPassword();
                    break;
                // Key-based
                case 3:
                    this.resetUserAuthentication();
                    this.restoreKeyBasedData();
                    break;
                default:
                    break;
            }
        }
    }
    updateConnectionStatusLabel(server) {
        const connected = server.c8y_Connection && server.c8y_Connection.status === 'CONNECTED';
        const label = connected ? gettext('Connected') : gettext('Disconnected');
        this.connectionStatusLabel = label;
    }
    setNewPassword() {
        const username = this.getModelConfig('userName');
        if (username && username.length > 0) {
            // userName is given, NO need to change the password because it is already set
            this.changePassword = false;
            this.initialPasswordRequired = false;
        }
        else {
            // no userName in response, so require the user to set the initial pw
            this.changePassword = true;
            this.initialPasswordRequired = true;
        }
    }
    toggleChangePassword() {
        this.changePassword = !this.changePassword;
        // When the user hides the pw-input field but has entered a
        // string to it before, we need to discard the changes reflected in the model
        // otherwise we PUT it with the model when user hits the save button
        if (!this.changePassword) {
            if (this.getModelConfig('userPassword')) {
                delete this.model.config.userPassword;
            }
        }
    }
    uploadKeystore(binaryId) {
        if (!binaryId) {
            return this.opcuaService.uploadKeystore(this.keystore);
        }
        else if (binaryId && binaryId.length > 0) {
            // update existing binary
            return this.opcuaService.updateKeystore(binaryId, this.keystore);
        }
    }
    removeKeystore(server) {
        if (server &&
            server.config &&
            server.config.keystoreBinaryId &&
            server.config.keystoreBinaryId.length > 0) {
            this.authSwitch = false;
            return this.opcuaService.removeKeystore(this.server.config.keystoreBinaryId);
        }
    }
    resetUserAuthentication() {
        this.model.config.userName = null;
        this.model.config.userPassword = null;
        this.model.config.userIdentityMode = 'none';
    }
    resetKeyBasedAuthentication() {
        this.authSwitch = true;
        this.model.config.keystorePass = null;
        this.model.config.certificatePass = null;
        this.model.config.keystoreBinaryId = '';
        this.model.config.keystoreFilename = '';
        this.model.config.userIdentityMode = 'none';
    }
    restoreUserData() {
        this.model.config.userName = this._server.config.userName;
        this.model.config.userIdentityMode = 'userAndPassword';
    }
    restoreKeyBasedData() {
        this.authSwitch = false;
        this.model.config.keystorePass = this._server.config.keystorePass;
        this.model.config.certificatePass = this._server.config.certificatePass;
        this.model.config.keystoreBinaryId = this._server.config.keystoreBinaryId;
        this.model.config.keystoreFilename = this._server.config.keystoreFilename;
        this.model.config.userIdentityMode = 'certificate';
    }
    getServerConfig() {
        let cfg = {
            securityMode: this.NONE,
            userIdentityMode: 'none'
        };
        if (this.server && this.server.config) {
            cfg = this.server.config;
        }
        return cfg;
    }
    setCurrentSecurityMode() {
        const { securityMode } = this.getServerConfig();
        if (securityMode) {
            const foundInSign = this.securityPolicies.sign.find(el => el === securityMode);
            if (foundInSign) {
                this.currentSecMode = this.SIGN;
            }
            else {
                const foundInSignEncrypt = this.securityPolicies.sign_enc.find(el => el === securityMode);
                foundInSignEncrypt
                    ? (this.currentSecMode = this.SIGN_ENC)
                    : (this.currentSecMode = this.NONE);
            }
        }
    }
    setCurrentAuthenticationMode() {
        const { userIdentityMode } = this.getServerConfig();
        switch (userIdentityMode) {
            case 'certificate':
                this.authenticationMode = this.KEY_BASED;
                break;
            case 'userAndPassword':
                this.authenticationMode = this.USER_PASSWORD;
                break;
            case 'Anonymous':
                this.authenticationMode = this.ANONYM;
                break;
            case 'UserName':
                this.authenticationMode = this.USER_PASSWORD;
                break;
            case 'Certificate':
                this.authenticationMode = this.KEY_BASED;
                break;
            default:
                this.authenticationMode = this.ANONYM;
                break;
        }
    }
    getModelConfig(fragment) {
        if (this.model && this.model.config) {
            if (fragment && fragment.length > 0) {
                return has(this.model.config, fragment) ? this.model.config[`${fragment}`] : undefined;
            }
        }
        return undefined;
    }
    getAdvancedSettingsFields() {
        return [
            {
                fieldGroupClassName: 'tight-grid',
                fieldGroup: [
                    {
                        key: 'timeout',
                        type: 'number',
                        className: 'col-xs-6',
                        props: {
                            label: gettext('Timeout'),
                            placeholder: '30',
                            required: true,
                            min: this.minIntervalNumber,
                            addonRight: {
                                text: gettext('seconds')
                            }
                        }
                    },
                    {
                        key: 'statusCheckInterval',
                        type: 'number',
                        className: 'col-xs-6',
                        props: {
                            label: gettext('Status check interval'),
                            placeholder: '40',
                            required: true,
                            min: this.minIntervalNumber,
                            addonRight: {
                                text: gettext('seconds')
                            }
                        }
                    }
                ]
            },
            {
                fieldGroupClassName: 'row',
                fieldGroup: [
                    {
                        key: 'autoScanAddressSpace',
                        type: 'checkbox',
                        className: 'col-sm-6',
                        props: {
                            label: gettext('Auto scan address space'),
                            indeterminate: false
                        }
                    },
                    {
                        key: 'partialAddressScan',
                        type: 'radio',
                        className: 'col-sm-6',
                        props: {
                            label: gettext('Address scan type'),
                            options: [
                                { label: gettext('Partial'), value: true },
                                { label: gettext('Full'), value: false }
                            ]
                        }
                    }
                ]
            },
            {
                key: 'partialAddressScanNodeIds',
                type: 'array',
                props: {
                    label: gettext('Partial address scan nodes'),
                    description: gettext('Add node IDs to be scanned in the address space of the OPC UA server'),
                    required: true
                },
                fieldArray: {
                    type: 'string',
                    props: {
                        label: gettext('Node ID'),
                        placeholder: 'ns=2;s=Node1',
                        required: true
                    }
                },
                expressions: {
                    hide: ({ parent }) => !parent?.model?.partialAddressScan
                }
            }
        ];
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerConfigComponent, deps: [{ token: OpcuaService }, { token: i2$1.ModalService }, { token: i2$1.AlertService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaServerConfigComponent, isStandalone: true, selector: "opcua-server-config", inputs: { server: "server" }, outputs: { canceled: "canceled", removed: "removed", saved: "saved", updated: "updated" }, viewQueries: [{ propertyName: "opcuaConfigForm", first: true, predicate: ["opcuaConfigForm"], descendants: true }, { propertyName: "dropArea", first: true, predicate: DropAreaComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<c8y-ui-empty-state\n  [icon]=\"'server'\"\n  [title]=\"'No server to display.' | translate\"\n  [subtitle]=\"'Add or select a server.' | translate\"\n  *ngIf=\"!server\"\n></c8y-ui-empty-state>\n\n<form\n  class=\"d-contents\"\n  #opcuaConfigForm=\"ngForm\"\n  *ngIf=\"server\"\n>\n  <div class=\"card-header large-padding separator sticky-top visible-sm visible-xs\">\n    <button\n      class=\"btn btn-clean text-primary visible-sm visible-xs\"\n      title=\"{{ 'Back' | translate }}\"\n      type=\"button\"\n      (click)=\"cancel()\"\n    >\n      <i c8yIcon=\"chevron-left\"></i>\n      {{ 'Back' | translate }}\n    </button>\n  </div>\n  <div class=\"flex-grow\">\n    <div class=\"card-block large-padding\">\n      <!-- SERVER NAME -->\n      <c8y-form-group class=\"m-b-8\">\n        <label>{{ 'Server name' | translate }}</label>\n        <input\n          class=\"form-control\"\n          id=\"name\"\n          placeholder=\"{{ 'e.g. My server' | translate }}\"\n          name=\"name\"\n          type=\"text\"\n          required\n          [(ngModel)]=\"model.name\"\n        />\n        <c8y-messages>\n          <c8y-message\n            name=\"required\"\n            text=\"{{ 'Server name is required' | translate }}\"\n          ></c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </div>\n\n    <div class=\"card-block large-padding bg-level-2\">\n      <div class=\"tight-grid\">\n        <div class=\"col-sm-6\">\n          <label\n            class=\"fit-w\"\n            translate\n          >\n            Server connection\n          </label>\n          <button\n            class=\"btn m-t-4\"\n            name=\"serverConnection\"\n            type=\"button\"\n            [(ngModel)]=\"targetConnectionState\"\n            (ngModelChange)=\"setServerConnection($event)\"\n            btnCheckbox\n            btnCheckboxTrue=\"1\"\n            btnCheckboxFalse=\"0\"\n          >\n            <span\n              title=\"{{ 'Enabled' | translate }}\"\n              [hidden]=\"targetConnectionState !== '1'\"\n            >\n              {{ 'Enabled' | translate }}\n            </span>\n            <span\n              title=\"{{ 'Disabled' | translate }}\"\n              [hidden]=\"targetConnectionState !== '0'\"\n            >\n              {{ 'Disabled' | translate }}\n            </span>\n          </button>\n        </div>\n        <div class=\"col-sm-6\">\n          <label translate>Connection status</label>\n          <div class=\"form-control-static\">\n            <device-status\n              class=\"p-r-8\"\n              [mo]=\"server\"\n            ></device-status>\n            <span>{{ connectionStatusLabel | translate }}</span>\n          </div>\n        </div>\n      </div>\n    </div>\n    <div class=\"card-block large-padding\">\n      <!-- SERVER URL-->\n      <c8y-form-group>\n        <label\n          for=\"configServerUrl\"\n          translate\n        >\n          Server URL\n        </label>\n        <input\n          class=\"form-control\"\n          id=\"configServerUrl\"\n          name=\"serverUrl\"\n          type=\"text\"\n          required\n          [(ngModel)]=\"model.config.serverUrl\"\n          c8yDefaultValidation=\"opcuaBrowsePath\"\n        />\n      </c8y-form-group>\n\n      <!-- SECURITY MODE -->\n      <div class=\"tight-grid\">\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <!-- NONE, SIGN, SIGN & ENCRYPT-->\n            <label\n              for=\"config.securityMode\"\n              translate\n            >\n              Security mode\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.securityMode\"\n                name=\"securityMode\"\n                required\n                [(ngModel)]=\"currentSecMode\"\n                (ngModelChange)=\"setPolicy($event)\"\n              >\n                <option\n                  *ngFor=\"let mode of securityModes\"\n                  [ngValue]=\"mode\"\n                >\n                  {{ mode }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n        <div\n          class=\"col-md-6\"\n          *ngIf=\"currentSecMode === NONE\"\n        >\n          <div class=\"form-group\">\n            <label\n              for=\"config.securityPolicy\"\n              translate\n            >\n              Security policy\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.securityPolicy\"\n              name=\"securityPolicy\"\n              type=\"text\"\n              required\n              [readonly]=\"true\"\n              [(ngModel)]=\"model.config.securityMode\"\n            />\n          </div>\n        </div>\n        <div\n          class=\"col-md-6\"\n          *ngIf=\"currentSecMode !== NONE\"\n        >\n          <div class=\"form-group\">\n            <label\n              for=\"config.securityPolicy\"\n              translate\n            >\n              Security policy\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.securityPolicy\"\n                name=\"securityPolicy\"\n                required\n                *ngIf=\"currentSecMode === SIGN\"\n                [(ngModel)]=\"model.config.securityMode\"\n              >\n                <option\n                  *ngFor=\"let policy of securityPolicies.sign\"\n                  [ngValue]=\"policy\"\n                >\n                  {{ policy }}\n                </option>\n              </select>\n              <select\n                class=\"form-control\"\n                id=\"config.securityPolicy\"\n                name=\"securityPolicy\"\n                required\n                *ngIf=\"currentSecMode === SIGN_ENC\"\n                [(ngModel)]=\"model.config.securityMode\"\n              >\n                <option\n                  *ngFor=\"let policy of securityPolicies.sign_enc\"\n                  [ngValue]=\"policy\"\n                >\n                  {{ policy }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- AUTHENTICATION -->\n      <div class=\"row tight-grid\">\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.authenticationMode\"\n              translate\n            >\n              Authentication\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.authenticationMode\"\n                name=\"authenticationMode\"\n                required\n                [(ngModel)]=\"authenticationMode\"\n                (ngModelChange)=\"updateAuthentication($event)\"\n              >\n                <option\n                  *ngFor=\"let auth of authenticationModes\"\n                  [ngValue]=\"auth\"\n                >\n                  {{ auth.value | translate }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n      </div>\n      <!-- User/Pw-->\n      <div\n        class=\"tight-grid\"\n        *ngIf=\"authenticationMode.id === 2\"\n      >\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.userName\"\n              translate\n            >\n              Username\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.userName\"\n              placeholder=\"{{ 'e.g. joe.doe`LOCALIZE`' | translate }}\"\n              name=\"userName\"\n              type=\"text\"\n              autocomplete=\"new-password\"\n              required\n              [(ngModel)]=\"model.config.userName\"\n            />\n          </div>\n        </div>\n\n        <!-- change password section BEGINS-->\n        <div class=\"col-md-6\">\n          <div\n            class=\"form-group\"\n            *ngIf=\"!initialPasswordRequired\"\n          >\n            <button\n              class=\"btn btn-default\"\n              type=\"button\"\n              (click)=\"toggleChangePassword()\"\n            >\n              <ng-container *ngIf=\"!changePassword\">\n                {{ 'Change password' | translate }}\n              </ng-container>\n              <ng-container *ngIf=\"changePassword\">\n                {{ 'Cancel password change' | translate }}\n              </ng-container>\n            </button>\n          </div>\n\n          <div class=\"form-group\">\n            <div *ngIf=\"changePassword\">\n              <label\n                for=\"config.password\"\n                translate\n              >\n                Password\n              </label>\n              <input\n                class=\"form-control\"\n                id=\"config.userPassword\"\n                name=\"password\"\n                type=\"password\"\n                autocomplete=\"new-password\"\n                required\n                [(ngModel)]=\"model.config.userPassword\"\n              />\n            </div>\n          </div>\n        </div>\n        <!-- change password section ENDS-->\n      </div>\n\n      <!-- Key-based -->\n      <div\n        class=\"tight-grid\"\n        *ngIf=\"authenticationMode.id === 3\"\n      >\n        <!-- KEYSTORE PASSWORD -->\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.keystorePass\"\n              translate\n            >\n              Keystore password\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.keystorePass\"\n              name=\"keystorePass\"\n              type=\"password\"\n              required\n              [(ngModel)]=\"model.config.keystorePass\"\n            />\n          </div>\n        </div>\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.certificatePass\"\n              translate\n            >\n              Certificate password\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.certificatePass\"\n              name=\"keystorePass\"\n              type=\"password\"\n              required\n              [(ngModel)]=\"model.config.certificatePass\"\n            />\n          </div>\n        </div>\n        <!-- UPLOAD KEYSTORE -->\n        <div class=\"col-md-12\">\n          <div class=\"form-group\">\n            <label\n              for=\"certificateUpload\"\n              translate\n            >\n              Upload keystore\n            </label>\n            <input\n              class=\"form-control m-b-8\"\n              placeholder=\"{{ 'e.g.' | translate }} yourKeystore.jks\"\n              name=\"certificateUpload\"\n              type=\"text\"\n              required\n              [readonly]=\"true\"\n              [ngModel]=\"fileName\"\n            />\n            <c8y-drop-area\n              [title]=\"'Import keystore with jks file extension' | translate\"\n              (dropped)=\"uploadFile($event)\"\n              [loadingMessage]=\"'Importing, please wait.' | translate\"\n            ></c8y-drop-area>\n          </div>\n        </div>\n      </div>\n\n      <div class=\"form-group m-b-0 d-flex a-i-center\">\n        <button\n          class=\"btn btn-dot collapse-btn\"\n          title=\"{{ (advancedSettings ? collapse : expand) | translate }}\"\n          [attr.aria-label]=\"(advancedSettings ? collapse : expand) | translate\"\n          [attr.aria-expanded]=\"advancedSettings\"\n          [ngClass]=\"{ active: advancedSettings }\"\n          (click)=\"advancedSettings = !advancedSettings\"\n          data-cy=\"opcua-server-config--advanced-settings-toggle\"\n        >\n          <i c8yIcon=\"chevron-right\"></i>\n        </button>\n        <label class=\"m-0\">\n          <span>{{ 'Advanced settings' | translate }}</span>\n        </label>\n      </div>\n    </div>\n\n    <div\n      class=\"card-block collapse\"\n      [collapse]=\"!advancedSettings\"\n      [isAnimated]=\"true\"\n      [ngClass]=\"{ 'bg-level-1': advancedSettings }\"\n    >\n      <formly-form\n        [form]=\"advancedSettingsForm\"\n        [fields]=\"advancedSettingsFields\"\n        [model]=\"model.config\"\n      ></formly-form>\n    </div>\n  </div>\n  <div class=\"card-footer large-padding separator sticky-bottom\">\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Cancel' | translate }}\"\n      type=\"button\"\n      (click)=\"cancel()\"\n    >\n      {{ 'Cancel' | translate }}\n    </button>\n    <button\n      class=\"btn btn-danger\"\n      title=\"{{ 'Remove' | translate }}\"\n      type=\"button\"\n      (click)=\"remove()\"\n      [disabled]=\"isNew()\"\n    >\n      {{ 'Remove' | translate }}\n    </button>\n    <button\n      class=\"btn btn-primary\"\n      title=\"{{ 'Save' | translate }}\"\n      type=\"submit\"\n      (click)=\"save()\"\n      [disabled]=\"!opcuaConfigForm.valid || !advancedSettingsForm.valid\"\n    >\n      {{ 'Save' | translate }}\n    </button>\n  </div>\n</form>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: ButtonCheckboxDirective, selector: "[btnCheckbox]", inputs: ["btnCheckboxTrue", "btnCheckboxFalse"] }, { kind: "component", type: DeviceStatusComponent, selector: "device-status, c8y-device-status", inputs: ["mo", "size"] }, { kind: "directive", type: DefaultValidationDirective, selector: "[c8yDefaultValidation]", inputs: ["c8yDefaultValidation"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerConfigComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-server-config', imports: [
                        NgIf,
                        EmptyStateComponent,
                        FormsModule,
                        IconDirective,
                        FormGroupComponent,
                        RequiredInputPlaceholderDirective,
                        MessagesComponent,
                        MessageDirective,
                        C8yTranslateDirective,
                        ButtonCheckboxDirective,
                        DeviceStatusComponent,
                        DefaultValidationDirective,
                        NgFor,
                        DropAreaComponent,
                        NgClass,
                        CollapseDirective,
                        FormlyModule,
                        C8yTranslatePipe
                    ], template: "<c8y-ui-empty-state\n  [icon]=\"'server'\"\n  [title]=\"'No server to display.' | translate\"\n  [subtitle]=\"'Add or select a server.' | translate\"\n  *ngIf=\"!server\"\n></c8y-ui-empty-state>\n\n<form\n  class=\"d-contents\"\n  #opcuaConfigForm=\"ngForm\"\n  *ngIf=\"server\"\n>\n  <div class=\"card-header large-padding separator sticky-top visible-sm visible-xs\">\n    <button\n      class=\"btn btn-clean text-primary visible-sm visible-xs\"\n      title=\"{{ 'Back' | translate }}\"\n      type=\"button\"\n      (click)=\"cancel()\"\n    >\n      <i c8yIcon=\"chevron-left\"></i>\n      {{ 'Back' | translate }}\n    </button>\n  </div>\n  <div class=\"flex-grow\">\n    <div class=\"card-block large-padding\">\n      <!-- SERVER NAME -->\n      <c8y-form-group class=\"m-b-8\">\n        <label>{{ 'Server name' | translate }}</label>\n        <input\n          class=\"form-control\"\n          id=\"name\"\n          placeholder=\"{{ 'e.g. My server' | translate }}\"\n          name=\"name\"\n          type=\"text\"\n          required\n          [(ngModel)]=\"model.name\"\n        />\n        <c8y-messages>\n          <c8y-message\n            name=\"required\"\n            text=\"{{ 'Server name is required' | translate }}\"\n          ></c8y-message>\n        </c8y-messages>\n      </c8y-form-group>\n    </div>\n\n    <div class=\"card-block large-padding bg-level-2\">\n      <div class=\"tight-grid\">\n        <div class=\"col-sm-6\">\n          <label\n            class=\"fit-w\"\n            translate\n          >\n            Server connection\n          </label>\n          <button\n            class=\"btn m-t-4\"\n            name=\"serverConnection\"\n            type=\"button\"\n            [(ngModel)]=\"targetConnectionState\"\n            (ngModelChange)=\"setServerConnection($event)\"\n            btnCheckbox\n            btnCheckboxTrue=\"1\"\n            btnCheckboxFalse=\"0\"\n          >\n            <span\n              title=\"{{ 'Enabled' | translate }}\"\n              [hidden]=\"targetConnectionState !== '1'\"\n            >\n              {{ 'Enabled' | translate }}\n            </span>\n            <span\n              title=\"{{ 'Disabled' | translate }}\"\n              [hidden]=\"targetConnectionState !== '0'\"\n            >\n              {{ 'Disabled' | translate }}\n            </span>\n          </button>\n        </div>\n        <div class=\"col-sm-6\">\n          <label translate>Connection status</label>\n          <div class=\"form-control-static\">\n            <device-status\n              class=\"p-r-8\"\n              [mo]=\"server\"\n            ></device-status>\n            <span>{{ connectionStatusLabel | translate }}</span>\n          </div>\n        </div>\n      </div>\n    </div>\n    <div class=\"card-block large-padding\">\n      <!-- SERVER URL-->\n      <c8y-form-group>\n        <label\n          for=\"configServerUrl\"\n          translate\n        >\n          Server URL\n        </label>\n        <input\n          class=\"form-control\"\n          id=\"configServerUrl\"\n          name=\"serverUrl\"\n          type=\"text\"\n          required\n          [(ngModel)]=\"model.config.serverUrl\"\n          c8yDefaultValidation=\"opcuaBrowsePath\"\n        />\n      </c8y-form-group>\n\n      <!-- SECURITY MODE -->\n      <div class=\"tight-grid\">\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <!-- NONE, SIGN, SIGN & ENCRYPT-->\n            <label\n              for=\"config.securityMode\"\n              translate\n            >\n              Security mode\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.securityMode\"\n                name=\"securityMode\"\n                required\n                [(ngModel)]=\"currentSecMode\"\n                (ngModelChange)=\"setPolicy($event)\"\n              >\n                <option\n                  *ngFor=\"let mode of securityModes\"\n                  [ngValue]=\"mode\"\n                >\n                  {{ mode }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n        <div\n          class=\"col-md-6\"\n          *ngIf=\"currentSecMode === NONE\"\n        >\n          <div class=\"form-group\">\n            <label\n              for=\"config.securityPolicy\"\n              translate\n            >\n              Security policy\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.securityPolicy\"\n              name=\"securityPolicy\"\n              type=\"text\"\n              required\n              [readonly]=\"true\"\n              [(ngModel)]=\"model.config.securityMode\"\n            />\n          </div>\n        </div>\n        <div\n          class=\"col-md-6\"\n          *ngIf=\"currentSecMode !== NONE\"\n        >\n          <div class=\"form-group\">\n            <label\n              for=\"config.securityPolicy\"\n              translate\n            >\n              Security policy\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.securityPolicy\"\n                name=\"securityPolicy\"\n                required\n                *ngIf=\"currentSecMode === SIGN\"\n                [(ngModel)]=\"model.config.securityMode\"\n              >\n                <option\n                  *ngFor=\"let policy of securityPolicies.sign\"\n                  [ngValue]=\"policy\"\n                >\n                  {{ policy }}\n                </option>\n              </select>\n              <select\n                class=\"form-control\"\n                id=\"config.securityPolicy\"\n                name=\"securityPolicy\"\n                required\n                *ngIf=\"currentSecMode === SIGN_ENC\"\n                [(ngModel)]=\"model.config.securityMode\"\n              >\n                <option\n                  *ngFor=\"let policy of securityPolicies.sign_enc\"\n                  [ngValue]=\"policy\"\n                >\n                  {{ policy }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- AUTHENTICATION -->\n      <div class=\"row tight-grid\">\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.authenticationMode\"\n              translate\n            >\n              Authentication\n            </label>\n            <div class=\"c8y-select-wrapper\">\n              <select\n                class=\"form-control\"\n                id=\"config.authenticationMode\"\n                name=\"authenticationMode\"\n                required\n                [(ngModel)]=\"authenticationMode\"\n                (ngModelChange)=\"updateAuthentication($event)\"\n              >\n                <option\n                  *ngFor=\"let auth of authenticationModes\"\n                  [ngValue]=\"auth\"\n                >\n                  {{ auth.value | translate }}\n                </option>\n              </select>\n              <span></span>\n            </div>\n          </div>\n        </div>\n      </div>\n      <!-- User/Pw-->\n      <div\n        class=\"tight-grid\"\n        *ngIf=\"authenticationMode.id === 2\"\n      >\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.userName\"\n              translate\n            >\n              Username\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.userName\"\n              placeholder=\"{{ 'e.g. joe.doe`LOCALIZE`' | translate }}\"\n              name=\"userName\"\n              type=\"text\"\n              autocomplete=\"new-password\"\n              required\n              [(ngModel)]=\"model.config.userName\"\n            />\n          </div>\n        </div>\n\n        <!-- change password section BEGINS-->\n        <div class=\"col-md-6\">\n          <div\n            class=\"form-group\"\n            *ngIf=\"!initialPasswordRequired\"\n          >\n            <button\n              class=\"btn btn-default\"\n              type=\"button\"\n              (click)=\"toggleChangePassword()\"\n            >\n              <ng-container *ngIf=\"!changePassword\">\n                {{ 'Change password' | translate }}\n              </ng-container>\n              <ng-container *ngIf=\"changePassword\">\n                {{ 'Cancel password change' | translate }}\n              </ng-container>\n            </button>\n          </div>\n\n          <div class=\"form-group\">\n            <div *ngIf=\"changePassword\">\n              <label\n                for=\"config.password\"\n                translate\n              >\n                Password\n              </label>\n              <input\n                class=\"form-control\"\n                id=\"config.userPassword\"\n                name=\"password\"\n                type=\"password\"\n                autocomplete=\"new-password\"\n                required\n                [(ngModel)]=\"model.config.userPassword\"\n              />\n            </div>\n          </div>\n        </div>\n        <!-- change password section ENDS-->\n      </div>\n\n      <!-- Key-based -->\n      <div\n        class=\"tight-grid\"\n        *ngIf=\"authenticationMode.id === 3\"\n      >\n        <!-- KEYSTORE PASSWORD -->\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.keystorePass\"\n              translate\n            >\n              Keystore password\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.keystorePass\"\n              name=\"keystorePass\"\n              type=\"password\"\n              required\n              [(ngModel)]=\"model.config.keystorePass\"\n            />\n          </div>\n        </div>\n        <div class=\"col-md-6\">\n          <div class=\"form-group\">\n            <label\n              for=\"config.certificatePass\"\n              translate\n            >\n              Certificate password\n            </label>\n            <input\n              class=\"form-control\"\n              id=\"config.certificatePass\"\n              name=\"keystorePass\"\n              type=\"password\"\n              required\n              [(ngModel)]=\"model.config.certificatePass\"\n            />\n          </div>\n        </div>\n        <!-- UPLOAD KEYSTORE -->\n        <div class=\"col-md-12\">\n          <div class=\"form-group\">\n            <label\n              for=\"certificateUpload\"\n              translate\n            >\n              Upload keystore\n            </label>\n            <input\n              class=\"form-control m-b-8\"\n              placeholder=\"{{ 'e.g.' | translate }} yourKeystore.jks\"\n              name=\"certificateUpload\"\n              type=\"text\"\n              required\n              [readonly]=\"true\"\n              [ngModel]=\"fileName\"\n            />\n            <c8y-drop-area\n              [title]=\"'Import keystore with jks file extension' | translate\"\n              (dropped)=\"uploadFile($event)\"\n              [loadingMessage]=\"'Importing, please wait.' | translate\"\n            ></c8y-drop-area>\n          </div>\n        </div>\n      </div>\n\n      <div class=\"form-group m-b-0 d-flex a-i-center\">\n        <button\n          class=\"btn btn-dot collapse-btn\"\n          title=\"{{ (advancedSettings ? collapse : expand) | translate }}\"\n          [attr.aria-label]=\"(advancedSettings ? collapse : expand) | translate\"\n          [attr.aria-expanded]=\"advancedSettings\"\n          [ngClass]=\"{ active: advancedSettings }\"\n          (click)=\"advancedSettings = !advancedSettings\"\n          data-cy=\"opcua-server-config--advanced-settings-toggle\"\n        >\n          <i c8yIcon=\"chevron-right\"></i>\n        </button>\n        <label class=\"m-0\">\n          <span>{{ 'Advanced settings' | translate }}</span>\n        </label>\n      </div>\n    </div>\n\n    <div\n      class=\"card-block collapse\"\n      [collapse]=\"!advancedSettings\"\n      [isAnimated]=\"true\"\n      [ngClass]=\"{ 'bg-level-1': advancedSettings }\"\n    >\n      <formly-form\n        [form]=\"advancedSettingsForm\"\n        [fields]=\"advancedSettingsFields\"\n        [model]=\"model.config\"\n      ></formly-form>\n    </div>\n  </div>\n  <div class=\"card-footer large-padding separator sticky-bottom\">\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Cancel' | translate }}\"\n      type=\"button\"\n      (click)=\"cancel()\"\n    >\n      {{ 'Cancel' | translate }}\n    </button>\n    <button\n      class=\"btn btn-danger\"\n      title=\"{{ 'Remove' | translate }}\"\n      type=\"button\"\n      (click)=\"remove()\"\n      [disabled]=\"isNew()\"\n    >\n      {{ 'Remove' | translate }}\n    </button>\n    <button\n      class=\"btn btn-primary\"\n      title=\"{{ 'Save' | translate }}\"\n      type=\"submit\"\n      (click)=\"save()\"\n      [disabled]=\"!opcuaConfigForm.valid || !advancedSettingsForm.valid\"\n    >\n      {{ 'Save' | translate }}\n    </button>\n  </div>\n</form>\n" }]
        }], ctorParameters: () => [{ type: OpcuaService }, { type: i2$1.ModalService }, { type: i2$1.AlertService }, { type: i0.ChangeDetectorRef }], propDecorators: { opcuaConfigForm: [{
                type: ViewChild,
                args: ['opcuaConfigForm', { static: false }]
            }], dropArea: [{
                type: ViewChild,
                args: [DropAreaComponent, { static: false }]
            }], canceled: [{
                type: Output
            }], removed: [{
                type: Output
            }], saved: [{
                type: Output
            }], updated: [{
                type: Output
            }], server: [{
                type: Input
            }] } });

class OpcuaServerListComponent {
    constructor() {
        this.serverList = [];
        this.present = new EventEmitter();
    }
    presentConfig(server) {
        server.active = true;
        this.present.emit(server);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaServerListComponent, isStandalone: true, selector: "opcua-server-list", inputs: { serverList: "serverList" }, outputs: { present: "present" }, ngImport: i0, template: "<!-- add active class to c8y-stacked-item when clicked -->\n<div class=\"card-block\" *ngIf=\"serverList.length === 0\">\n  <c8y-ui-empty-state\n    class=\"m-l-auto p-l-8 d-flex p-r-16\"\n    [icon]=\"'server'\"\n    [title]=\"'No servers found.' | translate\"\n    [subtitle]=\"'Click below to add a new server.' | translate\"\n  ></c8y-ui-empty-state>\n</div>\n<div\n  class=\"c8y-stacked-item\"\n  [class.active]=\"server.active\"\n  *ngFor=\"let server of serverList\"\n  (click)=\"presentConfig(server)\"\n>\n  <i [c8yIcon]=\"'server'\" class=\"icon-20\"></i>\n  <div class=\"p-l-16 text-truncate\">\n    <p id=\"serverName\" class=\"text-truncate\">{{ server.name }}</p>\n    <small id=\"serverUrl\" class=\"text-truncate text-muted\">{{ server.config.serverUrl }}</small>\n  </div>\n  <div class=\"m-l-auto p-l-8 d-flex p-r-16 a-i-center\">\n    <device-status class=\"p-r-8\" [mo]=\"server\"></device-status>\n    <button\n      class=\"btn btn-dot text-gray-darker\"\n      type=\"button\"\n      [attr.aria-label]=\"server.quickInfo.padlockMsg | translate\"\n      tooltip=\"{{ server.quickInfo.padlockMsg | translate }}\"\n      placement=\"left\"\n      container=\"body\"\n    >\n      <i [c8yIcon]=\"server.quickInfo.padlock\"></i>\n    </button>\n  </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: DeviceStatusComponent, selector: "device-status, c8y-device-status", inputs: ["mo", "size"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-server-list', imports: [
                        NgIf,
                        EmptyStateComponent,
                        NgFor,
                        IconDirective,
                        DeviceStatusComponent,
                        TooltipDirective,
                        C8yTranslatePipe
                    ], template: "<!-- add active class to c8y-stacked-item when clicked -->\n<div class=\"card-block\" *ngIf=\"serverList.length === 0\">\n  <c8y-ui-empty-state\n    class=\"m-l-auto p-l-8 d-flex p-r-16\"\n    [icon]=\"'server'\"\n    [title]=\"'No servers found.' | translate\"\n    [subtitle]=\"'Click below to add a new server.' | translate\"\n  ></c8y-ui-empty-state>\n</div>\n<div\n  class=\"c8y-stacked-item\"\n  [class.active]=\"server.active\"\n  *ngFor=\"let server of serverList\"\n  (click)=\"presentConfig(server)\"\n>\n  <i [c8yIcon]=\"'server'\" class=\"icon-20\"></i>\n  <div class=\"p-l-16 text-truncate\">\n    <p id=\"serverName\" class=\"text-truncate\">{{ server.name }}</p>\n    <small id=\"serverUrl\" class=\"text-truncate text-muted\">{{ server.config.serverUrl }}</small>\n  </div>\n  <div class=\"m-l-auto p-l-8 d-flex p-r-16 a-i-center\">\n    <device-status class=\"p-r-8\" [mo]=\"server\"></device-status>\n    <button\n      class=\"btn btn-dot text-gray-darker\"\n      type=\"button\"\n      [attr.aria-label]=\"server.quickInfo.padlockMsg | translate\"\n      tooltip=\"{{ server.quickInfo.padlockMsg | translate }}\"\n      placement=\"left\"\n      container=\"body\"\n    >\n      <i [c8yIcon]=\"server.quickInfo.padlock\"></i>\n    </button>\n  </div>\n</div>\n" }]
        }], propDecorators: { serverList: [{
                type: Input
            }], present: [{
                type: Output
            }] } });

class OpcuaServerGuard {
    constructor() {
        this.type = 'c8y_OpcuaServer';
    }
    canActivate({ data }) {
        const { contextData } = data;
        return contextData && contextData.type === this.type;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServerGuard, decorators: [{
            type: Injectable
        }] });

class OpcuaServersComponent {
    constructor(opcuaService, alertService, translateService, context) {
        this.opcuaService = opcuaService;
        this.alertService = alertService;
        this.translateService = translateService;
        this.context = context;
        this.serverObjectList = [];
        this.initialServerObject = {
            id: NEW_SERVER_ID,
            name: gettext('New Server'),
            config: {
                securityMode: 'NONE',
                keystorePass: null,
                keystoreBinaryId: null,
                keystoreFilename: '',
                certificatePass: null,
                serverUrl: '',
                userName: '',
                userPassword: '',
                rescanCron: null,
                timeout: 30,
                statusCheckInterval: 40,
                autoReconnect: true,
                autoScanAddressSpace: true,
                partialAddressScan: false,
                valid: true
            },
            quickInfo: {
                padlock: 'unlock',
                padlockMsg: ''
            },
            active: true
        };
        this.active = false;
        this.moId = '';
    }
    async ngOnInit() {
        this.moId = this.opcuaService.getMoId();
        if (this.moId && this.moId.length > 0) {
            const res = await this.opcuaService.getServers(this.moId);
            if (res && res.status !== 200) {
                const data = res.json ? await res.json() : undefined;
                this.alertService.addServerFailure({ data, res });
            }
            else {
                this.serverObjectList = (await res.json());
                this.serverObjectList.map(server => this.setQuickInfo(server));
                this.onPresent(this.serverObjectList[0], false);
            }
        }
    }
    localServerObjectExist() {
        return !!this.serverObjectList.find(server => server.id === NEW_SERVER_ID);
    }
    addServer() {
        const server = cloneDeep$1(this.initialServerObject);
        this.serverObjectList.push(server);
        this.onPresent(server);
    }
    onSaved(server) {
        if (server && server.id) {
            server.gatewayId = this.moId;
            if (server.id === NEW_SERVER_ID) {
                this.createServer(server);
            }
            else {
                this.updateServer(server);
            }
        }
    }
    onUpdated(server) {
        if (server.id === NEW_SERVER_ID) {
            this.serverObjectList.forEach(item => {
                if (item.id === server.id) {
                    item.name = server.name;
                    item.config = server.config;
                    this.setQuickInfo(item);
                }
            });
        }
    }
    reloadTabs() {
        if (this.context) {
            this.context.refreshTabs();
        }
    }
    onCanceled(server) {
        if (server?.id === NEW_SERVER_ID) {
            this.removeServerObjectListById(server.id);
        }
        else {
            // update activity status for UI
            this.serverObjectList.forEach(item => {
                if (item.id === server.id) {
                    item.active = false;
                }
            });
            // When server id is not 'new' we just close the details
            delete this.server;
        }
    }
    onRemoved(server) {
        if (server.id === NEW_SERVER_ID) {
            this.onCanceled(server);
        }
        else {
            this.removeServer(server);
        }
    }
    async getKeystore(binaryId) {
        const { data } = await this.opcuaService.getKeystore(binaryId);
        return data;
    }
    async onPresent(server, overridePresent = true) {
        if (server && server.id !== NEW_SERVER_ID && server.config && server.config.keystoreBinaryId) {
            try {
                const mo = await this.getKeystore(server.config.keystoreBinaryId);
                server.config.keystoreFilename = mo.name;
            }
            catch (ex) {
                this.server = Object.assign({}, server);
            }
        }
        if (this.serverObjectList.length > 0) {
            this.serverObjectList.forEach(item => {
                item.active = false;
                if (item.id === server.id) {
                    item.active = true;
                    server.active = item.active;
                }
            });
            this.setQuickInfo(server);
            if (overridePresent || !this.server) {
                this.server = Object.assign({}, server);
            }
        }
    }
    async createServer(server) {
        const response = await this.opcuaService.createServer(server);
        const svr = (await response.json());
        this.updateServerObjectListById(NEW_SERVER_ID, svr);
        this.onPresent(svr);
        this.reloadTabs();
    }
    async updateServer(server) {
        const updatedServer = (await this.opcuaService.updateServer(server));
        if (updatedServer) {
            this.updateServerObjectListById(updatedServer.id, updatedServer);
        }
    }
    async removeServer(server) {
        try {
            await this.opcuaService.removeServer(server);
            this.removeServerObjectListById(server.id);
            this.reloadTabs();
        }
        catch (ex) { }
    }
    removeServerObjectListById(id) {
        this.serverObjectList.forEach((item, index) => {
            if (item.id === id) {
                this.serverObjectList.splice(index, 1);
                delete this.server;
            }
        });
    }
    updateServerObjectListById(id, server) {
        const idx = this.serverObjectList.findIndex(item => item.id === id);
        if (idx > -1) {
            this.setQuickInfo(server);
            this.serverObjectList[idx] = server;
        }
        delete this.server;
    }
    setQuickInfo(server) {
        server.quickInfo = {
            padlock: 'unlock',
            padlockMsg: ''
        };
        if (server && server.config) {
            if (server.config.securityMode) {
                server.quickInfo.padlock = server.config.securityMode !== 'NONE' ? 'lock' : 'unlock';
                server.quickInfo.padlockMsg = this.translateService.instant(gettext('The security policy is set to {{param}}.'), { param: server.config.securityMode });
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServersComponent, deps: [{ token: OpcuaService }, { token: i2$1.AlertService }, { token: i3.TranslateService }, { token: i2$1.ContextRouteComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: OpcuaServersComponent, isStandalone: true, selector: "opcua-servers", ngImport: i0, template: "<div class=\"card content-fullpage split-view--5-7\">\n  <div class=\"card-header grid__col--fullspan separator\">\n    <div class=\"h4 card-title\">OPC UA servers</div>\n    <button\n      class=\"btn-help\"\n      [attr.aria-label]=\"'Help' | translate\"\n      popover=\"{{\n        'Below you can configure one or more OPC UA servers. The OPC UA agent will connect to these servers if they are enabled and the connection state is set to connected.'\n          | translate\n      }}\"\n      placement=\"right\"\n      triggers=\"focus\"\n      type=\"button\"\n    ></button>\n  </div>\n  <div class=\"inner-scroll split-view__list\">\n    <div class=\"bg-level-1 flex-grow\">\n      <div class=\"c8y-nav-stacked\">\n        <opcua-server-list\n          [serverList]=\"serverObjectList\"\n          (present)=\"onPresent($event)\"\n        ></opcua-server-list>\n      </div>\n    </div>\n    <div class=\"card-footer separator sticky-bottom\">\n      <button\n        class=\"btn btn-default\"\n        title=\"{{ 'Add server' | translate }}\"\n        type=\"button\"\n        [disabled]=\"localServerObjectExist()\"\n        (click)=\"addServer()\"\n      >\n        <i [c8yIcon]=\"'plus-circle'\"></i>\n        {{ 'Add server' | translate }}\n      </button>\n    </div>\n  </div>\n\n  <opcua-server-config\n    class=\"inner-scroll split-view__detail\"\n    [ngClass]=\"{ 'split-view__detail--selected': server }\"\n    (canceled)=\"onCanceled($event)\"\n    (removed)=\"onRemoved($event)\"\n    (saved)=\"onSaved($event)\"\n    (updated)=\"onUpdated($event)\"\n    [server]=\"server\"\n  ></opcua-server-config>\n</div>\n", 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: "component", type: OpcuaServerListComponent, selector: "opcua-server-list", inputs: ["serverList"], outputs: ["present"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: OpcuaServerConfigComponent, selector: "opcua-server-config", inputs: ["server"], outputs: ["canceled", "removed", "saved", "updated"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaServersComponent, decorators: [{
            type: Component,
            args: [{ selector: 'opcua-servers', imports: [
                        PopoverDirective,
                        OpcuaServerListComponent,
                        IconDirective,
                        OpcuaServerConfigComponent,
                        NgClass,
                        C8yTranslatePipe
                    ], template: "<div class=\"card content-fullpage split-view--5-7\">\n  <div class=\"card-header grid__col--fullspan separator\">\n    <div class=\"h4 card-title\">OPC UA servers</div>\n    <button\n      class=\"btn-help\"\n      [attr.aria-label]=\"'Help' | translate\"\n      popover=\"{{\n        'Below you can configure one or more OPC UA servers. The OPC UA agent will connect to these servers if they are enabled and the connection state is set to connected.'\n          | translate\n      }}\"\n      placement=\"right\"\n      triggers=\"focus\"\n      type=\"button\"\n    ></button>\n  </div>\n  <div class=\"inner-scroll split-view__list\">\n    <div class=\"bg-level-1 flex-grow\">\n      <div class=\"c8y-nav-stacked\">\n        <opcua-server-list\n          [serverList]=\"serverObjectList\"\n          (present)=\"onPresent($event)\"\n        ></opcua-server-list>\n      </div>\n    </div>\n    <div class=\"card-footer separator sticky-bottom\">\n      <button\n        class=\"btn btn-default\"\n        title=\"{{ 'Add server' | translate }}\"\n        type=\"button\"\n        [disabled]=\"localServerObjectExist()\"\n        (click)=\"addServer()\"\n      >\n        <i [c8yIcon]=\"'plus-circle'\"></i>\n        {{ 'Add server' | translate }}\n      </button>\n    </div>\n  </div>\n\n  <opcua-server-config\n    class=\"inner-scroll split-view__detail\"\n    [ngClass]=\"{ 'split-view__detail--selected': server }\"\n    (canceled)=\"onCanceled($event)\"\n    (removed)=\"onRemoved($event)\"\n    (saved)=\"onSaved($event)\"\n    (updated)=\"onUpdated($event)\"\n    [server]=\"server\"\n  ></opcua-server-config>\n</div>\n" }]
        }], ctorParameters: () => [{ type: OpcuaService }, { type: i2$1.AlertService }, { type: i3.TranslateService }, { type: i2$1.ContextRouteComponent, decorators: [{
                    type: Optional
                }] }] });

const opcuaRoutes = [
    {
        context: ViewContext.Device,
        path: 'opcua-servers',
        component: OpcuaServersComponent,
        label: gettext('OPC UA server'),
        icon: 'server',
        canActivate: [OpcuaAgentGuard, OpcuaMicroserviceGuard]
    },
    {
        context: ViewContext.Device,
        path: 'address-space',
        component: OpcuaAddressSpaceComponent,
        label: gettext('Address space'),
        icon: 'cloud-network',
        canActivate: [OpcuaServerGuard, OpcuaMicroserviceGuard]
    }
];
const deviceProtocolRoutes = [
    {
        path: 'deviceprotocols/opcuaV2/:id',
        component: OpcuaDeviceProtocolDetailComponent
    }
];
class OpcuaProtocolModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaProtocolModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: OpcuaProtocolModule, imports: [CoreModule,
            FormsModule$1,
            ReactiveFormsModule,
            DropAreaModule,
            ButtonsModule,
            CdkTreeModule, i2.RouterModule, i2$3.TooltipModule, i3$1.PopoverModule, DeviceStatusModule,
            OperationDetailsModule,
            BrowserAnimationsModule, i4$1.CollapseModule, i5.BsDropdownModule, ObjectMappingComponent,
            DynamicFormsModule,
            OpcuaServersComponent,
            OpcuaServerListComponent,
            OpcuaServerConfigComponent,
            OpcuaAddressSpaceComponent,
            OpcuaAddressSpaceTreeComponent,
            OpcuaAddressSpaceDetailComponent,
            OpcuaDeviceProtocolDescription,
            OpcuaDeviceProtocolDetailComponent,
            OpcuaDeviceProtocolDataReportingComponent,
            OpcuaDeviceProtocolMapping,
            OpcuaDeviceProtocolObjectMappingStatus,
            OpcuaAutoApplySettingsComponent,
            OpcuaDeviceProtocolBrowsePathValidation] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaProtocolModule, providers: [
            OpcuaAgentGuard,
            OpcuaServerGuard,
            OpcuaMicroserviceGuard,
            OpcuaService,
            AddressSpaceService,
            hookRoute(opcuaRoutes)
        ], imports: [CoreModule,
            FormsModule$1,
            ReactiveFormsModule,
            DropAreaModule,
            ButtonsModule,
            CdkTreeModule,
            RouterModule.forChild(deviceProtocolRoutes),
            TooltipModule.forRoot(),
            PopoverModule.forRoot(),
            DeviceStatusModule,
            OperationDetailsModule,
            BrowserAnimationsModule,
            CollapseModule.forRoot(),
            BsDropdownModule.forRoot(),
            ObjectMappingComponent,
            DynamicFormsModule,
            OpcuaServersComponent,
            OpcuaServerListComponent,
            OpcuaServerConfigComponent,
            OpcuaAddressSpaceComponent,
            OpcuaAddressSpaceTreeComponent,
            OpcuaDeviceProtocolDescription,
            OpcuaDeviceProtocolDetailComponent,
            OpcuaDeviceProtocolDataReportingComponent,
            OpcuaDeviceProtocolMapping,
            OpcuaAutoApplySettingsComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: OpcuaProtocolModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CoreModule,
                        FormsModule$1,
                        ReactiveFormsModule,
                        DropAreaModule,
                        ButtonsModule,
                        CdkTreeModule,
                        RouterModule.forChild(deviceProtocolRoutes),
                        TooltipModule.forRoot(),
                        PopoverModule.forRoot(),
                        DeviceStatusModule,
                        OperationDetailsModule,
                        BrowserAnimationsModule,
                        CollapseModule.forRoot(),
                        BsDropdownModule.forRoot(),
                        ObjectMappingComponent,
                        DynamicFormsModule,
                        OpcuaServersComponent,
                        OpcuaServerListComponent,
                        OpcuaServerConfigComponent,
                        OpcuaAddressSpaceComponent,
                        OpcuaAddressSpaceTreeComponent,
                        OpcuaAddressSpaceDetailComponent,
                        OpcuaDeviceProtocolDescription,
                        OpcuaDeviceProtocolDetailComponent,
                        OpcuaDeviceProtocolDataReportingComponent,
                        OpcuaDeviceProtocolMapping,
                        OpcuaDeviceProtocolObjectMappingStatus,
                        OpcuaAutoApplySettingsComponent,
                        OpcuaDeviceProtocolBrowsePathValidation
                    ],
                    providers: [
                        OpcuaAgentGuard,
                        OpcuaServerGuard,
                        OpcuaMicroserviceGuard,
                        OpcuaService,
                        AddressSpaceService,
                        hookRoute(opcuaRoutes)
                    ]
                }]
        }] });

const opcuaAddressSpaceTreeComponentDowngradedComponent = downgradeComponent({
    component: OpcuaAddressSpaceTreeComponent,
    inputs: ['moId'],
    outputs: ['selectedNode']
});

const NAME_OPCUA = 'c8y.upgrade.opcua';
angular
    .module(NAME_OPCUA, [])
    .directive('c8yOpcuaAddressSpaceTree', opcuaAddressSpaceTreeComponentDowngradedComponent);
const ng1ModulesOPCUA = [NAME_OPCUA];
registerNgModule(ng1ModulesOPCUA);

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

export { AddressSpaceService, DynamicDataSource, NEW_SERVER_ID, OpcuaAddressSpaceComponent, OpcuaAddressSpaceDetailComponent, OpcuaAddressSpaceTreeComponent, OpcuaAgentGuard, OpcuaAutoApplySettingsComponent, OpcuaDeviceProtocolBrowsePathValidation, OpcuaDeviceProtocolDataReportingComponent, OpcuaDeviceProtocolDescription, OpcuaDeviceProtocolDetailComponent, OpcuaDeviceProtocolMapping, OpcuaDeviceProtocolObjectMappingStatus, OpcuaMicroserviceGuard, OpcuaProtocolModule, OpcuaServerConfigComponent, OpcuaServerGuard, OpcuaServerListComponent, OpcuaServersComponent, OpcuaService, ng1ModulesOPCUA };
//# sourceMappingURL=c8y-ngx-components-protocol-opcua.mjs.map