UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

759 lines (752 loc) 68.5 kB
import * as i0 from '@angular/core'; import { Component, inject, ViewContainerRef, ViewChild } from '@angular/core'; import { LWM2MEndpoint, permissionAlert, BinaryEncoding, SerializationFormat, AutoManageAvailabilty, FWU_DeliveryMethod, FWU_SupportedDeviceProtocol, FWU_ResetMechanism, Mode, CertificateUsage, BindingMode, ValidationType } from '@c8y/ngx-components/protocol-lwm2m/model'; import * as i2 from '@angular/router'; import { RouterModule, Router, ActivatedRoute } from '@angular/router'; import * as i1 from '@c8y/ngx-components/protocol-lwm2m/services'; import { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly'; import { CdkTreeModule } from '@angular/cdk/tree'; import * as i2$1 from '@c8y/ngx-components'; import { gettext, CoreModule, Permissions, AlertService } from '@c8y/ngx-components'; import * as i3 from '@angular/common'; import * as i5 from '@angular/forms'; import { FormGroup } from '@angular/forms'; import * as i4 from '@ngx-formly/core'; import { FormlyFormBuilder } from '@ngx-formly/core'; import { Subject, map, delay, of } from 'rxjs'; import { takeUntil, filter, map as map$1, delay as delay$1, catchError } from 'rxjs/operators'; class Lwm2mConfigurationComponent { constructor(lwm2mConfigService, route) { this.lwm2mConfigService = lwm2mConfigService; this.route = route; this.lwm2mConfigService.deviceId = this.route?.snapshot?.parent?.params?.id; this.tabs = [ { icon: 'cog', label: gettext('Device settings'), path: this.getPath(LWM2MEndpoint.deviceSettings) }, { icon: 'connected', label: gettext('Connectivity'), path: this.getPath(LWM2MEndpoint.connectivity) }, { icon: 'c8y-firmware', label: gettext('Firmware update'), path: this.getPath(LWM2MEndpoint.firmware) }, { icon: 'root-server', label: gettext('Bootstrap'), path: this.getPath(LWM2MEndpoint.bootstrap) }, { icon: 'stack', label: gettext('Servers written during bootstrap'), path: this.getPath(LWM2MEndpoint.servers) } ]; this.lwm2mConfigService.getSecurityModes(); } onActivate(event) { this.componentInstance = event; } getPath(endpoint) { const { deviceId } = this.lwm2mConfigService; return `/device/${deviceId}/lwm2m-configuration/${endpoint}`; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mConfigurationComponent, deps: [{ token: i1.Lwm2mConfigurationService }, { token: i2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mConfigurationComponent, isStandalone: true, selector: "c8y-lwm2m-configuration", ngImport: i0, template: "<div class=\"card content-fullpage d-col\">\n <div class=\"card-header p-0\">\n <c8y-ui-tabs\n class=\"card-has-tabs card-tabs\"\n [tabs]=\"tabs\"\n [orientation]=\"'horizontal'\"\n ></c8y-ui-tabs>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <form class=\"card-block--formly fit-h\">\n <router-outlet (activate)=\"onActivate($event)\"></router-outlet>\n </form>\n </div>\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"componentInstance?.fields?.length > 0\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"componentInstance.cancel()\"\n [disabled]=\"!componentInstance.form.dirty\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"componentInstance.form.invalid || !componentInstance.form.dirty\"\n (click)=\"componentInstance.save()\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen", "outletName", "context", "openFirstTab", "hasHeader"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }, { kind: "ngmodule", type: CdkTreeModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mConfigurationComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-lwm2m-configuration', imports: [CoreModule, Lwm2mUIThemeModule, CdkTreeModule, RouterModule], standalone: true, template: "<div class=\"card content-fullpage d-col\">\n <div class=\"card-header p-0\">\n <c8y-ui-tabs\n class=\"card-has-tabs card-tabs\"\n [tabs]=\"tabs\"\n [orientation]=\"'horizontal'\"\n ></c8y-ui-tabs>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <form class=\"card-block--formly fit-h\">\n <router-outlet (activate)=\"onActivate($event)\"></router-outlet>\n </form>\n </div>\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"componentInstance?.fields?.length > 0\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"componentInstance.cancel()\"\n [disabled]=\"!componentInstance.form.dirty\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"componentInstance.form.invalid || !componentInstance.form.dirty\"\n (click)=\"componentInstance.save()\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }, { type: i2.ActivatedRoute }] }); class Lwm2mFormWrapperBase { constructor(service) { this.service = service; this.destroy$ = new Subject(); this.model = {}; this.form = new FormGroup({}); this.fields = []; this.buttons = {}; this.options = { formState: { disabled: false } }; this.cancel = () => { this.options.resetModel(); this.service.getSettingsFor({ endpoint: this.endpoint }); }; this.fields = this.createForm(); inject(FormlyFormBuilder)?.buildForm(this.form, this.fields, this.model, this.options); if (!inject(Permissions)?.hasRole(Permissions.ROLE_INVENTORY_ADMIN)) { this.alertService = inject(AlertService); this.alertService.info(permissionAlert.text); this.form.disable(); this.options.formState.disabled = true; } } ngOnInit() { this.service.settings$.pipe(takeUntil(this.destroy$)).subscribe(next => (this.model = next)); this.service.getSettingsFor({ endpoint: this.endpoint }); } ngOnDestroy() { this.alertService?.remove(permissionAlert); this.destroy$.next(); this.destroy$.complete(); } save() { this.form.markAsPristine(); this.form.markAsUntouched(); this.service.updateConfig(this.model, this.endpoint); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormWrapperBase, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormWrapperBase, isStandalone: true, selector: "c8y-lwm2m-form-wrapper-base", ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormWrapperBase, decorators: [{ type: Component, args: [{ imports: [CoreModule, Lwm2mUIThemeModule], standalone: true, selector: 'c8y-lwm2m-form-wrapper-base', template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }] }); class Lwm2mFormBootstrapSettings extends Lwm2mFormWrapperBase { constructor(service) { super(service); this.service = service; this.endpoint = LWM2MEndpoint.bootstrap; } createForm() { return [ { fieldGroup: [ { key: 'bootstrapServerId', type: 'number', props: { label: gettext('Bootstrap Server ID'), placeholder: '1', min: 0 } }, { key: 'securityInstanceOffset', type: 'number', props: { label: gettext('Security instance offset'), placeholder: '1', min: 0 } } ] } ]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormBootstrapSettings, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormBootstrapSettings, isStandalone: true, selector: "c8y-lwm2m-form-bootstrap-settings", usesInheritance: true, ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormBootstrapSettings, decorators: [{ type: Component, args: [{ imports: [CoreModule, Lwm2mUIThemeModule], standalone: true, selector: 'c8y-lwm2m-form-bootstrap-settings', template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }] }); class Lwm2mFormConnectivitySettings extends Lwm2mFormWrapperBase { constructor(service) { super(service); this.service = service; this.endpoint = LWM2MEndpoint.connectivity; } createForm() { const selects = [ { key: 'bootstrapConnectivity', label: gettext('Bootstrap server authentication'), options: this.service.securityModesRaw$.pipe(map(dictObjs => dictObjs.filter(o => o?.useInBootstrapConnectivity)), delay(1)) }, { key: 'serverConnectivity', label: gettext('Server authentication'), options: this.service.securityModesRaw$.pipe(map(dictObjs => dictObjs.filter(o => o?.useInServerConnectivity)), delay(1)) } ]; return [ { fieldGroup: [ ...selects.map(select => ({ key: select.key, wrappers: ['legend'], props: { label: select.label }, fieldGroup: [ { type: '#securityMode', props: { options: select.options } }, { type: '#pskId' }, { type: '#pskKey' } ] })) ] } ]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormConnectivitySettings, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormConnectivitySettings, isStandalone: true, selector: "c8y-lwm2m-form-connectivity-settings", usesInheritance: true, ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormConnectivitySettings, decorators: [{ type: Component, args: [{ imports: [CoreModule, Lwm2mUIThemeModule], standalone: true, selector: 'c8y-lwm2m-form-connectivity-settings', template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }] }); class Lwm2mFormDeviceSettings extends Lwm2mFormWrapperBase { constructor(service) { super(service); this.service = service; this.endpoint = LWM2MEndpoint.deviceSettings; } createForm() { return [ { fieldGroup: [ { key: 'endpointId', type: 'string', props: { label: gettext('Endpoint client ID'), required: true } }, { key: 'awakeTime', type: 'number', props: { label: gettext('Awake time registration parameter'), description: gettext('in milliseconds, 0 means device is always online'), placeholder: '0', min: 0 } }, { key: 'requestTimeout', type: 'number', props: { label: gettext('LWM2M request timeout'), description: gettext('in milliseconds'), placeholder: '180000', min: 0 } }, { key: 'binaryEncoding', type: 'select', defaultValue: BinaryEncoding.OPAQUE, props: { label: gettext('Binary delivery encoding'), options: Object.values(BinaryEncoding).map(value => ({ label: value, value })) } }, { key: 'serializationFormat', type: 'select', props: { label: gettext('Serialization format'), placeholder: gettext('Default device value'), options: [ ...Object.values(SerializationFormat).map(value => ({ label: value, value })) ], description: gettext('Indicates the preferred content format for LWM2M Agent to use to communicate with the device.'), acceptUndefined: true, removeExempliGratia: true } }, { key: 'useTimestampResources', type: 'switch', defaultValue: false, props: { label: gettext('Use source timestamp'), description: gettext('LWM2M offers various methods for associating timestamp information with data points, including resources 5518 and 6050, SenML, or resource 5 for the location object (6). When activated, the LWM2M agent utilizes this timestamp data source to generate measurements, events, or alarms. If deactivated, the LWM2M agent resorts to using its local time.') } }, { key: 'keepOldValuesOnOperationFail', type: 'switch', defaultValue: false, props: { label: gettext('Keep old values'), description: gettext('Keep old values in the objects tab if an operation fails') } }, { key: 'disableObjectInstanceActions', type: 'switch', defaultValue: false, props: { label: gettext('Disable default behavior for object instances'), description: gettext('Turns off the internal default handling of objects 3, 4 and 6') } }, { key: 'autoManageAvailabilityRequiredInterval', type: 'select', defaultValue: null, props: { label: gettext('Set the required interval automatically'), options: [ { label: gettext('Default'), value: null }, ...Object.entries(AutoManageAvailabilty).map(entry => { return { label: gettext(entry[0]), value: !!+entry[1] }; }) ], description: gettext('When enabled, the LWM2M service automatically sets the interval to registration lifetime plus 2 minutes.') } } ] } ]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormDeviceSettings, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormDeviceSettings, isStandalone: true, selector: "c8y-lwm2m-form-device-settings", usesInheritance: true, ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormDeviceSettings, decorators: [{ type: Component, args: [{ imports: [CoreModule, Lwm2mUIThemeModule], standalone: true, selector: 'c8y-lwm2m-form-device-settings', template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }] }); class Lwm2mFormFirmwareSettings extends Lwm2mFormWrapperBase { constructor(service) { super(service); this.service = service; this.endpoint = LWM2MEndpoint.firmware; } createForm() { const selects = [ { key: 'firmwareDeliveryMethod', label: gettext('Update`verb` delivery method'), _enum: FWU_DeliveryMethod }, { key: 'supportedDeviceProtocol', label: gettext('Update`verb` supported device protocol'), _enum: FWU_SupportedDeviceProtocol }, { key: 'resetMethod', label: gettext('Update`verb` reset mechanism'), _enum: FWU_ResetMechanism } ]; return [ { fieldGroup: [ { key: 'disableFirmwareStateMachine', type: 'switch', defaultValue: false, props: { label: gettext('Disable automated firmware update support'), description: gettext('Turns off the internal firmware update state machine') } }, { key: 'url', type: 'string', props: { label: gettext('Update`noun` URL'), placeholder: 'firmware-image-url', description: gettext('If not specified, LWM2M Agent generates the URL') }, expressions: { hide: 'model.disableFirmwareStateMachine' } }, { key: 'resetStateMachineOnStart', type: 'switch', defaultValue: false, props: { label: gettext('Always reset firmware state machine'), description: gettext('Controls if the LWM2M Agent performs an initial state machine reset before it starts a firmware update') }, expressions: { hide: 'model.disableFirmwareStateMachine' } }, ...selects.map(select => ({ key: select.key, type: 'select', props: { label: select.label, placeholder: gettext('Default device value'), options: Object.values(select._enum).map(value => ({ label: value, value })), acceptUndefined: true, removeExempliGratia: true }, expressions: { hide: 'model.disableFirmwareStateMachine' } })), { key: 'failOnStateAndResultIncompatibility', type: 'switch', defaultValue: false, props: { label: gettext('Fail device firmware update on unexpected result'), description: gettext('If the configuration is enabled, the firmware update operation will fail if the update result (resource 5) is not as expected based on the LWM2M firmware state machine.') } } ] } ]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormFirmwareSettings, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormFirmwareSettings, isStandalone: true, selector: "c8y-lwm2m-form-firmware-settings", usesInheritance: true, ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: Lwm2mUIThemeModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormFirmwareSettings, decorators: [{ type: Component, args: [{ imports: [CoreModule, Lwm2mUIThemeModule], standalone: true, selector: 'c8y-lwm2m-form-firmware-settings', template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.Lwm2mConfigurationService }] }); class Lwm2mFormSingleServerSettings extends Lwm2mFormWrapperBase { constructor(service) { super(service); this.service = service; this.endpoint = LWM2MEndpoint.servers; this.COAP = 'coap://'; this.COAPS = 'coaps://'; this.cancel = () => this.router.navigate(['../servers'], { relativeTo: this.route }); this.router = inject(Router); this.route = inject(ActivatedRoute); this.alert = inject(AlertService); } ngOnInit() { this.service.settings$.pipe(takeUntil(this.destroy$)).subscribe(data => (this.model = data)); this.service.getSettingsFor({ endpoint: this.endpoint, id: this.id }); } createForm() { return [ { wrappers: ['legend'], fieldGroup: [ { key: 'bootstrap', type: 'switch', defaultValue: false, props: { label: gettext('Bootstrap server'), description: gettext('This configuration is for a bootstrap server') } }, { key: 'uri', type: 'input-addon', props: { label: gettext('Server URI'), addonLabel: this.COAP, required: true, placeholder: '<LWM2M-server-domain>:<coap(s)-port>' }, hooks: { onInit: (field) => { field.props.addonLabel = this.COAP; return field.options.fieldChanges.pipe(filter(e => e.type === 'valueChanges' && (e.field === field || e.field.key === 'mode')), map$1(e => { if (e.field.key === 'uri') field.formControl.setValue((e.value || '').replace(/^.*:\/\//i, '')); field.props.addonLabel = field.model?.security?.mode === Mode.NO_SEC ? this.COAP : this.COAPS; return e; })); } } }, { key: 'security', wrappers: ['legend'], props: { label: 'Security' }, fieldGroup: [ { type: '#securityMode', hooks: { onInit: (field) => { field.props.options = this.service.securityModesByScope$.pipe(delay$1(1)); this.service.getSecurityModeByScope('useInServerConnectivity'); return field.options.fieldChanges.pipe(filter(e => e.type === 'valueChanges' && e.field.key === 'bootstrap'), map$1(e => { if (e.value) { this.service.getSecurityModeByScope('useInBootstrapConnectivity'); if (field.model?.mode === Mode.X509_EST) { field.formControl.setValue(Mode.NO_SEC); } } else { this.service.getSecurityModeByScope('useInServerConnectivity'); } return e; })); } } }, { type: '#pskId' }, { type: '#pskKey' }, { key: 'x509ServerCertificateName', type: 'select', props: { label: gettext('Server certificate'), placeholder: gettext('Not written`setting`'), acceptUndefined: true, removeExempliGratia: true, options: this.service.certificates$.pipe(map$1(certs => certs.map(value => ({ label: value, value })))) }, expressions: { 'props.disabled': (field) => field?.options?.formState?.disabled, hide: (field) => { return field.model?.mode !== Mode.X509 && field.model?.mode !== Mode.X509_EST; } } }, { key: 'certificateUsage', type: 'select', props: { label: gettext('Certificate usage'), placeholder: gettext('Not written`setting`'), acceptUndefined: true, removeExempliGratia: true, options: Object.values(CertificateUsage).map(value => ({ label: value, value })) }, expressions: { 'props.disabled': (field) => field?.options?.formState?.disabled, hide: (field) => { return field.model?.mode !== Mode.X509 && field.model?.mode !== Mode.X509_EST; } } }, { key: 'certificateDropArea', type: 'file', props: { accept: 'pem', label: gettext('Certificate'), description: gettext('One .pem file may be uploaded'), forceHideList: true, dropped: async (files) => this.patchCommonName(this.service.cleanUpBase64Data((await files?.pop()?.readAsDataURL()))) }, expressions: { hide: (field) => { return (field.model?.mode !== Mode.X509 || !!field.model?.x509CertificateCommonName); } } }, { key: 'x509CertificateCommonName', type: 'file-pick-replace', props: { label: gettext('Certificate Common Name'), remove: () => this.removeCertificateAndCommonName(), onPick: certificate => this.patchCommonName(certificate) }, expressions: { 'props.disabled': (field) => field?.options?.formState?.disabled, hide: (field) => { return (field.model?.mode !== Mode.X509 || !field.model?.x509CertificateCommonName); } } }, { key: 'privateKeyDropArea', type: 'file', props: { accept: 'pem', label: gettext('Private key'), description: gettext('One .pem file may be uploaded'), forceHideList: true, disabled: true, dropped: async (files) => this.patchFingerprint(this.service.cleanUpBase64Data((await files?.pop()?.readAsDataURL()))) }, expressions: { 'props.disabled': (field) => field?.options?.formState?.disabled, hide: (field) => { return (field.model?.mode !== Mode.X509 || !!field.model?.x509PrivateKeyFingerPrint); } } }, { key: 'x509PrivateKeyFingerPrint', type: 'file-pick-replace', props: { label: gettext('Fingerprint of the private key'), remove: () => this.removePrivateKeyAndFingerprint(), onPick: privateKey => this.patchFingerprint(privateKey) }, expressions: { 'props.disabled': (field) => field?.options?.formState?.disabled, hide: (field) => { return (field.model?.mode !== Mode.X509 || !field.model?.x509PrivateKeyFingerPrint); } } } ] }, { wrappers: ['legend'], props: { label: gettext('Server object configuration') }, fieldGroup: [ { key: 'storeNotifications', type: 'switch', defaultValue: false, props: { label: gettext('Store notifications'), description: gettext('LWM2M Client to store notify operations when client is offline or LWM2M Server is disabled. Also used to forward them to the LWM2M Server when the client is able to connect.') } }, { key: 'shortServerId', type: 'number', props: { label: gettext('Short Server ID'), description: gettext('in numbers'), placeholder: '1', min: 0 } }, { key: 'registrationLifetime', type: 'number', props: { label: gettext('Registration lifetime'), description: gettext('in seconds'), placeholder: '600', min: 0 } }, { key: 'defaultMinPeriod', type: 'number', props: { label: gettext('Default minimum period'), description: gettext('in seconds'), placeholder: '10', min: 0 } }, { key: 'defaultMaxPeriod', type: 'number', props: { label: gettext('Default maximum period'), description: gettext('in seconds'), placeholder: '60', min: 0 } }, { key: 'bindingMode', type: 'select', defaultValue: BindingMode.U, props: { label: gettext('Binding mode'), options: Object.values(BindingMode).map(value => ({ label: value === BindingMode.U ? gettext('UDP') : gettext('UDP with queue mode'), value })) } }, { key: 'disableTimeout', type: 'number', props: { label: gettext('Disable timeout'), description: gettext('in seconds'), placeholder: '86400', min: 0 } } ] } ] } ]; } save() { this.service .update$({ ...this.model, uri: this.getFullURI(), endpoint: LWM2MEndpoint.servers }) .pipe(catchError(err => { this.alert.addServerFailure(err); return of(null); })) .subscribe(_next => this.cancel()); } delete() { this.service .deleteServer$(this.model) .pipe(catchError(err => { this.alert.addServerFailure(err); return of(null); })) .subscribe(_next => this.cancel()); } getFullURI() { const { uri, security: { mode = Mode.NO_SEC } } = this.model; return (mode === Mode.NO_SEC ? this.COAP : this.COAPS).concat(uri); } patchFingerprint(privateKey) { if (privateKey?.length > 0) { this.service .validate(privateKey, ValidationType.PRIVATE_KEY) .pipe(takeUntil(this.destroy$)) .subscribe(fingerprint => { this.model.security.x509PrivateKey = privateKey; this.model.security.x509PrivateKeyFingerPrint = fingerprint; this.form.patchValue(this.model); this.form.markAsDirty(); }, _error => { // already catched }); } } patchCommonName(certificate) { if (certificate?.length > 0) { this.service .validate(certificate, ValidationType.X509) .pipe(takeUntil(this.destroy$)) .subscribe(commonName => { this.model.security.x509Certificate = certificate; this.model.security.x509CertificateCommonName = commonName; this.form.patchValue(this.model); this.form.markAsDirty(); }, _error => { // already catched }); } } removePrivateKeyAndFingerprint() { this.form.patchValue({ security: { x509PrivateKey: null, x509PrivateKeyFingerPrint: null } }); delete this.model?.security?.x509PrivateKey; delete this.model?.security?.x509PrivateKeyFingerPrint; this.form.markAsDirty(); } removeCertificateAndCommonName() { this.form.patchValue({ security: { x509Certificate: null, x509CertificateCommonName: null } }); delete this.model?.security?.x509CertificateCommonName; delete this.model?.security?.x509Certificate; this.form.markAsDirty(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Lwm2mFormSingleServerSettings, deps: [{ token: i1.Lwm2mConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: Lwm2mFormSingleServerSettings, isStandalone: true, selector: "c8y-lwm2m-form-single-server-settings", usesInheritance: true, ngImport: i0, template: "<formly-form\n *ngIf=\"fields?.length > 0; else empty\"\n [model]=\"model\"\n [form]=\"form\"\n [fields]=\"fields\"\n [options]=\"options\"\n data-cy=\"lwm2m-device-configuration--formly-form\"\n></formly-form>\n<ng-template #empty>\n <c8y-ui-empty-state\n [icon]=\"'c8y-device-protocols'\"\n title=\"{{ 'No configuration selected' | translate }}\"\n subtitle=\"{{ 'Select a configuration on the left' | translate }}\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2$1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: i2$1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.N