@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
1 lines • 75.9 kB
Source Map (JSON)
{"version":3,"file":"c8y-ngx-components-protocol-lwm2m-components-configuration.mjs","sources":["../../protocol-lwm2m/components/configuration/lwm2m-configuration.component.ts","../../protocol-lwm2m/components/configuration/lwm2m-configuration.component.html","../../protocol-lwm2m/components/configuration/typed-forms/form-wrapper-base.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/form-wrapper-base.component.html","../../protocol-lwm2m/components/configuration/typed-forms/bootstrap-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/connectivity-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/device-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/firmware-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/single-server-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/create-single-server-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/servers-settings.component.ts","../../protocol-lwm2m/components/configuration/typed-forms/server-settings.component.html","../../protocol-lwm2m/components/configuration/c8y-ngx-components-protocol-lwm2m-components-configuration.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { LWM2MEndpoint, Settings } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { ActivatedRoute, RouterModule } from '@angular/router';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { CdkTreeModule } from '@angular/cdk/tree';\nimport { CoreModule, Tab, gettext } from '@c8y/ngx-components';\nimport { IIdentified } from '@c8y/client';\nimport { Lwm2mFormWrapperBase } from './typed-forms';\n\n@Component({\n selector: 'c8y-lwm2m-configuration',\n templateUrl: './lwm2m-configuration.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule, CdkTreeModule, RouterModule],\n standalone: true\n})\nexport class Lwm2mConfigurationComponent {\n tabs: Tab[];\n componentInstance: Lwm2mFormWrapperBase<Settings>;\n\n constructor(\n private lwm2mConfigService: Lwm2mConfigurationService<IIdentified>,\n private route: ActivatedRoute\n ) {\n this.lwm2mConfigService.deviceId = this.route?.snapshot?.parent?.params?.id;\n\n this.tabs = [\n {\n icon: 'cog',\n label: gettext('Device settings'),\n path: this.getPath(LWM2MEndpoint.deviceSettings)\n },\n {\n icon: 'connected',\n label: gettext('Connectivity'),\n path: this.getPath(LWM2MEndpoint.connectivity)\n },\n {\n icon: 'c8y-firmware',\n label: gettext('Firmware update'),\n path: this.getPath(LWM2MEndpoint.firmware)\n },\n {\n icon: 'root-server',\n label: gettext('Bootstrap'),\n path: this.getPath(LWM2MEndpoint.bootstrap)\n },\n {\n icon: 'stack',\n label: gettext('Servers written during bootstrap'),\n path: this.getPath(LWM2MEndpoint.servers)\n }\n ];\n\n this.lwm2mConfigService.getSecurityModes();\n }\n\n onActivate(event) {\n this.componentInstance = event;\n }\n\n private getPath(endpoint: LWM2MEndpoint) {\n const { deviceId } = this.lwm2mConfigService;\n return `/device/${deviceId}/lwm2m-configuration/${endpoint}`;\n }\n}\n","<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","import { Component, OnDestroy, OnInit, inject } from '@angular/core';\nimport { AlertService, CoreModule, Permissions } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { FormlyFieldConfig, FormlyFormBuilder, FormlyFormOptions } from '@ngx-formly/core';\nimport { LWM2MEndpoint, permissionAlert } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { FormGroup } from '@angular/forms';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-wrapper-base'\n})\nexport abstract class Lwm2mFormWrapperBase<T> implements OnInit, OnDestroy {\n private alertService: AlertService;\n protected abstract endpoint: LWM2MEndpoint;\n protected destroy$: Subject<void> = new Subject();\n\n model = {} as T;\n form = new FormGroup({});\n fields: FormlyFieldConfig[] = [];\n buttons = {};\n options: FormlyFormOptions = {\n formState: { disabled: false }\n };\n\n constructor(protected service: Lwm2mConfigurationService<T>) {\n this.fields = this.createForm();\n\n inject(FormlyFormBuilder)?.buildForm(this.form, this.fields, this.model, this.options);\n\n if (!inject(Permissions)?.hasRole(Permissions.ROLE_INVENTORY_ADMIN)) {\n this.alertService = inject(AlertService);\n this.alertService.info(permissionAlert.text as string);\n this.form.disable();\n this.options.formState.disabled = true;\n }\n }\n\n abstract createForm(): FormlyFieldConfig[];\n\n ngOnInit(): void {\n this.service.settings$.pipe(takeUntil(this.destroy$)).subscribe(next => (this.model = next));\n this.service.getSettingsFor({ endpoint: this.endpoint });\n }\n\n ngOnDestroy(): void {\n this.alertService?.remove(permissionAlert);\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n save() {\n this.form.markAsPristine();\n this.form.markAsUntouched();\n this.service.updateConfig(this.model, this.endpoint);\n }\n\n cancel = () => {\n this.options.resetModel();\n this.service.getSettingsFor({ endpoint: this.endpoint });\n };\n}\n","<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","import { Component } from '@angular/core';\nimport { CoreModule, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { BootstrapSettings, LWM2MEndpoint } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mFormWrapperBase } from './form-wrapper-base.component';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-bootstrap-settings'\n})\nexport class Lwm2mFormBootstrapSettings extends Lwm2mFormWrapperBase<BootstrapSettings> {\n protected endpoint: LWM2MEndpoint = LWM2MEndpoint.bootstrap;\n constructor(protected service: Lwm2mConfigurationService<BootstrapSettings>) {\n super(service);\n }\n\n createForm() {\n return [\n {\n fieldGroup: [\n {\n key: 'bootstrapServerId',\n type: 'number',\n props: {\n label: gettext('Bootstrap Server ID'),\n placeholder: '1',\n min: 0\n }\n },\n {\n key: 'securityInstanceOffset',\n type: 'number',\n props: {\n label: gettext('Security instance offset'),\n placeholder: '1',\n min: 0\n }\n }\n ]\n }\n ];\n }\n}\n","import { Component } from '@angular/core';\nimport { CoreModule, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { ConnectivitySettings, LWM2MEndpoint } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mFormWrapperBase } from './form-wrapper-base.component';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\nimport { delay, map } from 'rxjs';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-connectivity-settings'\n})\nexport class Lwm2mFormConnectivitySettings extends Lwm2mFormWrapperBase<ConnectivitySettings> {\n protected endpoint: LWM2MEndpoint = LWM2MEndpoint.connectivity;\n constructor(protected service: Lwm2mConfigurationService<ConnectivitySettings>) {\n super(service);\n }\n\n createForm() {\n const selects = [\n {\n key: 'bootstrapConnectivity',\n label: gettext('Bootstrap server authentication'),\n options: this.service.securityModesRaw$.pipe(\n map(dictObjs => dictObjs.filter(o => o?.useInBootstrapConnectivity)),\n delay(1)\n )\n },\n {\n key: 'serverConnectivity',\n label: gettext('Server authentication'),\n options: this.service.securityModesRaw$.pipe(\n map(dictObjs => dictObjs.filter(o => o?.useInServerConnectivity)),\n delay(1)\n )\n }\n ];\n\n return [\n {\n fieldGroup: [\n ...selects.map(select => ({\n key: select.key,\n wrappers: ['legend'],\n props: {\n label: select.label\n },\n fieldGroup: [\n {\n type: '#securityMode',\n props: {\n options: select.options\n }\n },\n { type: '#pskId' },\n { type: '#pskKey' }\n ]\n }))\n ]\n }\n ];\n }\n}\n","import { Component } from '@angular/core';\nimport { CoreModule, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport {\n AutoManageAvailabilty,\n BinaryEncoding,\n DeviceSettings,\n LWM2MEndpoint,\n SerializationFormat\n} from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mFormWrapperBase } from './form-wrapper-base.component';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-device-settings'\n})\nexport class Lwm2mFormDeviceSettings extends Lwm2mFormWrapperBase<DeviceSettings> {\n protected endpoint: LWM2MEndpoint = LWM2MEndpoint.deviceSettings;\n constructor(protected service: Lwm2mConfigurationService<DeviceSettings>) {\n super(service);\n }\n\n createForm() {\n return [\n {\n fieldGroup: [\n {\n key: 'endpointId',\n type: 'string',\n props: {\n label: gettext('Endpoint client ID'),\n required: true\n }\n },\n {\n key: 'awakeTime',\n type: 'number',\n props: {\n label: gettext('Awake time registration parameter'),\n description: gettext('in milliseconds, 0 means device is always online'),\n placeholder: '0',\n min: 0\n }\n },\n {\n key: 'requestTimeout',\n type: 'number',\n props: {\n label: gettext('LWM2M request timeout'),\n description: gettext('in milliseconds'),\n placeholder: '180000',\n min: 0\n }\n },\n {\n key: 'binaryEncoding',\n type: 'select',\n defaultValue: BinaryEncoding.OPAQUE,\n props: {\n label: gettext('Binary delivery encoding'),\n options: Object.values(BinaryEncoding).map(value => ({ label: value, value }))\n }\n },\n {\n key: 'serializationFormat',\n type: 'select',\n props: {\n label: gettext('Serialization format'),\n placeholder: gettext('Default device value'),\n options: [\n ...Object.values(SerializationFormat).map(value => ({ label: value, value }))\n ],\n description: gettext(\n 'Indicates the preferred content format for LWM2M Agent to use to communicate with the device.'\n ),\n acceptUndefined: true,\n removeExempliGratia: true\n }\n },\n {\n key: 'useTimestampResources',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Use source timestamp'),\n description: gettext(\n '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.'\n )\n }\n },\n {\n key: 'keepOldValuesOnOperationFail',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Keep old values'),\n description: gettext('Keep old values in the objects tab if an operation fails')\n }\n },\n {\n key: 'disableObjectInstanceActions',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Disable default behavior for object instances'),\n description: gettext('Turns off the internal default handling of objects 3, 4 and 6')\n }\n },\n {\n key: 'autoManageAvailabilityRequiredInterval',\n type: 'select',\n defaultValue: null,\n props: {\n label: gettext('Set the required interval automatically'),\n options: [\n { label: gettext('Default'), value: null },\n ...Object.entries(AutoManageAvailabilty).map(entry => {\n return { label: gettext(entry[0]), value: !!+entry[1] };\n })\n ],\n description: gettext(\n 'When enabled, the LWM2M service automatically sets the interval to registration lifetime plus 2 minutes.'\n )\n }\n }\n ]\n }\n ];\n }\n}\n","import { Component } from '@angular/core';\nimport { CoreModule, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport {\n LWM2MEndpoint,\n FWU_DeliveryMethod,\n FWU_ResetMechanism,\n FWU_SupportedDeviceProtocol,\n FirmwareSettings\n} from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mFormWrapperBase } from './form-wrapper-base.component';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-firmware-settings'\n})\nexport class Lwm2mFormFirmwareSettings extends Lwm2mFormWrapperBase<FirmwareSettings> {\n protected endpoint = LWM2MEndpoint.firmware;\n constructor(protected service: Lwm2mConfigurationService<FirmwareSettings>) {\n super(service);\n }\n\n createForm() {\n const selects = [\n {\n key: 'firmwareDeliveryMethod',\n label: gettext('Update`verb` delivery method'),\n _enum: FWU_DeliveryMethod\n },\n {\n key: 'supportedDeviceProtocol',\n label: gettext('Update`verb` supported device protocol'),\n _enum: FWU_SupportedDeviceProtocol\n },\n {\n key: 'resetMethod',\n label: gettext('Update`verb` reset mechanism'),\n _enum: FWU_ResetMechanism\n }\n ];\n return [\n {\n fieldGroup: [\n {\n key: 'disableFirmwareStateMachine',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Disable automated firmware update support'),\n description: gettext('Turns off the internal firmware update state machine')\n }\n },\n {\n key: 'url',\n type: 'string',\n props: {\n label: gettext('Update`noun` URL'),\n placeholder: 'firmware-image-url',\n description: gettext('If not specified, LWM2M Agent generates the URL')\n },\n expressions: {\n hide: 'model.disableFirmwareStateMachine'\n }\n },\n {\n key: 'resetStateMachineOnStart',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Always reset firmware state machine'),\n description: gettext(\n 'Controls if the LWM2M Agent performs an initial state machine reset before it starts a firmware update'\n )\n },\n expressions: {\n hide: 'model.disableFirmwareStateMachine'\n }\n },\n ...selects.map(select => ({\n key: select.key,\n type: 'select',\n props: {\n label: select.label,\n placeholder: gettext('Default device value'),\n options: Object.values(select._enum).map(value => ({ label: value, value })),\n acceptUndefined: true,\n removeExempliGratia: true\n },\n expressions: {\n hide: 'model.disableFirmwareStateMachine'\n }\n })),\n {\n key: 'failOnStateAndResultIncompatibility',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Fail device firmware update on unexpected result'),\n description: gettext(\n '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.'\n )\n }\n }\n ]\n }\n ];\n }\n}\n","import { Component, OnInit, inject } from '@angular/core';\nimport { AlertService, CoreModule, DroppedFile, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\nimport { FormlyFieldConfig } from '@ngx-formly/core';\nimport {\n BindingMode,\n CertificateUsage,\n LWM2MEndpoint,\n Mode,\n Security,\n ServerSettings,\n ValidationType\n} from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mFormWrapperBase } from './form-wrapper-base.component';\nimport { catchError, delay, filter, map, takeUntil } from 'rxjs/operators';\nimport { ActivatedRoute, Router, RouterModule } from '@angular/router';\nimport { of } from 'rxjs';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule, RouterModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-single-server-settings'\n})\nexport class Lwm2mFormSingleServerSettings\n extends Lwm2mFormWrapperBase<ServerSettings>\n implements OnInit\n{\n id: string;\n protected endpoint: LWM2MEndpoint = LWM2MEndpoint.servers;\n protected alert: AlertService;\n private readonly COAP = 'coap://';\n private readonly COAPS = 'coaps://';\n private router: Router;\n private route: ActivatedRoute;\n\n constructor(protected service: Lwm2mConfigurationService<ServerSettings>) {\n super(service);\n this.router = inject(Router);\n this.route = inject(ActivatedRoute);\n this.alert = inject(AlertService);\n }\n\n ngOnInit(): void {\n this.service.settings$.pipe(takeUntil(this.destroy$)).subscribe(data => (this.model = data));\n this.service.getSettingsFor({ endpoint: this.endpoint, id: this.id });\n }\n\n createForm() {\n return [\n {\n wrappers: ['legend'],\n fieldGroup: [\n {\n key: 'bootstrap',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Bootstrap server'),\n description: gettext('This configuration is for a bootstrap server')\n }\n },\n {\n key: 'uri',\n type: 'input-addon',\n props: {\n label: gettext('Server URI'),\n addonLabel: this.COAP,\n required: true,\n placeholder: '<LWM2M-server-domain>:<coap(s)-port>'\n },\n hooks: {\n onInit: (field: FormlyFieldConfig) => {\n field.props.addonLabel = this.COAP;\n return field.options.fieldChanges.pipe(\n filter(\n e => e.type === 'valueChanges' && (e.field === field || e.field.key === 'mode')\n ),\n map(e => {\n if (e.field.key === 'uri')\n field.formControl.setValue(\n ((e.value as string) || '').replace(/^.*:\\/\\//i, '')\n );\n field.props.addonLabel =\n field.model?.security?.mode === Mode.NO_SEC ? this.COAP : this.COAPS;\n return e;\n })\n );\n }\n }\n },\n {\n key: 'security',\n wrappers: ['legend'],\n props: {\n label: 'Security'\n },\n fieldGroup: [\n {\n type: '#securityMode',\n hooks: {\n onInit: (field: FormlyFieldConfig) => {\n field.props.options = this.service.securityModesByScope$.pipe(delay(1));\n this.service.getSecurityModeByScope('useInServerConnectivity');\n return field.options.fieldChanges.pipe(\n filter(e => e.type === 'valueChanges' && e.field.key === 'bootstrap'),\n map(e => {\n if (e.value) {\n this.service.getSecurityModeByScope('useInBootstrapConnectivity');\n if (field.model?.mode === Mode.X509_EST) {\n field.formControl.setValue(Mode.NO_SEC);\n }\n } else {\n this.service.getSecurityModeByScope('useInServerConnectivity');\n }\n return e;\n })\n );\n }\n }\n },\n { type: '#pskId' },\n { type: '#pskKey' },\n {\n key: 'x509ServerCertificateName',\n type: 'select',\n props: {\n label: gettext('Server certificate'),\n placeholder: gettext('Not written`setting`'),\n acceptUndefined: true,\n removeExempliGratia: true,\n options: this.service.certificates$.pipe(\n map(certs => certs.map(value => ({ label: value, value })))\n )\n },\n expressions: {\n 'props.disabled': (field: FormlyFieldConfig) =>\n field?.options?.formState?.disabled,\n hide: (field: FormlyFieldConfig) => {\n return field.model?.mode !== Mode.X509 && field.model?.mode !== Mode.X509_EST;\n }\n }\n },\n {\n key: 'certificateUsage',\n type: 'select',\n props: {\n label: gettext('Certificate usage'),\n placeholder: gettext('Not written`setting`'),\n acceptUndefined: true,\n removeExempliGratia: true,\n options: Object.values(CertificateUsage).map(value => ({ label: value, value }))\n },\n expressions: {\n 'props.disabled': (field: FormlyFieldConfig) =>\n field?.options?.formState?.disabled,\n hide: (field: FormlyFieldConfig) => {\n return field.model?.mode !== Mode.X509 && field.model?.mode !== Mode.X509_EST;\n }\n }\n },\n {\n key: 'certificateDropArea',\n type: 'file',\n props: {\n accept: 'pem',\n label: gettext('Certificate'),\n description: gettext('One .pem file may be uploaded'),\n forceHideList: true,\n dropped: async (files: DroppedFile[]) =>\n this.patchCommonName(\n this.service.cleanUpBase64Data(\n (await files?.pop()?.readAsDataURL()) as string\n )\n )\n },\n expressions: {\n hide: (field: FormlyFieldConfig) => {\n return (\n field.model?.mode !== Mode.X509 || !!field.model?.x509CertificateCommonName\n );\n }\n }\n },\n {\n key: 'x509CertificateCommonName',\n type: 'file-pick-replace',\n props: {\n label: gettext('Certificate Common Name'),\n remove: () => this.removeCertificateAndCommonName(),\n onPick: certificate => this.patchCommonName(certificate)\n },\n expressions: {\n 'props.disabled': (field: FormlyFieldConfig) =>\n field?.options?.formState?.disabled,\n hide: (field: FormlyFieldConfig) => {\n return (\n field.model?.mode !== Mode.X509 || !field.model?.x509CertificateCommonName\n );\n }\n }\n },\n {\n key: 'privateKeyDropArea',\n type: 'file',\n props: {\n accept: 'pem',\n label: gettext('Private key'),\n description: gettext('One .pem file may be uploaded'),\n forceHideList: true,\n disabled: true,\n dropped: async (files: DroppedFile[]) =>\n this.patchFingerprint(\n this.service.cleanUpBase64Data(\n (await files?.pop()?.readAsDataURL()) as string\n )\n )\n },\n expressions: {\n 'props.disabled': (field: FormlyFieldConfig) =>\n field?.options?.formState?.disabled,\n hide: (field: FormlyFieldConfig) => {\n return (\n field.model?.mode !== Mode.X509 || !!field.model?.x509PrivateKeyFingerPrint\n );\n }\n }\n },\n {\n key: 'x509PrivateKeyFingerPrint',\n type: 'file-pick-replace',\n props: {\n label: gettext('Fingerprint of the private key'),\n remove: () => this.removePrivateKeyAndFingerprint(),\n onPick: privateKey => this.patchFingerprint(privateKey)\n },\n expressions: {\n 'props.disabled': (field: FormlyFieldConfig) =>\n field?.options?.formState?.disabled,\n hide: (field: FormlyFieldConfig) => {\n return (\n field.model?.mode !== Mode.X509 || !field.model?.x509PrivateKeyFingerPrint\n );\n }\n }\n }\n ]\n },\n {\n wrappers: ['legend'],\n props: {\n label: gettext('Server object configuration')\n },\n fieldGroup: [\n {\n key: 'storeNotifications',\n type: 'switch',\n defaultValue: false,\n props: {\n label: gettext('Store notifications'),\n description: gettext(\n '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.'\n )\n }\n },\n {\n key: 'shortServerId',\n type: 'number',\n props: {\n label: gettext('Short Server ID'),\n description: gettext('in numbers'),\n placeholder: '1',\n min: 0\n }\n },\n {\n key: 'registrationLifetime',\n type: 'number',\n props: {\n label: gettext('Registration lifetime'),\n description: gettext('in seconds'),\n placeholder: '600',\n min: 0\n }\n },\n {\n key: 'defaultMinPeriod',\n type: 'number',\n props: {\n label: gettext('Default minimum period'),\n description: gettext('in seconds'),\n placeholder: '10',\n min: 0\n }\n },\n {\n key: 'defaultMaxPeriod',\n type: 'number',\n props: {\n label: gettext('Default maximum period'),\n description: gettext('in seconds'),\n placeholder: '60',\n min: 0\n }\n },\n {\n key: 'bindingMode',\n type: 'select',\n defaultValue: BindingMode.U,\n props: {\n label: gettext('Binding mode'),\n options: Object.values(BindingMode).map(value => ({\n label:\n value === BindingMode.U ? gettext('UDP') : gettext('UDP with queue mode'),\n value\n }))\n }\n },\n {\n key: 'disableTimeout',\n type: 'number',\n props: {\n label: gettext('Disable timeout'),\n description: gettext('in seconds'),\n placeholder: '86400',\n min: 0\n }\n }\n ]\n }\n ]\n }\n ];\n }\n\n save() {\n this.service\n .update$({\n ...this.model,\n uri: this.getFullURI(),\n endpoint: LWM2MEndpoint.servers\n })\n .pipe(\n catchError(err => {\n this.alert.addServerFailure(err);\n return of(null);\n })\n )\n .subscribe(_next => this.cancel());\n }\n\n delete() {\n this.service\n .deleteServer$(this.model)\n .pipe(\n catchError(err => {\n this.alert.addServerFailure(err);\n return of(null);\n })\n )\n .subscribe(_next => this.cancel());\n }\n\n cancel = () => this.router.navigate(['../servers'], { relativeTo: this.route });\n\n protected getFullURI() {\n const {\n uri,\n security: { mode = Mode.NO_SEC }\n } = this.model;\n return (mode === Mode.NO_SEC ? this.COAP : this.COAPS).concat(uri);\n }\n\n private patchFingerprint(privateKey: string) {\n if (privateKey?.length > 0) {\n this.service\n .validate(privateKey, ValidationType.PRIVATE_KEY)\n .pipe(takeUntil(this.destroy$))\n .subscribe(\n fingerprint => {\n this.model.security.x509PrivateKey = privateKey;\n this.model.security.x509PrivateKeyFingerPrint = fingerprint;\n this.form.patchValue(this.model);\n this.form.markAsDirty();\n },\n _error => {\n // already catched\n }\n );\n }\n }\n\n private patchCommonName(certificate: string) {\n if (certificate?.length > 0) {\n this.service\n .validate(certificate, ValidationType.X509)\n .pipe(takeUntil(this.destroy$))\n .subscribe(\n commonName => {\n this.model.security.x509Certificate = certificate;\n this.model.security.x509CertificateCommonName = commonName;\n this.form.patchValue(this.model);\n this.form.markAsDirty();\n },\n _error => {\n // already catched\n }\n );\n }\n }\n\n private removePrivateKeyAndFingerprint() {\n this.form.patchValue({\n security: {\n x509PrivateKey: null,\n x509PrivateKeyFingerPrint: null\n } as Partial<Security>\n });\n delete this.model?.security?.x509PrivateKey;\n delete this.model?.security?.x509PrivateKeyFingerPrint;\n this.form.markAsDirty();\n }\n\n private removeCertificateAndCommonName() {\n this.form.patchValue({\n security: {\n x509Certificate: null,\n x509CertificateCommonName: null\n } as Partial<Security>\n });\n delete this.model?.security?.x509CertificateCommonName;\n delete this.model?.security?.x509Certificate;\n this.form.markAsDirty();\n }\n}\n","import { Component, OnInit } from '@angular/core';\nimport { CoreModule } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { ServerSettings } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\nimport { Lwm2mFormSingleServerSettings } from './single-server-settings.component';\nimport { catchError } from 'rxjs/operators';\nimport { of } from 'rxjs';\n\n@Component({\n templateUrl: './form-wrapper-base.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-create-single-server-settings'\n})\nexport class Lwm2mFormCreateSingleServerSettings\n extends Lwm2mFormSingleServerSettings\n implements OnInit\n{\n constructor(protected service: Lwm2mConfigurationService<ServerSettings>) {\n super(service);\n }\n\n ngOnInit() {\n // override by design\n }\n\n create() {\n this.service\n .createServer$({\n ...this.model,\n uri: this.getFullURI()\n })\n .pipe(\n catchError(err => {\n this.alert.addServerFailure(err);\n return of(null);\n })\n )\n .subscribe(_next => this.cancel());\n }\n}\n","import { Component, ComponentRef, OnInit, ViewChild, ViewContainerRef } from '@angular/core';\nimport { CoreModule, gettext } from '@c8y/ngx-components';\nimport { Lwm2mUIThemeModule } from '@c8y/ngx-components/protocol-lwm2m/formly';\nimport { ServerSettings } from '@c8y/ngx-components/protocol-lwm2m/model';\nimport { Lwm2mConfigurationService } from '@c8y/ngx-components/protocol-lwm2m/services';\nimport { Lwm2mFormSingleServerSettings } from './single-server-settings.component';\nimport { map, takeUntil } from 'rxjs/operators';\nimport { ActivatedRoute, Router, RouterModule } from '@angular/router';\nimport { Lwm2mFormCreateSingleServerSettings } from './create-single-server-settings.component';\nimport { Subject } from 'rxjs';\n\n@Component({\n templateUrl: './server-settings.component.html',\n imports: [CoreModule, Lwm2mUIThemeModule, Lwm2mFormSingleServerSettings, RouterModule],\n standalone: true,\n selector: 'c8y-lwm2m-form-server-settings'\n})\nexport class Lwm2mFormServerSettings implements OnInit {\n private componentRef: ComponentRef<\n Lwm2mFormSingleServerSettings | Lwm2mFormCreateSingleServerSettings\n >;\n private destroy$: Subject<void> = new Subject();\n @ViewChild('singleServerForm', { read: ViewContainerRef, static: true })\n formContainer: ViewContainerRef;\n cmp: Lwm2mFormSingleServerSettings;\n id: string;\n\n listelements$ = this.service.servers$.pipe(\n map(servers =>\n servers.map(server => ({\n title: server.uri || gettext('Invalid server configuration'),\n icon: 'server',\n id: server.id\n }))\n )\n );\n\n constructor(\n protected service: Lwm2mConfigurationService<ServerSettings>,\n protected route: ActivatedRoute,\n protected router: Router\n ) {}\n\n ngOnInit() {\n this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe(({ id }) => {\n this.id = id;\n this.service.listServers();\n this.createComponent(id);\n });\n }\n\n ngOnDestroy() {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n select(id) {\n this.router.navigate([], {\n relativeTo: this.route,\n queryParams: { id },\n queryParamsHandling: 'merge'\n });\n }\n\n createComponent(id) {\n this.formContainer.clear();\n this.cmp = null;\n\n if (!id) return;\n\n this.componentRef = this.formContainer.createComponent(\n id !== 'create' ? Lwm2mFormSingleServerSettings : Lwm2mFormCreateSingleServerSettings\n );\n this.cmp = this.componentRef?.instance;\n this.cmp.id = id;\n }\n}\n","<div class=\"split-view--5-7 grid__row--1 fit-h\">\n <div class=\"inner-scroll split-view__list\">\n <div class=\"bg-level-1 flex-grow\">\n <ng-container *ngIf=\"listelements$ | async as list\">\n <ng-container *ngIf=\"list.length > 0 || id === 'create'; else empty\">\n <c8y-list-group class=\"c8y-list__group nav c8y-nav-stacked\">\n <c8y-li\n class=\"c8y-stacked-item p-0 active\"\n *ngIf=\"id === 'create'\"\n >\n <c8y-li-icon icon=\"server\"></c8y-li-icon>\n <span title=\"{{ 'New server' | translate }}\">\n {{ 'New server' | translate }}\n </span>\n </c8y-li>\n <c8y-li\n class=\"c8y-stacked-item p-0\"\n [class.active]=\"el.id === id\"\n *ngFor=\"let el of list\"\n (click)=\"select(el.id)\"\n >\n <c8y-li-icon [icon]=\"el.icon\"></c8y-li-icon>\n <span title=\"{{ el.title }}\">\n {{ el.title }}\n </span>\n </c8y-li>\n </c8y-list-group>\n </ng-container>\n <ng-template #empty>\n <div class=\"card-block\">\n <c8y-ui-empty-state\n [icon]=\"'stack'\"\n [title]=\"'No servers found.' | translate\"\n [subtitle]=\"'Click below to add a new server.' | translate\"\n ></c8y-ui-empty-state>\n </div>\n </ng-template>\n </ng-container>\n </div>\n <div class=\"card-footer separator-top\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Add server' | translate }}\"\n [disabled]=\"id === 'create'\"\n (click)=\"select('create')\"\n >\n <i [c8yIcon]=\"'plus-circle'\"></i>\n {{ 'Add server' | translate }}\n </button>\n </div>\n </div>\n <form class=\"d-contents\">\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': cmp?.fields?.length > 0 }\"\n >\n <div class=\"card-header separator visible-sm visible-xs fit-w sticky-top\">\n <button\n class=\"btn btn-clean text-primary\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n (click)=\"cmp?.cancel()\"\n >\n <i c8y-icon=\"chevron-left\"></i>\n <span>{{ 'Back' | translate }}</span>\n </button>\n </div>\n <div class=\"card-block flex-grow overflow-visible\">\n <ng-container *ngIf=\"!cmp?.fields?.length\">\n <c8y-ui-empty-state\n [icon]=\"'stack'\"\n title=\"{{ 'No server to display.' | translate }}\"\n subtitle=\"{{ 'Add or select a server.' | translate }}\"\n ></c8y-ui-empty-state>\n <div\n class=\"alert alert-info\"\n role=\"alert\"\n >\n <strong>{{ 'Info' | translate }}</strong>\n {{\n 'Configured servers are written as soon as the device does a bootstrap connection.'\n | translate\n }}\n </div>\n </ng-container>\n <ng-container #singleServerForm></ng-container>\n </div>\n <div\n class=\"card-footer separator sticky-bottom bg-level-0\"\n *ngIf=\"cmp?.fields?.length > 0\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cmp.cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n\n <ng-container *ngIf=\"id !== 'create'; else createServer\">\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n [disabled]=\"cmp.options?.formState?.disabled || false\"\n (click)=\"cmp.delete()\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"button\"\n [disabled]=\"cmp.form?.invalid || !cmp.form?.dirty\"\n (click)=\"cmp.save()\"\n >\n {{ 'Save' | translate }}\n </button>\n </ng-container>\n <ng-template #createServer>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Create' | translate }}\"\n type=\"button\"\n [disabled]=\"cmp.form?.invalid || !cmp.form?.dirty\"\n (click)=\"cmp.create()\"\n >\n {{ 'Create' | translate }}\n </button>\n </ng-template>\n </div>\n </div>\n </form>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["map","delay","i2","i3","i4"],"mappings":"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