@c8y/ngx-components 1024.5.1 → 1024.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/fesm2022/{c8y-ngx-components-asset-property-grid.component-DhfJagxU.mjs → c8y-ngx-components-asset-property-grid.component-Ddva2QJW.mjs} +35 -19
  2. package/fesm2022/c8y-ngx-components-asset-property-grid.component-Ddva2QJW.mjs.map +1 -0
  3. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +28 -14
  4. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +2 -2
  6. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-icon-selector.mjs +1538 -59
  8. package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-platform-configuration.mjs +2 -2
  10. package/fesm2022/c8y-ngx-components-platform-configuration.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-remote-access-data.mjs +9 -2
  12. package/fesm2022/c8y-ngx-components-remote-access-data.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs +6 -1
  14. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-reports.mjs +3 -5
  16. package/fesm2022/c8y-ngx-components-reports.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +94 -49
  18. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components.mjs +1 -1
  20. package/locales/de.po +266 -3
  21. package/locales/es.po +266 -3
  22. package/locales/fr.po +266 -3
  23. package/locales/ja_JP.po +265 -3
  24. package/locales/ko.po +266 -3
  25. package/locales/locales.pot +294 -7
  26. package/locales/nl.po +266 -3
  27. package/locales/pl.po +266 -3
  28. package/locales/pt_BR.po +266 -3
  29. package/locales/zh_CN.po +266 -3
  30. package/locales/zh_TW.po +266 -3
  31. package/package.json +1 -1
  32. package/types/c8y-ngx-components-context-dashboard.d.ts +7 -3
  33. package/types/c8y-ngx-components-context-dashboard.d.ts.map +1 -1
  34. package/types/c8y-ngx-components-icon-selector.d.ts +286 -32
  35. package/types/c8y-ngx-components-icon-selector.d.ts.map +1 -1
  36. package/types/c8y-ngx-components-platform-configuration.d.ts +2 -2
  37. package/types/c8y-ngx-components-remote-access-data.d.ts +8 -1
  38. package/types/c8y-ngx-components-remote-access-data.d.ts.map +1 -1
  39. package/types/c8y-ngx-components-remote-access-terminal-viewer.d.ts.map +1 -1
  40. package/types/c8y-ngx-components-reports.d.ts.map +1 -1
  41. package/types/c8y-ngx-components-repository-configuration.d.ts +20 -10
  42. package/types/c8y-ngx-components-repository-configuration.d.ts.map +1 -1
  43. package/fesm2022/c8y-ngx-components-asset-property-grid.component-DhfJagxU.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-platform-configuration.mjs","sources":["../../platform-configuration/platform-configuration-form-provider.service.ts","../../platform-configuration/platform-configuration-form.component.ts","../../platform-configuration/platform-configuration-form.component.html","../../platform-configuration/platform-configuration.module.ts","../../platform-configuration/c8y-ngx-components-platform-configuration.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { DatePipe } from '@c8y/ngx-components';\nimport { FormControl, Validators } from '@angular/forms';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class PlatformConfigurationFormProviderService {\n lineBreakHint = gettext('Use [Enter] or <br> tag to add a new line');\n\n exampleTomorrowDate = (() => {\n const tomorrow = new Date();\n tomorrow.setDate(tomorrow.getDate() + 1);\n return this.c8yDatePipe.transform(tomorrow, 'yyyy-MM-ddTHH:mm:ssZ');\n })();\n\n platformConfigurationFormDefinitions = {\n 'system.password.enforce.strength': {\n formId: 'system.password.enforce.strength',\n title: gettext('Enforce \"green\" passwords for all users'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'system.password.limit.validity': {\n formId: 'system.password.limit.validity',\n title: gettext('Password validity limit (days)'),\n description: gettext(\n 'The number of days a password may be valid before it must be reset; minimum value is 0, maximum value is 999999. Leave empty to use the value from the tenant options.'\n ),\n type: 'number',\n control: new FormControl('', [Validators.min(0), Validators.max(999999)])\n },\n 'system.password.history.size': {\n formId: 'system.password.history.size',\n title: gettext('Password history size'),\n description: gettext(\n 'The number of times before the current password can be reused. Minimum value is 0, preset value is 10.'\n ),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '10' },\n control: new FormControl('', [Validators.min(0)])\n },\n 'system.password.green.min-length': {\n formId: 'system.password.green.min-length',\n title: gettext('Minimal length of \"green\" password'),\n description: gettext(\n 'The minimum number of characters which are required for a safe password. Minimum (and preset) value is 8, maximum value is 32. Leave empty to skip this constraint.'\n ),\n type: 'number',\n control: new FormControl('', [Validators.min(8), Validators.max(32)])\n },\n 'ui.email.protocolAndEncryption': {\n formId: 'ui.email.protocolAndEncryption',\n title: gettext('Protocol and encryption'),\n type: 'select',\n options: [\n {\n value: 'SMTP_PLAIN',\n name: gettext('SMTP (no encryption)')\n },\n {\n value: 'SMTP_ENCRYPTED',\n name: gettext('SMTP (STARTTLS)')\n },\n {\n value: 'SMTPS_ENCRYPTED',\n name: gettext('SMTPS (SSL/TLS)')\n }\n ],\n skipOnSave: true,\n control: new FormControl('')\n },\n 'email.protocol': {\n formId: 'email.protocol',\n title: gettext('Protocol'),\n type: 'select',\n options: [\n {\n value: 'smtp',\n name: 'SMTP'\n },\n {\n value: 'smtps',\n name: 'SMTPS'\n }\n ],\n control: new FormControl('')\n },\n 'email.connection.encrypted': {\n formId: 'email.connection.encrypted',\n title: gettext('Connection encrypted'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'email.host': {\n formId: 'email.host',\n title: gettext('Host'),\n type: 'string',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: 'localhost' },\n control: new FormControl('')\n },\n 'email.port': {\n formId: 'email.port',\n title: gettext('Port'),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '25' },\n control: new FormControl('', [Validators.min(1), Validators.max(65535)])\n },\n 'email.username': {\n formId: 'email.username',\n title: gettext('Username'),\n type: 'string',\n control: new FormControl('')\n },\n 'credentials.email.password': {\n formId: 'credentials.email.password',\n title: gettext('Password'),\n type: 'password',\n control: new FormControl('')\n },\n 'email.from': {\n formId: 'email.from',\n title: gettext('Sender address'),\n type: 'string',\n control: new FormControl('', [Validators.email])\n },\n 'passwordReset.sendNotificationToUnknownEmails': {\n formId: 'passwordReset.sendNotificationToUnknownEmails',\n title: gettext('Send notifications to unknown email addresses'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'passwordReset.email.subject': {\n formId: 'passwordReset.email.subject',\n title: gettext('Email subject'),\n description: gettext('Subject used for all password reset related emails'),\n type: 'string',\n control: new FormControl('')\n },\n 'passwordReset.token.email.template': {\n formId: 'passwordReset.token.email.template',\n title: gettext('Password reset email template (when address is known)'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {token}, {username}, {email}. Whole link to reset password can be, for example: {tenant-domain}/apps/devicemanagement/index.html?token={token}&email={email}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.user.not.found.email.template': {\n formId: 'passwordReset.user.not.found.email.template',\n title: gettext('Password reset email template (when address is not known)'),\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.success.email.template': {\n formId: 'passwordReset.success.email.template',\n title: gettext('Password change confirmation email template'),\n description: `${gettext('Placeholders: {host}, {tenant-domain}, {username}')}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.invite.template': {\n formId: 'passwordReset.invite.template',\n title: gettext('Invitation email template'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {token}, {username}, {email}. Whole link to setup password can be, for example: {tenant-domain}/apps/devicemanagement/index.html?token={token}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'export.data.mail.subject': {\n formId: 'export.data.mail.subject',\n title: gettext('Email subject'),\n description: gettext(\n 'Placeholders: {tenant-domain}, {host}, {binaryId}. Whole link to result file is: {tenant-domain}/inventory/binaries/{binaryId}'\n ),\n type: 'string',\n control: new FormControl('')\n },\n 'export.data.mail.text': {\n formId: 'export.data.mail.text',\n title: gettext('Email template'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {binaryId}. Whole link to result file is: {tenant-domain}/inventory/binaries/{binaryId}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'export.data.mail.text.userunauthorized': {\n formId: 'export.data.mail.text.userunauthorized',\n title: gettext('User unauthorized error message'),\n description: gettext('Placeholders: {user}, {exportApi}'),\n type: 'string',\n control: new FormControl('')\n },\n 'two-factor-authentication.token.sms.template': {\n formId: 'two-factor-authentication.token.sms.template',\n title: gettext('Verification token SMS template'),\n description: gettext('Placeholder: {token} - created token'),\n type: 'string',\n placeholder: gettext('e.g.: Verification code: {token}'),\n control: new FormControl('')\n },\n 'system.support.url': {\n formId: 'system.support.url',\n title: gettext('URL'),\n type: 'string',\n description: gettext(\n 'Possible values: URL string, \"false`KEEP_ORIGINAL`\" (hides the link) or leave empty (uses the default). Applications can override this setting by defining \"supportUrl`KEEP_ORIGINAL`\" application option.'\n ),\n control: new FormControl('')\n },\n 'storageLimit.warning.email.subject': {\n formId: 'storageLimit.warning.email.subject',\n title: gettext('Warning email subject'),\n description: gettext('Email which will be sent one day before data is deleted'),\n type: 'string',\n control: new FormControl('')\n },\n 'storageLimit.warning.email.template': {\n formId: 'storageLimit.warning.email.template',\n title: gettext('Warning email template'),\n description: `${gettext(\n 'Email which will be sent one day before data is deleted. Placeholders: {tenant-domain}, {tenant}, {size} - storage usage in %'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'storageLimit.process.email.subject': {\n formId: 'storageLimit.process.email.subject',\n title: gettext('Limit exceeded email subject'),\n description: gettext('Email which will be sent after over-limit data has been deleted'),\n type: 'string',\n control: new FormControl('')\n },\n 'storageLimit.process.email.template': {\n formId: 'storageLimit.process.email.template',\n title: gettext('Limit exceeded email template'),\n description: `${gettext(\n 'Email which will be sent after over-limit data has been deleted. Placeholders: {tenant-domain}, {tenant}, {size} - storage usage in %'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'tenantSuspend.mail.sendtosuspended': {\n formId: 'tenantSuspend.mail.sendtosuspended',\n title: gettext(\"Send email to suspended tenant's administrator\"),\n type: 'boolean',\n control: new FormControl('')\n },\n 'tenantSuspend.mail.additional.address': {\n formId: 'tenantSuspend.mail.additional.address',\n title: gettext('Tenant suspended email additional receiver'),\n type: 'string',\n control: new FormControl('', [Validators.email])\n },\n 'tenantSuspend.mail.subject': {\n formId: 'tenantSuspend.mail.subject',\n title: gettext('Tenant suspended email subject'),\n description: gettext(\n \"Placeholder: {tenant} - suspended tenant's ID; {tenant-domain} - tenant's domain\"\n ),\n type: 'string',\n control: new FormControl('')\n },\n 'tenantSuspend.mail.text': {\n formId: 'tenantSuspend.mail.text',\n title: gettext('Tenant suspended email template'),\n description: `${gettext(\n \"Placeholder: {tenant} - suspended tenant's ID; {tenant-domain} - tenant's domain\"\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'system.support-user.enabled': {\n formId: 'system.support-user.enabled',\n title: gettext('Activate support user'),\n description: gettext(\n 'Possible values: \"true`KEEP_ORIGINAL`\", \"false`KEEP_ORIGINAL`\", or a specific date until the user should remain active, for example, \"{{ exampleDate }}\". Leaving it blank, will set the value to \"true`KEEP_ORIGINAL`\".'\n ),\n descriptionTranslateParams: {\n exampleDate: this.exampleTomorrowDate\n },\n type: 'string',\n control: new FormControl(''),\n placeholder: this.exampleTomorrowDate\n },\n 'system.support-user.validity-limit': {\n formId: 'system.support-user.validity-limit',\n title: gettext('Validity limit'),\n description: gettext(\n 'Each support user request from subtenant user will prolong support user access by the given number of hours (default: 24 hours). Leaving it blank, will set the value to \"24\".'\n ),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '24' },\n control: new FormControl('', [Validators.min(0)])\n }\n };\n\n optionsGroups = [\n {\n title: gettext('Passwords'),\n id: 'passwordsOptions',\n items: [\n this.platformConfigurationFormDefinitions['system.password.enforce.strength'],\n this.platformConfigurationFormDefinitions['system.password.limit.validity'],\n this.platformConfigurationFormDefinitions['system.password.history.size'],\n this.platformConfigurationFormDefinitions['system.password.green.min-length']\n ]\n },\n {\n title: gettext('Two-factor authentication'),\n id: 'twoFactorAuthenticationOptions',\n items: [\n this.platformConfigurationFormDefinitions['two-factor-authentication.token.sms.template']\n ]\n },\n {\n title: gettext('Support link'),\n id: 'supportLinkOptions',\n items: [this.platformConfigurationFormDefinitions['system.support.url']]\n },\n {\n title: gettext('Password reset'),\n id: 'passwordResetOptions',\n items: [\n this.platformConfigurationFormDefinitions['passwordReset.sendNotificationToUnknownEmails'],\n this.platformConfigurationFormDefinitions['passwordReset.token.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.user.not.found.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.email.subject'],\n this.platformConfigurationFormDefinitions['passwordReset.success.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.invite.template']\n ]\n },\n {\n title: gettext('Support user'),\n id: 'supportUserOptions',\n items: [\n this.platformConfigurationFormDefinitions['system.support-user.enabled'],\n this.platformConfigurationFormDefinitions['system.support-user.validity-limit']\n ]\n },\n {\n title: gettext('Email server'),\n id: 'emailServerOptions',\n items: [\n this.platformConfigurationFormDefinitions['ui.email.protocolAndEncryption'],\n this.platformConfigurationFormDefinitions['email.host'],\n this.platformConfigurationFormDefinitions['email.port'],\n this.platformConfigurationFormDefinitions['email.username'],\n this.platformConfigurationFormDefinitions['credentials.email.password'],\n this.platformConfigurationFormDefinitions['email.from']\n ]\n },\n {\n title: gettext('Data export'),\n id: 'dataExportOptions',\n items: [\n this.platformConfigurationFormDefinitions['export.data.mail.subject'],\n this.platformConfigurationFormDefinitions['export.data.mail.text'],\n this.platformConfigurationFormDefinitions['export.data.mail.text.userunauthorized']\n ]\n },\n {\n title: gettext('Storage limit'),\n id: 'storageLimitOptions',\n items: [\n this.platformConfigurationFormDefinitions['storageLimit.warning.email.subject'],\n this.platformConfigurationFormDefinitions['storageLimit.warning.email.template'],\n this.platformConfigurationFormDefinitions['storageLimit.process.email.subject'],\n this.platformConfigurationFormDefinitions['storageLimit.process.email.template']\n ]\n },\n {\n title: gettext('Suspending tenants'),\n id: 'suspendingTenantsOptions',\n items: [\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.sendtosuspended'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.additional.address'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.subject'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.text']\n ]\n }\n ];\n\n constructor(private c8yDatePipe: DatePipe) {}\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { PlatformConfigurationFormProviderService } from './platform-configuration-form-provider.service';\nimport { NgFor, NgSwitch, NgSwitchCase, NgTemplateOutlet, NgIf } from '@angular/common';\nimport {\n C8yTranslateDirective,\n FormGroupComponent,\n RequiredInputPlaceholderDirective,\n C8yTranslatePipe\n} from '@c8y/ngx-components';\n\n@Component({\n selector: 'c8y-platform-configuration-form',\n templateUrl: './platform-configuration-form.component.html',\n imports: [\n FormsModule,\n ReactiveFormsModule,\n NgFor,\n NgSwitch,\n NgSwitchCase,\n NgTemplateOutlet,\n C8yTranslateDirective,\n FormGroupComponent,\n RequiredInputPlaceholderDirective,\n NgIf,\n C8yTranslatePipe\n ]\n})\nexport class PlatformConfigurationFormComponent {\n @Input('optionsGroups')\n set _optionsGroups(groupIds: string[]) {\n if (groupIds === undefined) {\n return;\n }\n this.optionsGroups = groupIds.map(groupId =>\n this.formProviderService.optionsGroups.find(option => option.id === groupId)\n );\n }\n\n @Input()\n set readOnly(disabled: boolean) {\n disabled ? this.form.disable() : this.form.enable();\n }\n\n @Input()\n set formValue(value) {\n if (value) {\n const convertedValue = this.afterLoad(value);\n this.form.patchValue(convertedValue, { emitEvent: false });\n this.form.markAsUntouched();\n this.form.markAsPristine();\n }\n }\n optionsGroups = [];\n\n @Output()\n onSave = new EventEmitter();\n\n form = new FormGroup({});\n\n lineBreakHint = this.formProviderService.lineBreakHint;\n\n constructor(private formProviderService: PlatformConfigurationFormProviderService) {\n Object.keys(formProviderService.platformConfigurationFormDefinitions).forEach(fieldId => {\n this.form.addControl(\n fieldId,\n formProviderService.platformConfigurationFormDefinitions[fieldId].control\n );\n });\n }\n\n /**\n * Parses provided object's property values\n * @param options\n */\n parseConfiguration(options: object): void {\n const definitions: object = this.formProviderService.platformConfigurationFormDefinitions;\n Object.entries(options).forEach(([key, rawValue]) => {\n if (\n definitions[key] &&\n (definitions[key].type === 'number' || definitions[key].type === 'boolean')\n ) {\n try {\n options[key] = JSON.parse(rawValue);\n } catch {\n options[key] = rawValue;\n }\n }\n });\n }\n\n /**\n * Parses incoming raw object before it is applied to FormGroup.\n */\n afterLoad(options: object): object {\n this.parseConfiguration(options);\n\n delete options['ui.email.protocolAndEncryption'];\n const emailProtocol = options['email.protocol'];\n const connectionEncrypted = options['email.connection.encrypted'] || false;\n if (emailProtocol === 'smtp') {\n if (connectionEncrypted) {\n options['ui.email.protocolAndEncryption'] = 'SMTP_ENCRYPTED';\n } else {\n options['ui.email.protocolAndEncryption'] = 'SMTP_PLAIN';\n }\n } else if (emailProtocol === 'smtps') {\n options['ui.email.protocolAndEncryption'] = 'SMTPS_ENCRYPTED';\n } else {\n options['ui.email.protocolAndEncryption'] = undefined;\n }\n return options;\n }\n\n /**\n * Translates ui.email.protocolAndEncryption field into\n * separate email.protocol and email.connection.encrypted\n */\n beforeSave(value): object {\n const protocolAndEncryption = value['ui.email.protocolAndEncryption'];\n if (protocolAndEncryption) {\n //email.protocol\n const protocol = protocolAndEncryption.match(/^(.+?)_(.+?)$/)[1];\n value['email.protocol'] = protocol ? protocol.toLowerCase() : protocol;\n\n // email.connection.encrypted\n const encryption = protocolAndEncryption.match(/^(.+?)_(.+?)$/)[2];\n value['email.connection.encrypted'] = encryption === 'ENCRYPTED';\n delete value['ui.email.protocolAndEncryption'];\n }\n\n return value;\n }\n\n getDirtyValues() {\n const dirtyValues = {};\n\n Object.keys(this.form.controls).forEach(key => {\n const currentControl = this.form.controls[key];\n\n if (currentControl.dirty) {\n dirtyValues[key] = currentControl.value;\n }\n });\n\n return dirtyValues;\n }\n\n emitForm() {\n if (this.form.valid) {\n const changedValues = this.getDirtyValues();\n const convertedValue = this.beforeSave(changedValues);\n this.onSave.emit(convertedValue);\n }\n }\n}\n","<form [formGroup]=\"form\">\n <div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card card--fullpage\">\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ 'Configuration' | translate }}\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block\">\n <div>\n <fieldset\n class=\"row schema-form-fieldset separator-bottom p-t-24\"\n *ngFor=\"let category of optionsGroups\"\n >\n <div class=\"col-sm-3 col-md-2 p-l-24 p-l-xs-8 p-b-8\">\n <div\n class=\"h4 text-normal text-right text-left-xs\"\n data-cy=\"fieldset--section-title\"\n >\n {{ category.title | translate }}\n </div>\n </div>\n <div class=\"col-sm-9 col-md-8\">\n <div\n class=\"form-group\"\n *ngFor=\"let field of category.items\"\n >\n <ng-container [ngSwitch]=\"field.type\">\n <ng-container *ngSwitchCase=\"'string'\">\n <ng-container\n *ngTemplateOutlet=\"stringTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'number'\">\n <ng-container\n *ngTemplateOutlet=\"numberTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'password'\">\n <ng-container\n *ngTemplateOutlet=\"passwordTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textarea'\">\n <ng-container\n *ngTemplateOutlet=\"textareaTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'boolean'\">\n <ng-container\n *ngTemplateOutlet=\"booleanTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'select'\">\n <ng-container\n *ngTemplateOutlet=\"selectTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n </ng-container>\n </div>\n </div>\n </fieldset>\n </div>\n </div>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n [title]=\"'Save configuration' | translate\"\n type=\"submit\"\n (click)=\"emitForm()\"\n [disabled]=\"!form.dirty || form.invalid || form.disabled\"\n >\n <span translate>Save</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <ng-template\n #stringTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"text\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #passwordTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"password\"\n autocomplete=\"new-password\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #numberTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"number\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #textareaTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <textarea\n class=\"form-control\"\n [title]=\"field.title | translate\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n [rows]=\"10\"\n ></textarea>\n <div\n class=\"help-block\"\n *ngIf=\"field.description || field.lineBreakHint\"\n >\n <span *ngIf=\"field.description\">\n {{ field.description | translate : field.descriptionTranslateParams }}\n </span>\n <span *ngIf=\"field.description && field.lineBreakHint\"><br /></span>\n <span *ngIf=\"field.lineBreakHint\">{{ lineBreakHint | translate }}</span>\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #booleanTemplate\n let-field\n >\n <c8y-form-group>\n <label\n class=\"c8y-checkbox\"\n title=\"{{ field.title | translate }}\"\n >\n <input\n [title]=\"field.title | translate\"\n type=\"checkbox\"\n [formControlName]=\"field.formId\"\n />\n <span></span>\n <span>{{ field.title | translate }}</span>\n </label>\n\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #selectTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n <span>{{ field.title | translate }}</span>\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n >\n <option></option>\n <option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n >\n {{ option.name | translate }}\n </option>\n </select>\n <span></span>\n </div>\n\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n</form>\n","import { CommonModule, FormsModule } from '@c8y/ngx-components';\nimport { NgModule } from '@angular/core';\nimport { PlatformConfigurationFormComponent } from './platform-configuration-form.component';\nimport { ReactiveFormsModule } from '@angular/forms';\n\n@NgModule({\n imports: [CommonModule, FormsModule, ReactiveFormsModule, PlatformConfigurationFormComponent],\n exports: [PlatformConfigurationFormComponent]\n})\nexport class PlatformConfigurationModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.PlatformConfigurationFormProviderService","FormsModule"],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-platform-configuration.mjs","sources":["../../platform-configuration/platform-configuration-form-provider.service.ts","../../platform-configuration/platform-configuration-form.component.ts","../../platform-configuration/platform-configuration-form.component.html","../../platform-configuration/platform-configuration.module.ts","../../platform-configuration/c8y-ngx-components-platform-configuration.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { DatePipe } from '@c8y/ngx-components';\nimport { FormControl, Validators } from '@angular/forms';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class PlatformConfigurationFormProviderService {\n lineBreakHint = gettext('Use [Enter] or <br> tag to add a new line');\n\n exampleTomorrowDate = (() => {\n const tomorrow = new Date();\n tomorrow.setDate(tomorrow.getDate() + 1);\n return this.c8yDatePipe.transform(tomorrow, 'yyyy-MM-ddTHH:mm:ssZ');\n })();\n\n platformConfigurationFormDefinitions = {\n 'system.password.enforce.strength': {\n formId: 'system.password.enforce.strength',\n title: gettext('Enforce \"green\" passwords for all users'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'system.password.limit.validity': {\n formId: 'system.password.limit.validity',\n title: gettext('Password validity limit (days)'),\n description: gettext(\n 'The number of days a password may be valid before it must be reset; minimum value is 0, maximum value is 999999. Leave empty to use the value from the tenant options.'\n ),\n type: 'number',\n control: new FormControl('', [Validators.min(0), Validators.max(999999)])\n },\n 'system.password.history.size': {\n formId: 'system.password.history.size',\n title: gettext('Password history size'),\n description: gettext(\n 'The number of times before the current password can be reused. Minimum value is 0, preset value is 10.'\n ),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '10' },\n control: new FormControl('', [Validators.min(0)])\n },\n 'system.password.green.min-length': {\n formId: 'system.password.green.min-length',\n title: gettext('Minimal length of \"green\" password'),\n description: gettext(\n 'The minimum number of characters which are required for a safe password. Minimum (and preset) value is 8, maximum value is 32. Leave empty to skip this constraint.'\n ),\n type: 'number',\n control: new FormControl('', [Validators.min(8), Validators.max(32)])\n },\n 'ui.email.protocolAndEncryption': {\n formId: 'ui.email.protocolAndEncryption',\n title: gettext('Protocol and encryption'),\n type: 'select',\n options: [\n {\n value: 'SMTP_PLAIN',\n name: gettext('SMTP (no encryption)')\n },\n {\n value: 'SMTP_ENCRYPTED',\n name: gettext('SMTP (STARTTLS)')\n },\n {\n value: 'SMTPS_ENCRYPTED',\n name: gettext('SMTPS (SSL/TLS)')\n }\n ],\n skipOnSave: true,\n control: new FormControl('')\n },\n 'email.protocol': {\n formId: 'email.protocol',\n title: gettext('Protocol'),\n type: 'select',\n options: [\n {\n value: 'smtp',\n name: 'SMTP'\n },\n {\n value: 'smtps',\n name: 'SMTPS'\n }\n ],\n control: new FormControl('')\n },\n 'email.connection.encrypted': {\n formId: 'email.connection.encrypted',\n title: gettext('Connection encrypted'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'email.host': {\n formId: 'email.host',\n title: gettext('Host'),\n type: 'string',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: 'localhost' },\n control: new FormControl('')\n },\n 'email.port': {\n formId: 'email.port',\n title: gettext('Port'),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '25' },\n control: new FormControl('', [Validators.min(1), Validators.max(65535)])\n },\n 'email.username': {\n formId: 'email.username',\n title: gettext('Username'),\n type: 'string',\n control: new FormControl('')\n },\n 'credentials.email.password': {\n formId: 'credentials.email.password',\n title: gettext('Password'),\n type: 'password',\n control: new FormControl('')\n },\n 'email.from': {\n formId: 'email.from',\n title: gettext('Sender address'),\n type: 'string',\n control: new FormControl('', [Validators.email])\n },\n 'passwordReset.sendNotificationToUnknownEmails': {\n formId: 'passwordReset.sendNotificationToUnknownEmails',\n title: gettext('Send notifications to unknown email addresses'),\n type: 'boolean',\n control: new FormControl('')\n },\n 'passwordReset.email.subject': {\n formId: 'passwordReset.email.subject',\n title: gettext('Email subject'),\n description: gettext('Subject used for all password reset related emails'),\n type: 'string',\n control: new FormControl('')\n },\n 'passwordReset.token.email.template': {\n formId: 'passwordReset.token.email.template',\n title: gettext('Password reset email template (when address is known)'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {token}, {username}, {email}. Whole link to reset password can be, for example: {tenant-domain}/apps/devicemanagement/index.html?token={token}&email={email}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.user.not.found.email.template': {\n formId: 'passwordReset.user.not.found.email.template',\n title: gettext('Password reset email template (when address is not known)'),\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.success.email.template': {\n formId: 'passwordReset.success.email.template',\n title: gettext('Password change confirmation email template'),\n description: `${gettext('Placeholders: {host}, {tenant-domain}, {username}')}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'passwordReset.invite.template': {\n formId: 'passwordReset.invite.template',\n title: gettext('Invitation email template'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {token}, {username}, {email}. Whole link to setup password can be, for example: {tenant-domain}/apps/devicemanagement/index.html?token={token}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'export.data.mail.subject': {\n formId: 'export.data.mail.subject',\n title: gettext('Email subject'),\n description: gettext(\n 'Placeholders: {tenant-domain}, {host}, {binaryId}. Whole link to result file is: {tenant-domain}/apps/public/login/index.html#/?download={binaryId}'\n ),\n type: 'string',\n control: new FormControl('')\n },\n 'export.data.mail.text': {\n formId: 'export.data.mail.text',\n title: gettext('Email template'),\n description: `${gettext(\n 'Placeholders: {tenant-domain}, {host}, {binaryId}. Whole link to result file is: {tenant-domain}/apps/public/login/index.html#/?download={binaryId}'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'export.data.mail.text.userunauthorized': {\n formId: 'export.data.mail.text.userunauthorized',\n title: gettext('User unauthorized error message'),\n description: gettext('Placeholders: {user}, {exportApi}'),\n type: 'string',\n control: new FormControl('')\n },\n 'two-factor-authentication.token.sms.template': {\n formId: 'two-factor-authentication.token.sms.template',\n title: gettext('Verification token SMS template'),\n description: gettext('Placeholder: {token} - created token'),\n type: 'string',\n placeholder: gettext('e.g.: Verification code: {token}'),\n control: new FormControl('')\n },\n 'system.support.url': {\n formId: 'system.support.url',\n title: gettext('URL'),\n type: 'string',\n description: gettext(\n 'Possible values: URL string, \"false`KEEP_ORIGINAL`\" (hides the link) or leave empty (uses the default). Applications can override this setting by defining \"supportUrl`KEEP_ORIGINAL`\" application option.'\n ),\n control: new FormControl('')\n },\n 'storageLimit.warning.email.subject': {\n formId: 'storageLimit.warning.email.subject',\n title: gettext('Warning email subject'),\n description: gettext('Email which will be sent one day before data is deleted'),\n type: 'string',\n control: new FormControl('')\n },\n 'storageLimit.warning.email.template': {\n formId: 'storageLimit.warning.email.template',\n title: gettext('Warning email template'),\n description: `${gettext(\n 'Email which will be sent one day before data is deleted. Placeholders: {tenant-domain}, {tenant}, {size} - storage usage in %'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'storageLimit.process.email.subject': {\n formId: 'storageLimit.process.email.subject',\n title: gettext('Limit exceeded email subject'),\n description: gettext('Email which will be sent after over-limit data has been deleted'),\n type: 'string',\n control: new FormControl('')\n },\n 'storageLimit.process.email.template': {\n formId: 'storageLimit.process.email.template',\n title: gettext('Limit exceeded email template'),\n description: `${gettext(\n 'Email which will be sent after over-limit data has been deleted. Placeholders: {tenant-domain}, {tenant}, {size} - storage usage in %'\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'tenantSuspend.mail.sendtosuspended': {\n formId: 'tenantSuspend.mail.sendtosuspended',\n title: gettext(\"Send email to suspended tenant's administrator\"),\n type: 'boolean',\n control: new FormControl('')\n },\n 'tenantSuspend.mail.additional.address': {\n formId: 'tenantSuspend.mail.additional.address',\n title: gettext('Tenant suspended email additional receiver'),\n type: 'string',\n control: new FormControl('', [Validators.email])\n },\n 'tenantSuspend.mail.subject': {\n formId: 'tenantSuspend.mail.subject',\n title: gettext('Tenant suspended email subject'),\n description: gettext(\n \"Placeholder: {tenant} - suspended tenant's ID; {tenant-domain} - tenant's domain\"\n ),\n type: 'string',\n control: new FormControl('')\n },\n 'tenantSuspend.mail.text': {\n formId: 'tenantSuspend.mail.text',\n title: gettext('Tenant suspended email template'),\n description: `${gettext(\n \"Placeholder: {tenant} - suspended tenant's ID; {tenant-domain} - tenant's domain\"\n )}`,\n type: 'textarea',\n control: new FormControl(''),\n lineBreakHint: true\n },\n 'system.support-user.enabled': {\n formId: 'system.support-user.enabled',\n title: gettext('Activate support user'),\n description: gettext(\n 'Possible values: \"true`KEEP_ORIGINAL`\", \"false`KEEP_ORIGINAL`\", or a specific date until the user should remain active, for example, \"{{ exampleDate }}\". Leaving it blank, will set the value to \"true`KEEP_ORIGINAL`\".'\n ),\n descriptionTranslateParams: {\n exampleDate: this.exampleTomorrowDate\n },\n type: 'string',\n control: new FormControl(''),\n placeholder: this.exampleTomorrowDate\n },\n 'system.support-user.validity-limit': {\n formId: 'system.support-user.validity-limit',\n title: gettext('Validity limit'),\n description: gettext(\n 'Each support user request from subtenant user will prolong support user access by the given number of hours (default: 24 hours). Leaving it blank, will set the value to \"24\".'\n ),\n type: 'number',\n placeholder: `${gettext('e.g. {{ example }}')}`,\n placeholderParams: { example: '24' },\n control: new FormControl('', [Validators.min(0)])\n }\n };\n\n optionsGroups = [\n {\n title: gettext('Passwords'),\n id: 'passwordsOptions',\n items: [\n this.platformConfigurationFormDefinitions['system.password.enforce.strength'],\n this.platformConfigurationFormDefinitions['system.password.limit.validity'],\n this.platformConfigurationFormDefinitions['system.password.history.size'],\n this.platformConfigurationFormDefinitions['system.password.green.min-length']\n ]\n },\n {\n title: gettext('Two-factor authentication'),\n id: 'twoFactorAuthenticationOptions',\n items: [\n this.platformConfigurationFormDefinitions['two-factor-authentication.token.sms.template']\n ]\n },\n {\n title: gettext('Support link'),\n id: 'supportLinkOptions',\n items: [this.platformConfigurationFormDefinitions['system.support.url']]\n },\n {\n title: gettext('Password reset'),\n id: 'passwordResetOptions',\n items: [\n this.platformConfigurationFormDefinitions['passwordReset.sendNotificationToUnknownEmails'],\n this.platformConfigurationFormDefinitions['passwordReset.token.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.user.not.found.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.email.subject'],\n this.platformConfigurationFormDefinitions['passwordReset.success.email.template'],\n this.platformConfigurationFormDefinitions['passwordReset.invite.template']\n ]\n },\n {\n title: gettext('Support user'),\n id: 'supportUserOptions',\n items: [\n this.platformConfigurationFormDefinitions['system.support-user.enabled'],\n this.platformConfigurationFormDefinitions['system.support-user.validity-limit']\n ]\n },\n {\n title: gettext('Email server'),\n id: 'emailServerOptions',\n items: [\n this.platformConfigurationFormDefinitions['ui.email.protocolAndEncryption'],\n this.platformConfigurationFormDefinitions['email.host'],\n this.platformConfigurationFormDefinitions['email.port'],\n this.platformConfigurationFormDefinitions['email.username'],\n this.platformConfigurationFormDefinitions['credentials.email.password'],\n this.platformConfigurationFormDefinitions['email.from']\n ]\n },\n {\n title: gettext('Data export'),\n id: 'dataExportOptions',\n items: [\n this.platformConfigurationFormDefinitions['export.data.mail.subject'],\n this.platformConfigurationFormDefinitions['export.data.mail.text'],\n this.platformConfigurationFormDefinitions['export.data.mail.text.userunauthorized']\n ]\n },\n {\n title: gettext('Storage limit'),\n id: 'storageLimitOptions',\n items: [\n this.platformConfigurationFormDefinitions['storageLimit.warning.email.subject'],\n this.platformConfigurationFormDefinitions['storageLimit.warning.email.template'],\n this.platformConfigurationFormDefinitions['storageLimit.process.email.subject'],\n this.platformConfigurationFormDefinitions['storageLimit.process.email.template']\n ]\n },\n {\n title: gettext('Suspending tenants'),\n id: 'suspendingTenantsOptions',\n items: [\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.sendtosuspended'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.additional.address'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.subject'],\n this.platformConfigurationFormDefinitions['tenantSuspend.mail.text']\n ]\n }\n ];\n\n constructor(private c8yDatePipe: DatePipe) {}\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { PlatformConfigurationFormProviderService } from './platform-configuration-form-provider.service';\nimport { NgFor, NgSwitch, NgSwitchCase, NgTemplateOutlet, NgIf } from '@angular/common';\nimport {\n C8yTranslateDirective,\n FormGroupComponent,\n RequiredInputPlaceholderDirective,\n C8yTranslatePipe\n} from '@c8y/ngx-components';\n\n@Component({\n selector: 'c8y-platform-configuration-form',\n templateUrl: './platform-configuration-form.component.html',\n imports: [\n FormsModule,\n ReactiveFormsModule,\n NgFor,\n NgSwitch,\n NgSwitchCase,\n NgTemplateOutlet,\n C8yTranslateDirective,\n FormGroupComponent,\n RequiredInputPlaceholderDirective,\n NgIf,\n C8yTranslatePipe\n ]\n})\nexport class PlatformConfigurationFormComponent {\n @Input('optionsGroups')\n set _optionsGroups(groupIds: string[]) {\n if (groupIds === undefined) {\n return;\n }\n this.optionsGroups = groupIds.map(groupId =>\n this.formProviderService.optionsGroups.find(option => option.id === groupId)\n );\n }\n\n @Input()\n set readOnly(disabled: boolean) {\n disabled ? this.form.disable() : this.form.enable();\n }\n\n @Input()\n set formValue(value) {\n if (value) {\n const convertedValue = this.afterLoad(value);\n this.form.patchValue(convertedValue, { emitEvent: false });\n this.form.markAsUntouched();\n this.form.markAsPristine();\n }\n }\n optionsGroups = [];\n\n @Output()\n onSave = new EventEmitter();\n\n form = new FormGroup({});\n\n lineBreakHint = this.formProviderService.lineBreakHint;\n\n constructor(private formProviderService: PlatformConfigurationFormProviderService) {\n Object.keys(formProviderService.platformConfigurationFormDefinitions).forEach(fieldId => {\n this.form.addControl(\n fieldId,\n formProviderService.platformConfigurationFormDefinitions[fieldId].control\n );\n });\n }\n\n /**\n * Parses provided object's property values\n * @param options\n */\n parseConfiguration(options: object): void {\n const definitions: object = this.formProviderService.platformConfigurationFormDefinitions;\n Object.entries(options).forEach(([key, rawValue]) => {\n if (\n definitions[key] &&\n (definitions[key].type === 'number' || definitions[key].type === 'boolean')\n ) {\n try {\n options[key] = JSON.parse(rawValue);\n } catch {\n options[key] = rawValue;\n }\n }\n });\n }\n\n /**\n * Parses incoming raw object before it is applied to FormGroup.\n */\n afterLoad(options: object): object {\n this.parseConfiguration(options);\n\n delete options['ui.email.protocolAndEncryption'];\n const emailProtocol = options['email.protocol'];\n const connectionEncrypted = options['email.connection.encrypted'] || false;\n if (emailProtocol === 'smtp') {\n if (connectionEncrypted) {\n options['ui.email.protocolAndEncryption'] = 'SMTP_ENCRYPTED';\n } else {\n options['ui.email.protocolAndEncryption'] = 'SMTP_PLAIN';\n }\n } else if (emailProtocol === 'smtps') {\n options['ui.email.protocolAndEncryption'] = 'SMTPS_ENCRYPTED';\n } else {\n options['ui.email.protocolAndEncryption'] = undefined;\n }\n return options;\n }\n\n /**\n * Translates ui.email.protocolAndEncryption field into\n * separate email.protocol and email.connection.encrypted\n */\n beforeSave(value): object {\n const protocolAndEncryption = value['ui.email.protocolAndEncryption'];\n if (protocolAndEncryption) {\n //email.protocol\n const protocol = protocolAndEncryption.match(/^(.+?)_(.+?)$/)[1];\n value['email.protocol'] = protocol ? protocol.toLowerCase() : protocol;\n\n // email.connection.encrypted\n const encryption = protocolAndEncryption.match(/^(.+?)_(.+?)$/)[2];\n value['email.connection.encrypted'] = encryption === 'ENCRYPTED';\n delete value['ui.email.protocolAndEncryption'];\n }\n\n return value;\n }\n\n getDirtyValues() {\n const dirtyValues = {};\n\n Object.keys(this.form.controls).forEach(key => {\n const currentControl = this.form.controls[key];\n\n if (currentControl.dirty) {\n dirtyValues[key] = currentControl.value;\n }\n });\n\n return dirtyValues;\n }\n\n emitForm() {\n if (this.form.valid) {\n const changedValues = this.getDirtyValues();\n const convertedValue = this.beforeSave(changedValues);\n this.onSave.emit(convertedValue);\n }\n }\n}\n","<form [formGroup]=\"form\">\n <div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card card--fullpage\">\n <div class=\"card-header separator\">\n <div class=\"card-title\">\n {{ 'Configuration' | translate }}\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-block\">\n <div>\n <fieldset\n class=\"row schema-form-fieldset separator-bottom p-t-24\"\n *ngFor=\"let category of optionsGroups\"\n >\n <div class=\"col-sm-3 col-md-2 p-l-24 p-l-xs-8 p-b-8\">\n <div\n class=\"h4 text-normal text-right text-left-xs\"\n data-cy=\"fieldset--section-title\"\n >\n {{ category.title | translate }}\n </div>\n </div>\n <div class=\"col-sm-9 col-md-8\">\n <div\n class=\"form-group\"\n *ngFor=\"let field of category.items\"\n >\n <ng-container [ngSwitch]=\"field.type\">\n <ng-container *ngSwitchCase=\"'string'\">\n <ng-container\n *ngTemplateOutlet=\"stringTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'number'\">\n <ng-container\n *ngTemplateOutlet=\"numberTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'password'\">\n <ng-container\n *ngTemplateOutlet=\"passwordTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textarea'\">\n <ng-container\n *ngTemplateOutlet=\"textareaTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'boolean'\">\n <ng-container\n *ngTemplateOutlet=\"booleanTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'select'\">\n <ng-container\n *ngTemplateOutlet=\"selectTemplate; context: { $implicit: field }\"\n ></ng-container>\n </ng-container>\n </ng-container>\n </div>\n </div>\n </fieldset>\n </div>\n </div>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-primary\"\n [title]=\"'Save configuration' | translate\"\n type=\"submit\"\n (click)=\"emitForm()\"\n [disabled]=\"!form.dirty || form.invalid || form.disabled\"\n >\n <span translate>Save</span>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <ng-template\n #stringTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"text\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #passwordTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"password\"\n autocomplete=\"new-password\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #numberTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <input\n class=\"text-truncate form-control\"\n [title]=\"field.title | translate\"\n type=\"number\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n />\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #textareaTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n {{ field.title | translate }}\n </label>\n <textarea\n class=\"form-control\"\n [title]=\"field.title | translate\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n [placeholder]=\"field.placeholder || '' | translate : field.placeholderParams\"\n [rows]=\"10\"\n ></textarea>\n <div\n class=\"help-block\"\n *ngIf=\"field.description || field.lineBreakHint\"\n >\n <span *ngIf=\"field.description\">\n {{ field.description | translate : field.descriptionTranslateParams }}\n </span>\n <span *ngIf=\"field.description && field.lineBreakHint\"><br /></span>\n <span *ngIf=\"field.lineBreakHint\">{{ lineBreakHint | translate }}</span>\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #booleanTemplate\n let-field\n >\n <c8y-form-group>\n <label\n class=\"c8y-checkbox\"\n title=\"{{ field.title | translate }}\"\n >\n <input\n [title]=\"field.title | translate\"\n type=\"checkbox\"\n [formControlName]=\"field.formId\"\n />\n <span></span>\n <span>{{ field.title | translate }}</span>\n </label>\n\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n\n <ng-template\n #selectTemplate\n let-field\n >\n <c8y-form-group>\n <label\n title=\"{{ field.title | translate }}\"\n [for]=\"field.formId\"\n >\n <span>{{ field.title | translate }}</span>\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n [id]=\"field.formId\"\n [formControlName]=\"field.formId\"\n >\n <option></option>\n <option\n *ngFor=\"let option of field.options\"\n [value]=\"option.value\"\n >\n {{ option.name | translate }}\n </option>\n </select>\n <span></span>\n </div>\n\n <div\n class=\"help-block\"\n *ngIf=\"field.description\"\n >\n {{ field.description | translate : field.descriptionTranslateParams }}\n </div>\n </c8y-form-group>\n </ng-template>\n</form>\n","import { CommonModule, FormsModule } from '@c8y/ngx-components';\nimport { NgModule } from '@angular/core';\nimport { PlatformConfigurationFormComponent } from './platform-configuration-form.component';\nimport { ReactiveFormsModule } from '@angular/forms';\n\n@NgModule({\n imports: [CommonModule, FormsModule, ReactiveFormsModule, PlatformConfigurationFormComponent],\n exports: [PlatformConfigurationFormComponent]\n})\nexport class PlatformConfigurationModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.PlatformConfigurationFormProviderService","FormsModule"],"mappings":";;;;;;;;;MAQa,wCAAwC,CAAA;AAsYnD,IAAA,WAAA,CAAoB,WAAqB,EAAA;QAArB,IAAA,CAAA,WAAW,GAAX,WAAW;AArY/B,QAAA,IAAA,CAAA,aAAa,GAAG,OAAO,CAAC,2CAA2C,CAAC;QAEpE,IAAA,CAAA,mBAAmB,GAAG,CAAC,MAAK;AAC1B,YAAA,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE;YAC3B,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,sBAAsB,CAAC;QACrE,CAAC,GAAG;AAEJ,QAAA,IAAA,CAAA,oCAAoC,GAAG;AACrC,YAAA,kCAAkC,EAAE;AAClC,gBAAA,MAAM,EAAE,kCAAkC;AAC1C,gBAAA,KAAK,EAAE,OAAO,CAAC,yCAAyC,CAAC;AACzD,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,gCAAgC,EAAE;AAChC,gBAAA,MAAM,EAAE,gCAAgC;AACxC,gBAAA,KAAK,EAAE,OAAO,CAAC,gCAAgC,CAAC;AAChD,gBAAA,WAAW,EAAE,OAAO,CAClB,wKAAwK,CACzK;AACD,gBAAA,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACzE,aAAA;AACD,YAAA,8BAA8B,EAAE;AAC9B,gBAAA,MAAM,EAAE,8BAA8B;AACtC,gBAAA,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC;AACvC,gBAAA,WAAW,EAAE,OAAO,CAClB,wGAAwG,CACzG;AACD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA,CAAE;AAC/C,gBAAA,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;AACpC,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjD,aAAA;AACD,YAAA,kCAAkC,EAAE;AAClC,gBAAA,MAAM,EAAE,kCAAkC;AAC1C,gBAAA,KAAK,EAAE,OAAO,CAAC,oCAAoC,CAAC;AACpD,gBAAA,WAAW,EAAE,OAAO,CAClB,qKAAqK,CACtK;AACD,gBAAA,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACrE,aAAA;AACD,YAAA,gCAAgC,EAAE;AAChC,gBAAA,MAAM,EAAE,gCAAgC;AACxC,gBAAA,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC;AACzC,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA;AACE,wBAAA,KAAK,EAAE,YAAY;AACnB,wBAAA,IAAI,EAAE,OAAO,CAAC,sBAAsB;AACrC,qBAAA;AACD,oBAAA;AACE,wBAAA,KAAK,EAAE,gBAAgB;AACvB,wBAAA,IAAI,EAAE,OAAO,CAAC,iBAAiB;AAChC,qBAAA;AACD,oBAAA;AACE,wBAAA,KAAK,EAAE,iBAAiB;AACxB,wBAAA,IAAI,EAAE,OAAO,CAAC,iBAAiB;AAChC;AACF,iBAAA;AACD,gBAAA,UAAU,EAAE,IAAI;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,gBAAgB,EAAE;AAChB,gBAAA,MAAM,EAAE,gBAAgB;AACxB,gBAAA,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC;AAC1B,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA;AACE,wBAAA,KAAK,EAAE,MAAM;AACb,wBAAA,IAAI,EAAE;AACP,qBAAA;AACD,oBAAA;AACE,wBAAA,KAAK,EAAE,OAAO;AACd,wBAAA,IAAI,EAAE;AACP;AACF,iBAAA;AACD,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,4BAA4B,EAAE;AAC5B,gBAAA,MAAM,EAAE,4BAA4B;AACpC,gBAAA,KAAK,EAAE,OAAO,CAAC,sBAAsB,CAAC;AACtC,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,YAAY,EAAE;AACZ,gBAAA,MAAM,EAAE,YAAY;AACpB,gBAAA,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;AACtB,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA,CAAE;AAC/C,gBAAA,iBAAiB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE;AAC3C,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,YAAY,EAAE;AACZ,gBAAA,MAAM,EAAE,YAAY;AACpB,gBAAA,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;AACtB,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA,CAAE;AAC/C,gBAAA,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;gBACpC,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACxE,aAAA;AACD,YAAA,gBAAgB,EAAE;AAChB,gBAAA,MAAM,EAAE,gBAAgB;AACxB,gBAAA,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC;AAC1B,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,4BAA4B,EAAE;AAC5B,gBAAA,MAAM,EAAE,4BAA4B;AACpC,gBAAA,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC;AAC1B,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,YAAY,EAAE;AACZ,gBAAA,MAAM,EAAE,YAAY;AACpB,gBAAA,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC;AAChC,gBAAA,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;AAChD,aAAA;AACD,YAAA,+CAA+C,EAAE;AAC/C,gBAAA,MAAM,EAAE,+CAA+C;AACvD,gBAAA,KAAK,EAAE,OAAO,CAAC,+CAA+C,CAAC;AAC/D,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,6BAA6B,EAAE;AAC7B,gBAAA,MAAM,EAAE,6BAA6B;AACrC,gBAAA,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC;AAC/B,gBAAA,WAAW,EAAE,OAAO,CAAC,oDAAoD,CAAC;AAC1E,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,oCAAoC,EAAE;AACpC,gBAAA,MAAM,EAAE,oCAAoC;AAC5C,gBAAA,KAAK,EAAE,OAAO,CAAC,uDAAuD,CAAC;AACvE,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,qMAAqM,CACtM,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,6CAA6C,EAAE;AAC7C,gBAAA,MAAM,EAAE,6CAA6C;AACrD,gBAAA,KAAK,EAAE,OAAO,CAAC,2DAA2D,CAAC;AAC3E,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,sCAAsC,EAAE;AACtC,gBAAA,MAAM,EAAE,sCAAsC;AAC9C,gBAAA,KAAK,EAAE,OAAO,CAAC,6CAA6C,CAAC;AAC7D,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CAAC,mDAAmD,CAAC,CAAA,CAAE;AAC9E,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,+BAA+B,EAAE;AAC/B,gBAAA,MAAM,EAAE,+BAA+B;AACvC,gBAAA,KAAK,EAAE,OAAO,CAAC,2BAA2B,CAAC;AAC3C,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,uLAAuL,CACxL,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,0BAA0B,EAAE;AAC1B,gBAAA,MAAM,EAAE,0BAA0B;AAClC,gBAAA,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC;AAC/B,gBAAA,WAAW,EAAE,OAAO,CAClB,qJAAqJ,CACtJ;AACD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,uBAAuB,EAAE;AACvB,gBAAA,MAAM,EAAE,uBAAuB;AAC/B,gBAAA,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC;AAChC,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,qJAAqJ,CACtJ,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,wCAAwC,EAAE;AACxC,gBAAA,MAAM,EAAE,wCAAwC;AAChD,gBAAA,KAAK,EAAE,OAAO,CAAC,iCAAiC,CAAC;AACjD,gBAAA,WAAW,EAAE,OAAO,CAAC,mCAAmC,CAAC;AACzD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,8CAA8C,EAAE;AAC9C,gBAAA,MAAM,EAAE,8CAA8C;AACtD,gBAAA,KAAK,EAAE,OAAO,CAAC,iCAAiC,CAAC;AACjD,gBAAA,WAAW,EAAE,OAAO,CAAC,sCAAsC,CAAC;AAC5D,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,OAAO,CAAC,kCAAkC,CAAC;AACxD,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,oBAAoB,EAAE;AACpB,gBAAA,MAAM,EAAE,oBAAoB;AAC5B,gBAAA,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC;AACrB,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,OAAO,CAClB,4MAA4M,CAC7M;AACD,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,oCAAoC,EAAE;AACpC,gBAAA,MAAM,EAAE,oCAAoC;AAC5C,gBAAA,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC;AACvC,gBAAA,WAAW,EAAE,OAAO,CAAC,yDAAyD,CAAC;AAC/E,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,qCAAqC,EAAE;AACrC,gBAAA,MAAM,EAAE,qCAAqC;AAC7C,gBAAA,KAAK,EAAE,OAAO,CAAC,wBAAwB,CAAC;AACxC,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,+HAA+H,CAChI,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,oCAAoC,EAAE;AACpC,gBAAA,MAAM,EAAE,oCAAoC;AAC5C,gBAAA,KAAK,EAAE,OAAO,CAAC,8BAA8B,CAAC;AAC9C,gBAAA,WAAW,EAAE,OAAO,CAAC,iEAAiE,CAAC;AACvF,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,qCAAqC,EAAE;AACrC,gBAAA,MAAM,EAAE,qCAAqC;AAC7C,gBAAA,KAAK,EAAE,OAAO,CAAC,+BAA+B,CAAC;AAC/C,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,uIAAuI,CACxI,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,oCAAoC,EAAE;AACpC,gBAAA,MAAM,EAAE,oCAAoC;AAC5C,gBAAA,KAAK,EAAE,OAAO,CAAC,gDAAgD,CAAC;AAChE,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,uCAAuC,EAAE;AACvC,gBAAA,MAAM,EAAE,uCAAuC;AAC/C,gBAAA,KAAK,EAAE,OAAO,CAAC,4CAA4C,CAAC;AAC5D,gBAAA,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;AAChD,aAAA;AACD,YAAA,4BAA4B,EAAE;AAC5B,gBAAA,MAAM,EAAE,4BAA4B;AACpC,gBAAA,KAAK,EAAE,OAAO,CAAC,gCAAgC,CAAC;AAChD,gBAAA,WAAW,EAAE,OAAO,CAClB,kFAAkF,CACnF;AACD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE;AAC5B,aAAA;AACD,YAAA,yBAAyB,EAAE;AACzB,gBAAA,MAAM,EAAE,yBAAyB;AACjC,gBAAA,KAAK,EAAE,OAAO,CAAC,iCAAiC,CAAC;AACjD,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CACrB,kFAAkF,CACnF,CAAA,CAAE;AACH,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;AAC5B,gBAAA,aAAa,EAAE;AAChB,aAAA;AACD,YAAA,6BAA6B,EAAE;AAC7B,gBAAA,MAAM,EAAE,6BAA6B;AACrC,gBAAA,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC;AACvC,gBAAA,WAAW,EAAE,OAAO,CAClB,0NAA0N,CAC3N;AACD,gBAAA,0BAA0B,EAAE;oBAC1B,WAAW,EAAE,IAAI,CAAC;AACnB,iBAAA;AACD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;gBAC5B,WAAW,EAAE,IAAI,CAAC;AACnB,aAAA;AACD,YAAA,oCAAoC,EAAE;AACpC,gBAAA,MAAM,EAAE,oCAAoC;AAC5C,gBAAA,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC;AAChC,gBAAA,WAAW,EAAE,OAAO,CAClB,gLAAgL,CACjL;AACD,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,WAAW,EAAE,CAAA,EAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA,CAAE;AAC/C,gBAAA,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;AACpC,gBAAA,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjD;SACF;AAED,QAAA,IAAA,CAAA,aAAa,GAAG;AACd,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC;AAC3B,gBAAA,EAAE,EAAE,kBAAkB;AACtB,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,kCAAkC,CAAC;AAC7E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,gCAAgC,CAAC;AAC3E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,8BAA8B,CAAC;AACzE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,kCAAkC;AAC7E;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,2BAA2B,CAAC;AAC3C,gBAAA,EAAE,EAAE,gCAAgC;AACpC,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,8CAA8C;AACzF;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC;AAC9B,gBAAA,EAAE,EAAE,oBAAoB;gBACxB,KAAK,EAAE,CAAC,IAAI,CAAC,oCAAoC,CAAC,oBAAoB,CAAC;AACxE,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC;AAChC,gBAAA,EAAE,EAAE,sBAAsB;AAC1B,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,+CAA+C,CAAC;AAC1F,oBAAA,IAAI,CAAC,oCAAoC,CAAC,oCAAoC,CAAC;AAC/E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,6CAA6C,CAAC;AACxF,oBAAA,IAAI,CAAC,oCAAoC,CAAC,6BAA6B,CAAC;AACxE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,sCAAsC,CAAC;AACjF,oBAAA,IAAI,CAAC,oCAAoC,CAAC,+BAA+B;AAC1E;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC;AAC9B,gBAAA,EAAE,EAAE,oBAAoB;AACxB,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,6BAA6B,CAAC;AACxE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,oCAAoC;AAC/E;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC;AAC9B,gBAAA,EAAE,EAAE,oBAAoB;AACxB,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,gCAAgC,CAAC;AAC3E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,YAAY,CAAC;AACvD,oBAAA,IAAI,CAAC,oCAAoC,CAAC,YAAY,CAAC;AACvD,oBAAA,IAAI,CAAC,oCAAoC,CAAC,gBAAgB,CAAC;AAC3D,oBAAA,IAAI,CAAC,oCAAoC,CAAC,4BAA4B,CAAC;AACvE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,YAAY;AACvD;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC;AAC7B,gBAAA,EAAE,EAAE,mBAAmB;AACvB,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,0BAA0B,CAAC;AACrE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,uBAAuB,CAAC;AAClE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,wCAAwC;AACnF;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,eAAe,CAAC;AAC/B,gBAAA,EAAE,EAAE,qBAAqB;AACzB,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,oCAAoC,CAAC;AAC/E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,qCAAqC,CAAC;AAChF,oBAAA,IAAI,CAAC,oCAAoC,CAAC,oCAAoC,CAAC;AAC/E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,qCAAqC;AAChF;AACF,aAAA;AACD,YAAA;AACE,gBAAA,KAAK,EAAE,OAAO,CAAC,oBAAoB,CAAC;AACpC,gBAAA,EAAE,EAAE,0BAA0B;AAC9B,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,CAAC,oCAAoC,CAAC,oCAAoC,CAAC;AAC/E,oBAAA,IAAI,CAAC,oCAAoC,CAAC,uCAAuC,CAAC;AAClF,oBAAA,IAAI,CAAC,oCAAoC,CAAC,4BAA4B,CAAC;AACvE,oBAAA,IAAI,CAAC,oCAAoC,CAAC,yBAAyB;AACpE;AACF;SACF;IAE2C;+GAtYjC,wCAAwC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,QAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAxC,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wCAAwC,cAFvC,MAAM,EAAA,CAAA,CAAA;;4FAEP,wCAAwC,EAAA,UAAA,EAAA,CAAA;kBAHpD,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;MCqBY,kCAAkC,CAAA;IAC7C,IACI,cAAc,CAAC,QAAkB,EAAA;AACnC,QAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;YAC1B;QACF;AACA,QAAA,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,IACvC,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,CAAC,CAC7E;IACH;IAEA,IACI,QAAQ,CAAC,QAAiB,EAAA;AAC5B,QAAA,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;IACrD;IAEA,IACI,SAAS,CAAC,KAAK,EAAA;QACjB,IAAI,KAAK,EAAE;YACT,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AAC5C,YAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC1D,YAAA,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AAC3B,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;QAC5B;IACF;AAUA,IAAA,WAAA,CAAoB,mBAA6D,EAAA;QAA7D,IAAA,CAAA,mBAAmB,GAAnB,mBAAmB;QATvC,IAAA,CAAA,aAAa,GAAG,EAAE;AAGlB,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAE;AAE3B,QAAA,IAAA,CAAA,IAAI,GAAG,IAAI,SAAS,CAAC,EAAE,CAAC;AAExB,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,CAAC,mBAAmB,CAAC,aAAa;AAGpD,QAAA,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,oCAAoC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAG;AACtF,YAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAClB,OAAO,EACP,mBAAmB,CAAC,oCAAoC,CAAC,OAAO,CAAC,CAAC,OAAO,CAC1E;AACH,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;AACH,IAAA,kBAAkB,CAAC,OAAe,EAAA;AAChC,QAAA,MAAM,WAAW,GAAW,IAAI,CAAC,mBAAmB,CAAC,oCAAoC;AACzF,QAAA,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAI;YAClD,IACE,WAAW,CAAC,GAAG,CAAC;AAChB,iBAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAC3E;AACA,gBAAA,IAAI;oBACF,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACrC;AAAE,gBAAA,MAAM;AACN,oBAAA,OAAO,CAAC,GAAG,CAAC,GAAG,QAAQ;gBACzB;YACF;AACF,QAAA,CAAC,CAAC;IACJ;AAEA;;AAEG;AACH,IAAA,SAAS,CAAC,OAAe,EAAA;AACvB,QAAA,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;AAEhC,QAAA,OAAO,OAAO,CAAC,gCAAgC,CAAC;AAChD,QAAA,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAC/C,MAAM,mBAAmB,GAAG,OAAO,CAAC,4BAA4B,CAAC,IAAI,KAAK;AAC1E,QAAA,IAAI,aAAa,KAAK,MAAM,EAAE;YAC5B,IAAI,mBAAmB,EAAE;AACvB,gBAAA,OAAO,CAAC,gCAAgC,CAAC,GAAG,gBAAgB;YAC9D;iBAAO;AACL,gBAAA,OAAO,CAAC,gCAAgC,CAAC,GAAG,YAAY;YAC1D;QACF;AAAO,aAAA,IAAI,aAAa,KAAK,OAAO,EAAE;AACpC,YAAA,OAAO,CAAC,gCAAgC,CAAC,GAAG,iBAAiB;QAC/D;aAAO;AACL,YAAA,OAAO,CAAC,gCAAgC,CAAC,GAAG,SAAS;QACvD;AACA,QAAA,OAAO,OAAO;IAChB;AAEA;;;AAGG;AACH,IAAA,UAAU,CAAC,KAAK,EAAA;AACd,QAAA,MAAM,qBAAqB,GAAG,KAAK,CAAC,gCAAgC,CAAC;QACrE,IAAI,qBAAqB,EAAE;;YAEzB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAChE,YAAA,KAAK,CAAC,gBAAgB,CAAC,GAAG,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,GAAG,QAAQ;;YAGtE,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAClE,YAAA,KAAK,CAAC,4BAA4B,CAAC,GAAG,UAAU,KAAK,WAAW;AAChE,YAAA,OAAO,KAAK,CAAC,gCAAgC,CAAC;QAChD;AAEA,QAAA,OAAO,KAAK;IACd;IAEA,cAAc,GAAA;QACZ,MAAM,WAAW,GAAG,EAAE;AAEtB,QAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,IAAG;YAC5C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAE9C,YAAA,IAAI,cAAc,CAAC,KAAK,EAAE;AACxB,gBAAA,WAAW,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,KAAK;YACzC;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,WAAW;IACpB;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;AACnB,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE;YAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;AACrD,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;QAClC;IACF;+GA9HW,kCAAkC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,wCAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;mGAAlC,kCAAkC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,CAAA,eAAA,EAAA,gBAAA,CAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5B/C,8uQA2QA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED5PI,WAAW,q5CACX,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACnB,KAAK,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACL,QAAQ,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACR,YAAY,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACZ,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,qBAAqB,EAAA,QAAA,EAAA,6BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACrB,kBAAkB,uIAClB,iCAAiC,EAAA,QAAA,EAAA,yCAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjC,IAAI,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EACJ,gBAAgB,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAGP,kCAAkC,EAAA,UAAA,EAAA,CAAA;kBAjB9C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iCAAiC,EAAA,OAAA,EAElC;wBACP,WAAW;wBACX,mBAAmB;wBACnB,KAAK;wBACL,QAAQ;wBACR,YAAY;wBACZ,gBAAgB;wBAChB,qBAAqB;wBACrB,kBAAkB;wBAClB,iCAAiC;wBACjC,IAAI;wBACJ;AACD,qBAAA,EAAA,QAAA,EAAA,8uQAAA,EAAA;;sBAGA,KAAK;uBAAC,eAAe;;sBAUrB;;sBAKA;;sBAWA;;;ME9CU,2BAA2B,CAAA;+GAA3B,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;gHAA3B,2BAA2B,EAAA,OAAA,EAAA,CAH5B,YAAY,EAAEC,aAAW,EAAE,mBAAmB,EAAE,kCAAkC,CAAA,EAAA,OAAA,EAAA,CAClF,kCAAkC,CAAA,EAAA,CAAA,CAAA;AAEjC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,2BAA2B,YAH5B,YAAY,EAAEA,aAAW,EAAE,mBAAmB,EAAE,kCAAkC,CAAA,EAAA,CAAA,CAAA;;4FAGjF,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBAJvC,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,OAAO,EAAE,CAAC,YAAY,EAAEA,aAAW,EAAE,mBAAmB,EAAE,kCAAkC,CAAC;oBAC7F,OAAO,EAAE,CAAC,kCAAkC;AAC7C,iBAAA;;;ACRD;;AAEG;;;;"}
@@ -93,12 +93,19 @@ class RemoteAccessService {
93
93
  }
94
94
  /**
95
95
  * Returns the URI for the websocket connection to the remote access service.
96
+ *
97
+ * @param options.supportsHostKeyProbe when true, adds a `supportsHostKeyProbe=true` query parameter
98
+ * telling the backend this UI can render the first-use SSH host-key probe frame (DM-6421). A browser
99
+ * WebSocket cannot send custom headers, so the capability is negotiated via the URL. Older UIs omit
100
+ * it, so its absence keeps the backend on the backward-compatible path (no probe).
96
101
  */
97
- getWebSocketUri(deviceId, configurationId) {
102
+ getWebSocketUri(deviceId, configurationId, options = {}) {
98
103
  const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();
104
+ const featureParams = options.supportsHostKeyProbe ? 'supportsHostKeyProbe=true' : '';
105
+ const queryParams = [authQueryParams, featureParams].filter(Boolean).join('&');
99
106
  const protocol = this.document.location.protocol === 'http:' ? 'ws' : 'wss';
100
107
  const pathName = `${protocol}://${this.document.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}`;
101
- return authQueryParams ? `${pathName}?${authQueryParams}` : pathName;
108
+ return queryParams ? `${pathName}?${queryParams}` : pathName;
102
109
  }
103
110
  /**
104
111
  * Retrieves all configurations for a given device.
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-remote-access-data.mjs","sources":["../../remote-access/data/remote-access.service.ts","../../remote-access/data/c8y-ngx-components-remote-access-data.ts"],"sourcesContent":["import { DOCUMENT, inject, Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivateFn } from '@angular/router';\nimport { FetchClient, IManagedObject } from '@c8y/client';\nimport {\n ContextRouteService,\n Permissions,\n ServiceRegistry,\n ViewContext\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { Observable, defer, shareReplay } from 'rxjs';\nimport { RemoteAccessProtocolProvider } from './remote-access-protocol-provider';\nimport { uniqWith, intersectionWith, isEqual } from 'lodash';\n\nexport interface RemoteAccessConfiguration {\n id: string;\n name: string;\n hostname: string;\n port: number;\n protocol: string;\n attrs?: any;\n credentials?: any;\n credentialsType?: string;\n}\n\nexport const CREDENTIALS_TYPES = {\n NONE: {\n name: 'NONE',\n value: 'NONE',\n label: gettext('No password')\n },\n USER_PASS: {\n name: 'USER_PASS',\n value: 'USER_PASS',\n label: gettext('Username and password')\n },\n PASS_ONLY: {\n name: 'PASS_ONLY',\n value: 'PASS_ONLY',\n label: gettext('Password only')\n },\n KEY_PAIR: {\n name: 'KEY_PAIR',\n value: 'KEY_PAIR',\n label: gettext('Public/private keys')\n },\n CERTIFICATE: {\n name: 'CERTIFICATE',\n value: 'CERTIFICATE',\n label: gettext('Certificate')\n }\n} as const;\n\nexport const canActivateRemoteAccess: CanActivateFn = (route: ActivatedRouteSnapshot) => {\n const permissions = inject(Permissions);\n const remoteAccessService = inject(RemoteAccessService);\n const contextRouteService = inject(ContextRouteService);\n if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) {\n return false;\n }\n\n const contextDetails = contextRouteService.getContextData(route);\n if (contextDetails.context !== ViewContext.Device) {\n return false;\n }\n\n const device = contextDetails.contextData as IManagedObject;\n if (!device || !Array.isArray(device.c8y_SupportedOperations)) {\n return false;\n }\n const supportedOperations: string[] = device.c8y_SupportedOperations;\n if (!supportedOperations.includes('c8y_RemoteAccessConnect')) {\n return false;\n }\n return remoteAccessService.isAvailable$();\n};\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RemoteAccessService {\n private cachedIsAvailable$: Observable<boolean>;\n readonly baseUrl = '/service/remoteaccess';\n private document = inject(DOCUMENT);\n constructor(\n private fetchClient: FetchClient,\n private serviceRegistry: ServiceRegistry\n ) {}\n\n /**\n * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint.\n * @returns cached Observable that emits true if the service is available, false otherwise.\n */\n isAvailable$(): Observable<boolean> {\n if (!this.cachedIsAvailable$) {\n this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1));\n }\n\n return this.cachedIsAvailable$;\n }\n\n /**\n * misses the leading ? for the query params\n */\n getAuthQueryParamsForWebsocketConnection() {\n const { headers } = this.fetchClient.getFetchOptions();\n const params = new URLSearchParams();\n\n if (headers) {\n const xsrfToken = headers['X-XSRF-TOKEN'];\n const auth = headers['Authorization'];\n\n if (xsrfToken) {\n params.append('XSRF-TOKEN', xsrfToken);\n }\n if (auth) {\n params.append('token', auth.replace('Bearer ', '').replace('Basic ', ''));\n }\n }\n\n const paramsString = params.toString();\n return paramsString;\n }\n\n /**\n * Returns the URI for the websocket connection to the remote access service.\n */\n getWebSocketUri<K extends string, I extends string>(deviceId: K, configurationId: I) {\n const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();\n const protocol = this.document.location.protocol === 'http:' ? 'ws' : 'wss';\n const pathName =\n `${protocol}://${this.document.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}` as const;\n return authQueryParams ? (`${pathName}?${authQueryParams}` as const) : pathName;\n }\n\n /**\n * Retrieves all configurations for a given device.\n */\n async listConfigurations(deviceId: string): Promise<RemoteAccessConfiguration[]> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`\n );\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to fetch configurations for device ${deviceId}`);\n }\n\n /**\n * Deletes a configuration for a given device.\n */\n async deleteConfiguration(deviceId: string, configurationId: string) {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`,\n { method: 'DELETE' }\n );\n\n if (response.ok) {\n return;\n }\n\n throw new Error(`Failed to delete configuration for device ${deviceId}`);\n }\n\n /**\n * Retrieves all available remote access protocol providers.\n */\n getProtocolProviders() {\n return this.serviceRegistry.get('remoteAccessProtocolHook');\n }\n\n /**\n * Retrieves all supported protocol providers for a given device.\n * Based on the declarations in the fragment c8y_RemoteAccessSupportedProtocols of the device managed object.\n */\n getSupportedProtocolProvidersFor(device: IManagedObject): RemoteAccessProtocolProvider[] {\n const { c8y_RemoteAccessSupportedProtocols = [] } = device;\n const uniqueInput = uniqWith(\n c8y_RemoteAccessSupportedProtocols.map(p => p.toUpperCase()),\n isEqual\n );\n const supportedProviders = intersectionWith(\n this.getProtocolProviders(),\n uniqueInput,\n ({ protocolName }, protocol) => protocolName?.toUpperCase() === protocol\n );\n return supportedProviders?.length > 0 ? supportedProviders : this.getProtocolProviders();\n }\n\n /**\n * Creates a new configuration for a given device.\n */\n async addConfiguration(\n deviceId: string,\n configuration: Omit<RemoteAccessConfiguration, 'id'>\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Updates a configuration for a given device.\n */\n async updateConfiguration(\n deviceId: string,\n configuration: RemoteAccessConfiguration\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Persists a confirmed server host key onto a configuration (DM-6421 first-use flow). The stored\n * value is an OpenSSH authorized_keys-style string (`<keyType> <base64Blob>`).\n *\n * Uses the dedicated host-key endpoint so only the host key is sent — the untouched credential\n * secrets (password, private key, certificate) are never round-tripped through the client.\n */\n async updateHostKey(\n deviceId: string,\n configurationId: string,\n hostKey: string\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}/hostkey`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostKey })\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update host key for configuration ${configurationId}`);\n }\n\n /**\n * Whether the backend auto-trusts the server host key on first connect for the current tenant. When\n * enabled, the backend silently stores the key instead of prompting for confirmation.\n *\n * Delegates to the remote-access service rather than reading the `hostkey-autosave` tenant option\n * directly: the effective value is resolved server-side from the tenant option, owner inheritance\n * (a subtenant with no option set inherits the owner's) and the manifest default — none of which the\n * tenant-options API exposes to the client. Defaults to `false` (secure by default) when the status\n * cannot be read.\n */\n async isHostKeyAutosaveEnabled(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/settings/hostkey-autosave`);\n if (!response.ok) {\n return false;\n }\n const status = await response.json();\n return status?.enabled === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Generates a SSH key pair for a given hostname.\n */\n async generateKeyPair(hostname: string): Promise<{ publicKey: string; privateKey: string }> {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostname })\n });\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to generate key pair for ${hostname}`);\n }\n\n private async healthEndpointAvailable(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, {\n method: 'HEAD',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (response.ok) {\n return !!response.ok;\n }\n } catch {\n return false;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-remote-access-data.mjs","sources":["../../remote-access/data/remote-access.service.ts","../../remote-access/data/c8y-ngx-components-remote-access-data.ts"],"sourcesContent":["import { DOCUMENT, inject, Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivateFn } from '@angular/router';\nimport { FetchClient, IManagedObject } from '@c8y/client';\nimport {\n ContextRouteService,\n Permissions,\n ServiceRegistry,\n ViewContext\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { Observable, defer, shareReplay } from 'rxjs';\nimport { RemoteAccessProtocolProvider } from './remote-access-protocol-provider';\nimport { uniqWith, intersectionWith, isEqual } from 'lodash';\n\nexport interface RemoteAccessConfiguration {\n id: string;\n name: string;\n hostname: string;\n port: number;\n protocol: string;\n attrs?: any;\n credentials?: any;\n credentialsType?: string;\n}\n\nexport const CREDENTIALS_TYPES = {\n NONE: {\n name: 'NONE',\n value: 'NONE',\n label: gettext('No password')\n },\n USER_PASS: {\n name: 'USER_PASS',\n value: 'USER_PASS',\n label: gettext('Username and password')\n },\n PASS_ONLY: {\n name: 'PASS_ONLY',\n value: 'PASS_ONLY',\n label: gettext('Password only')\n },\n KEY_PAIR: {\n name: 'KEY_PAIR',\n value: 'KEY_PAIR',\n label: gettext('Public/private keys')\n },\n CERTIFICATE: {\n name: 'CERTIFICATE',\n value: 'CERTIFICATE',\n label: gettext('Certificate')\n }\n} as const;\n\nexport const canActivateRemoteAccess: CanActivateFn = (route: ActivatedRouteSnapshot) => {\n const permissions = inject(Permissions);\n const remoteAccessService = inject(RemoteAccessService);\n const contextRouteService = inject(ContextRouteService);\n if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) {\n return false;\n }\n\n const contextDetails = contextRouteService.getContextData(route);\n if (contextDetails.context !== ViewContext.Device) {\n return false;\n }\n\n const device = contextDetails.contextData as IManagedObject;\n if (!device || !Array.isArray(device.c8y_SupportedOperations)) {\n return false;\n }\n const supportedOperations: string[] = device.c8y_SupportedOperations;\n if (!supportedOperations.includes('c8y_RemoteAccessConnect')) {\n return false;\n }\n return remoteAccessService.isAvailable$();\n};\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RemoteAccessService {\n private cachedIsAvailable$: Observable<boolean>;\n readonly baseUrl = '/service/remoteaccess';\n private document = inject(DOCUMENT);\n constructor(\n private fetchClient: FetchClient,\n private serviceRegistry: ServiceRegistry\n ) {}\n\n /**\n * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint.\n * @returns cached Observable that emits true if the service is available, false otherwise.\n */\n isAvailable$(): Observable<boolean> {\n if (!this.cachedIsAvailable$) {\n this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1));\n }\n\n return this.cachedIsAvailable$;\n }\n\n /**\n * misses the leading ? for the query params\n */\n getAuthQueryParamsForWebsocketConnection() {\n const { headers } = this.fetchClient.getFetchOptions();\n const params = new URLSearchParams();\n\n if (headers) {\n const xsrfToken = headers['X-XSRF-TOKEN'];\n const auth = headers['Authorization'];\n\n if (xsrfToken) {\n params.append('XSRF-TOKEN', xsrfToken);\n }\n if (auth) {\n params.append('token', auth.replace('Bearer ', '').replace('Basic ', ''));\n }\n }\n\n const paramsString = params.toString();\n return paramsString;\n }\n\n /**\n * Returns the URI for the websocket connection to the remote access service.\n *\n * @param options.supportsHostKeyProbe when true, adds a `supportsHostKeyProbe=true` query parameter\n * telling the backend this UI can render the first-use SSH host-key probe frame (DM-6421). A browser\n * WebSocket cannot send custom headers, so the capability is negotiated via the URL. Older UIs omit\n * it, so its absence keeps the backend on the backward-compatible path (no probe).\n */\n getWebSocketUri(\n deviceId: string,\n configurationId: string,\n options: { supportsHostKeyProbe?: boolean } = {}\n ): string {\n const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();\n const featureParams = options.supportsHostKeyProbe ? 'supportsHostKeyProbe=true' : '';\n const queryParams = [authQueryParams, featureParams].filter(Boolean).join('&');\n const protocol = this.document.location.protocol === 'http:' ? 'ws' : 'wss';\n const pathName = `${protocol}://${this.document.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}`;\n return queryParams ? `${pathName}?${queryParams}` : pathName;\n }\n\n /**\n * Retrieves all configurations for a given device.\n */\n async listConfigurations(deviceId: string): Promise<RemoteAccessConfiguration[]> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`\n );\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to fetch configurations for device ${deviceId}`);\n }\n\n /**\n * Deletes a configuration for a given device.\n */\n async deleteConfiguration(deviceId: string, configurationId: string) {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`,\n { method: 'DELETE' }\n );\n\n if (response.ok) {\n return;\n }\n\n throw new Error(`Failed to delete configuration for device ${deviceId}`);\n }\n\n /**\n * Retrieves all available remote access protocol providers.\n */\n getProtocolProviders() {\n return this.serviceRegistry.get('remoteAccessProtocolHook');\n }\n\n /**\n * Retrieves all supported protocol providers for a given device.\n * Based on the declarations in the fragment c8y_RemoteAccessSupportedProtocols of the device managed object.\n */\n getSupportedProtocolProvidersFor(device: IManagedObject): RemoteAccessProtocolProvider[] {\n const { c8y_RemoteAccessSupportedProtocols = [] } = device;\n const uniqueInput = uniqWith(\n c8y_RemoteAccessSupportedProtocols.map(p => p.toUpperCase()),\n isEqual\n );\n const supportedProviders = intersectionWith(\n this.getProtocolProviders(),\n uniqueInput,\n ({ protocolName }, protocol) => protocolName?.toUpperCase() === protocol\n );\n return supportedProviders?.length > 0 ? supportedProviders : this.getProtocolProviders();\n }\n\n /**\n * Creates a new configuration for a given device.\n */\n async addConfiguration(\n deviceId: string,\n configuration: Omit<RemoteAccessConfiguration, 'id'>\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Updates a configuration for a given device.\n */\n async updateConfiguration(\n deviceId: string,\n configuration: RemoteAccessConfiguration\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(configuration)\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`);\n }\n\n /**\n * Persists a confirmed server host key onto a configuration (DM-6421 first-use flow). The stored\n * value is an OpenSSH authorized_keys-style string (`<keyType> <base64Blob>`).\n *\n * Uses the dedicated host-key endpoint so only the host key is sent — the untouched credential\n * secrets (password, private key, certificate) are never round-tripped through the client.\n */\n async updateHostKey(\n deviceId: string,\n configurationId: string,\n hostKey: string\n ): Promise<RemoteAccessConfiguration> {\n const response = await this.fetchClient.fetch(\n `${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}/hostkey`,\n {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostKey })\n }\n );\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to update host key for configuration ${configurationId}`);\n }\n\n /**\n * Whether the backend auto-trusts the server host key on first connect for the current tenant. When\n * enabled, the backend silently stores the key instead of prompting for confirmation.\n *\n * Delegates to the remote-access service rather than reading the `hostkey-autosave` tenant option\n * directly: the effective value is resolved server-side from the tenant option, owner inheritance\n * (a subtenant with no option set inherits the owner's) and the manifest default — none of which the\n * tenant-options API exposes to the client. Defaults to `false` (secure by default) when the status\n * cannot be read.\n */\n async isHostKeyAutosaveEnabled(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/settings/hostkey-autosave`);\n if (!response.ok) {\n return false;\n }\n const status = await response.json();\n return status?.enabled === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Generates a SSH key pair for a given hostname.\n */\n async generateKeyPair(hostname: string): Promise<{ publicKey: string; privateKey: string }> {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ hostname })\n });\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(`Failed to generate key pair for ${hostname}`);\n }\n\n private async healthEndpointAvailable(): Promise<boolean> {\n try {\n const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, {\n method: 'HEAD',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (response.ok) {\n return !!response.ok;\n }\n } catch {\n return false;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -247,7 +247,12 @@ class TerminalViewerComponent {
247
247
  this.closeSocket();
248
248
  this.firstDeviceMessageReceived.set(false);
249
249
  this.awaitingHostKeyConfirmation = false;
250
- this.socket = new WebSocket(this.remoteAccess.getWebSocketUri(this.deviceId, this.configurationId), 'binary');
250
+ this.socket = new WebSocket(
251
+ // This terminal renders the first-use SSH host-key probe frame, so advertise that capability
252
+ // to the backend (DM-6421); without it the backend skips the probe.
253
+ this.remoteAccess.getWebSocketUri(this.deviceId, this.configurationId, {
254
+ supportsHostKeyProbe: true
255
+ }), 'binary');
251
256
  this.socket.binaryType = 'arraybuffer';
252
257
  this.terminal.writeln('Establishing Websocket connection...  \r\n');
253
258
  this.socket.onopen = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-remote-access-terminal-viewer.mjs","sources":["../../remote-access/terminal-viewer/telnet-negotiator.ts","../../remote-access/terminal-viewer/shell-adapter.ts","../../remote-access/terminal-viewer/host-key.model.ts","../../remote-access/terminal-viewer/terminal-viewer.component.ts","../../remote-access/terminal-viewer/terminal-viewer.component.html","../../remote-access/terminal-viewer/c8y-ngx-components-remote-access-terminal-viewer.ts"],"sourcesContent":["import type { Terminal } from '@xterm/xterm';\n\nexport class TelnetNegotiator {\n constructor(\n private terminal: Terminal,\n private termType: string\n ) {}\n\n setTermType(type) {\n this.termType = type;\n }\n\n pushStr(str, arr) {\n for (let i = 0; i < str.length; i++) {\n arr.push(str.charCodeAt(i));\n }\n }\n\n negotiate(data) {\n const arrUint8 = new Uint8Array(data);\n const arr = [...arrUint8.values()];\n\n const sendQueue = [];\n let stringToDisplay = '';\n let chr: number;\n let code: number;\n let value: number;\n\n while (arr.length > 0) {\n chr = arr.shift();\n switch (chr) {\n case 255: // IAC\n code = arr.shift();\n value = arr.shift();\n switch (code) {\n case 253: // DO\n if (value === 24) {\n // Terminal type\n sendQueue.push(255, 251, value);\n } else if (value === 31) {\n // NAWS (Negotiate About Window Size)\n // client answers WILL NAWS\n sendQueue.push(255, 251, 31);\n // client sends IAC SB NAWS 0 terminalSize.cols 0 terminalSize.rows IAC SE\n sendQueue.push(\n 255,\n 250,\n 31,\n 0,\n this.terminal.cols,\n 0,\n this.terminal.rows,\n 255,\n 240\n );\n } else {\n // Refuse other DO requests with a WONT\n sendQueue.push(255, 252, value);\n }\n break;\n case 251: // WILL\n if (value === 1) {\n // Affirm echo with DO\n sendQueue.push(255, 253, value);\n } else {\n // Reject other WILL offers with a DONT\n sendQueue.push(255, 254, value);\n }\n break;\n case 250: // SB (subnegotiation)\n if (value === 24) {\n // TERM-TYPE subnegotiation\n if (arr[0] === 1 && arr[1] === 255 && arr[2] === 240) {\n arr.shift();\n arr.shift();\n arr.shift();\n sendQueue.push(255, 250, 24, 0);\n this.pushStr(this.termType, sendQueue);\n sendQueue.push(255, 240);\n } else {\n console.warn('Invalid subnegotiation received' + arr);\n }\n } else {\n console.warn('Ignoring SB ' + value);\n }\n break;\n case 254: // DONT\n case 252: // WONT\n default:\n break;\n }\n break;\n case 242: // Data Mark (Synch)\n code = arr.shift();\n value = arr.shift();\n break;\n default: // everything else\n stringToDisplay += String.fromCharCode(chr);\n break;\n }\n }\n\n return {\n dataToSend: sendQueue.length ? new Uint8Array(sendQueue) : '',\n isOutput: !!stringToDisplay.length\n };\n }\n}\n","import { TelnetNegotiator } from './telnet-negotiator';\nimport type { Terminal } from '@xterm/xterm';\n\nexport class ShellAdapter {\n constructor(\n private terminal: Terminal,\n private termType = 'xterm-256color'\n ) {}\n\n filterNonPrintable(str: string) {\n // get rid of �\n const helpArr = str.split('�');\n str = helpArr.join('');\n\n return str;\n }\n\n setTermType(type) {\n this.termType = type;\n }\n\n filterReceiveData(data) {\n // negotiate telnet signals, if any\n const telnet = new TelnetNegotiator(this.terminal, this.termType);\n const telnetData = telnet.negotiate(data);\n\n // decode text for display\n const textDecoder = new TextDecoder();\n const decodedToDisplay = textDecoder.decode(data);\n\n return {\n dataToSend: telnetData.dataToSend,\n dataToDisplay: telnetData.isOutput ? this.filterNonPrintable(decodedToDisplay) : ''\n };\n }\n\n filterSendData(data) {\n const sendQueue = [];\n for (let i = 0; i < data.length; i++) {\n sendQueue.push(data.charCodeAt(i));\n }\n\n return sendQueue.length ? new Uint8Array(sendQueue) : '';\n }\n}\n","/**\n * Wire model for the Cloud Remote Access first-use host-key confirmation flow (DM-6421).\n *\n * The remote-access WebSocket normally carries a raw telnet/binary shell stream. When the backend\n * runs a host-key probe (first use, `hostkey-autosave=false`, no key stored yet) it prepends a single\n * JSON control frame — delivered as a binary WebSocket frame — and then tears the socket down. The UI\n * distinguishes such a control frame from terminal bytes via the `type` discriminator.\n */\n\n/** Server host key captured during KEX, pushed to the UI for confirmation. */\nexport interface HostKeyProbeMessage {\n type: 'hostkey';\n hostname: string;\n port: number;\n /** SSH key type, e.g. `ssh-ed25519`, `ssh-rsa`. */\n keyType: string;\n /** Base64 of the raw SSH wire encoding of the key. */\n publicKey: string;\n /** OpenSSH-style SHA-256 fingerprint, e.g. `SHA256:abc123…`. Shown to the user for confirmation. */\n fingerprintSha256: string;\n /**\n * `null` = nothing stored yet (genuine first use); `true` = live key equals the stored key (safe);\n * `false` = live key differs from the stored key (rotation or MITM).\n */\n matchesStored: boolean | null;\n}\n\n/** Error raised while probing; surfaced to the user instead of a terminal session. */\nexport interface HostKeyErrorMessage {\n type: 'error';\n /** Machine-readable error identifier (contract shared with the backend `sendProbeError` frame). */\n code?: string;\n message: string;\n}\n\nexport type RemoteAccessControlFrame = HostKeyProbeMessage | HostKeyErrorMessage;\n\n/**\n * Attempts to parse an incoming WebSocket frame as a remote-access control frame. Returns the parsed\n * frame for a recognised `type`, or `null` when the data is a raw terminal byte stream (the normal\n * case) — the caller then falls through to the telnet/xterm path. Never throws.\n */\nexport function parseControlFrame(data: unknown): RemoteAccessControlFrame | null {\n if (data === null || typeof data !== 'object') {\n return null;\n }\n let bytes: Uint8Array;\n try {\n // The socket uses binaryType='arraybuffer', so frames arrive as ArrayBuffer. Constructing a\n // Uint8Array works across JS realms, unlike `instanceof ArrayBuffer` (which breaks under jsdom).\n bytes = data instanceof Uint8Array ? data : new Uint8Array(data as ArrayBuffer);\n } catch {\n return null;\n }\n // Control frames are JSON objects; a raw shell stream almost never starts with '{' (0x7b), so this\n // cheaply skips the JSON.parse attempt for terminal data.\n if (bytes.length === 0 || bytes[0] !== 0x7b) {\n return null;\n }\n try {\n const parsed = JSON.parse(new TextDecoder().decode(bytes));\n if (parsed?.type === 'hostkey' || parsed?.type === 'error') {\n return parsed as RemoteAccessControlFrame;\n }\n } catch {\n // Not JSON — raw terminal data that happened to start with '{'. Fall through to the terminal path.\n }\n return null;\n}\n\n/** Composes the OpenSSH authorized_keys-style string persisted in the configuration credentials. */\nexport function toStoredHostKey(frame: HostKeyProbeMessage): string {\n return `${frame.keyType} ${frame.publicKey}`;\n}\n","import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n OnDestroy,\n signal,\n ViewEncapsulation\n} from '@angular/core';\nimport {\n ActionBarItemComponent,\n AlertService,\n C8yTranslatePipe,\n IconDirective,\n ModalService,\n Status,\n TitleComponent\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Terminal } from '@xterm/xterm';\nimport { FitAddon } from '@xterm/addon-fit';\nimport { ShellAdapter } from './shell-adapter';\nimport { RemoteAccessService } from '@c8y/ngx-components/remote-access/data';\nimport { ActivatedRoute } from '@angular/router';\nimport {\n HostKeyProbeMessage,\n parseControlFrame,\n RemoteAccessControlFrame,\n toStoredHostKey\n} from './host-key.model';\n\n@Component({\n selector: 'c8y-terminal-viewer',\n templateUrl: './terminal-viewer.component.html',\n styleUrls: ['./terminal-viewer.component.scss'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TitleComponent, C8yTranslatePipe, ActionBarItemComponent, IconDirective]\n})\nexport class TerminalViewerComponent implements AfterViewInit, OnDestroy {\n title = '';\n container: HTMLElement | null = null;\n terminal: Terminal | null = null;\n socket: WebSocket | null = null;\n /** True once real terminal bytes start flowing (not while a host-key control frame is handled). */\n readonly firstDeviceMessageReceived = signal(false);\n readonly configurationId: string;\n readonly deviceId: string;\n protected observer: ResizeObserver;\n\n private shellAdapter: ShellAdapter;\n /** Suppresses the \"device disconnected\" banner while a probe socket is torn down for confirmation. */\n private awaitingHostKeyConfirmation = false;\n\n constructor(\n private remoteAccess: RemoteAccessService,\n private activatedRoute: ActivatedRoute,\n private modalService: ModalService,\n private alertService: AlertService,\n private translateService: TranslateService\n ) {\n this.configurationId = this.activatedRoute.snapshot.params.configurationId;\n this.deviceId = this.activatedRoute.parent.snapshot.params.id;\n }\n\n ngOnDestroy(): void {\n this.observer?.disconnect();\n this.closeSocket();\n }\n\n ngAfterViewInit(): void {\n this.container = document.getElementById('terminal-screen');\n this.terminal = new Terminal({\n fontSize: 18,\n fontFamily: 'consolas, monospace',\n cursorBlink: true\n });\n const fitAddon = new FitAddon();\n this.terminal.loadAddon(fitAddon);\n this.terminal.open(this.container);\n fitAddon.fit();\n this.shellAdapter = new ShellAdapter(this.terminal);\n this.observer = new ResizeObserver(() => fitAddon.fit());\n this.observer.observe(this.container);\n this.terminal.focus();\n\n this.terminal.onData(data => {\n if (this.firstDeviceMessageReceived()) {\n const encodedToSend = this.shellAdapter.filterSendData(data);\n if (encodedToSend.length) {\n this.socket?.send(encodedToSend);\n }\n }\n });\n\n this.connect();\n }\n\n toggleFullscreen() {\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else {\n this.container.requestFullscreen();\n }\n }\n\n /** Opens (or re-opens) the remote-access WebSocket and wires up the frame handlers. */\n private connect(): void {\n this.closeSocket();\n this.firstDeviceMessageReceived.set(false);\n this.awaitingHostKeyConfirmation = false;\n\n this.socket = new WebSocket(\n this.remoteAccess.getWebSocketUri(this.deviceId, this.configurationId),\n 'binary'\n );\n this.socket.binaryType = 'arraybuffer';\n\n this.terminal.writeln('\u001b[92mEstablishing Websocket connection... \u001b[39m \\r\\n');\n this.socket.onopen = () => {\n this.terminal.writeln(\n '\u001b[92mWebsocket connection was established successfully, waiting for device... \u001b[39m \\r\\n'\n );\n };\n\n this.socket.onclose = () => {\n if (this.awaitingHostKeyConfirmation) {\n return;\n }\n this.terminal.writeln('');\n this.terminal.writeln('\\r\\n\u001b[91mDevice disconnected. \u001b[39m \\r\\n');\n this.terminal.writeln('\\r\\n\u001b[91mWebsocket connection was closed. \u001b[39m \\r\\n');\n };\n\n this.socket.onmessage = message => {\n // On first use the backend prepends a single JSON control frame (host-key probe or error) and\n // then closes the socket. Everything else is a raw telnet/binary shell stream handled as before.\n if (!this.firstDeviceMessageReceived()) {\n const frame = parseControlFrame(message.data);\n if (frame) {\n this.handleControlFrame(frame);\n return;\n }\n this.firstDeviceMessageReceived.set(true);\n this.terminal.writeln('\u001b[92mDevice connection was established successfully. \u001b[39m \\r\\n');\n }\n const filteredData = this.shellAdapter.filterReceiveData(message.data);\n if (filteredData.dataToSend.length) {\n this.socket.send(filteredData.dataToSend);\n }\n if (filteredData.dataToDisplay.length) {\n this.terminal.write(filteredData.dataToDisplay);\n }\n };\n }\n\n private handleControlFrame(frame: RemoteAccessControlFrame): void {\n if (frame.type === 'hostkey') {\n this.awaitingHostKeyConfirmation = true;\n void this.confirmHostKey(frame);\n } else {\n this.alertService.danger(\n this.translateService.instant(gettext('Host key verification failed.')),\n frame.message\n );\n }\n }\n\n /** Shows the fingerprint confirmation dialog; on accept persists the key and reconnects. */\n private async confirmHostKey(frame: HostKeyProbeMessage): Promise<void> {\n const changed = frame.matchesStored === false;\n try {\n await this.modalService.confirm(\n this.translateService.instant(\n changed ? gettext('Host key changed') : gettext('Confirm host key')\n ),\n this.buildConfirmBody(frame, changed),\n changed ? Status.DANGER : Status.INFO,\n { ok: this.translateService.instant(gettext('Trust and connect')) },\n {},\n undefined,\n // Require the user to retype a code before trusting a key that differs from the stored one.\n changed\n );\n } catch {\n // Dismissed: abort without persisting the key and without opening a session.\n this.terminal.writeln(\n `\\r\\n\u001b[91m${this.translateService.instant(\n gettext('Host key was not confirmed. Connection aborted.')\n )} \u001b[39m \\r\\n`\n );\n return;\n }\n\n try {\n await this.remoteAccess.updateHostKey(\n this.deviceId,\n this.configurationId,\n toStoredHostKey(frame)\n );\n this.connect();\n } catch {\n this.alertService.danger(\n this.translateService.instant(gettext('Failed to save the host key.'))\n );\n }\n }\n\n private buildConfirmBody(frame: HostKeyProbeMessage, changed: boolean): string {\n const endpoint = `<code>${this.escapeHtml(frame.hostname)}:${Number(frame.port)}</code>`;\n const intro = changed\n ? this.translateService.instant(\n gettext(\n 'The host key for {{ endpoint }} has changed since it was last stored. This can happen after a legitimate key rotation, but it can also indicate a man-in-the-middle attack. Only continue if you trust the new key.'\n ),\n { endpoint }\n )\n : this.translateService.instant(\n gettext(\n 'Confirm the host key for {{ endpoint }}. Only continue if the fingerprint matches the server you expect.'\n ),\n { endpoint }\n );\n const keyType = this.translateService.instant(gettext('Key type: {{ keyType }}'), {\n keyType: this.escapeHtml(frame.keyType)\n });\n const fingerprint = this.translateService.instant(\n gettext('Fingerprint (SHA-256): {{ value }}'),\n {\n value: `<code>${this.escapeHtml(frame.fingerprintSha256)}</code>`\n }\n );\n return `${intro}<br><br>${keyType}<br>${fingerprint}`;\n }\n\n /** Escapes values interpolated into the modal's HTML body to prevent markup injection. */\n private escapeHtml(value: string): string {\n const entities: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;'\n };\n return String(value).replace(/[&<>\"']/g, char => entities[char]);\n }\n\n private closeSocket(): void {\n if (!this.socket) {\n return;\n }\n const socket = this.socket;\n this.socket = null;\n // Detach the close handler before closing so our own teardown never triggers the\n // \"device disconnected\" banner — the async onclose would otherwise fire after this returns.\n socket.onclose = null;\n const stringToSend = 'exit\\n';\n const sendQueue = [];\n for (let i = 0; i < stringToSend.length; i++) {\n sendQueue.push(stringToSend.charCodeAt(i));\n }\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(new Uint8Array(sendQueue));\n }\n socket.close();\n }\n}\n","<c8y-title>Terminal Viewer: {{ title | translate }}</c8y-title>\n\n@if (firstDeviceMessageReceived()) {\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n}\n\n<div class=\"content-fullpage\">\n <div\n class=\"inner-scroll\"\n id=\"terminal-screen\"\n ></div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"c8y-ngx-components-remote-access-terminal-viewer.mjs","sources":["../../remote-access/terminal-viewer/telnet-negotiator.ts","../../remote-access/terminal-viewer/shell-adapter.ts","../../remote-access/terminal-viewer/host-key.model.ts","../../remote-access/terminal-viewer/terminal-viewer.component.ts","../../remote-access/terminal-viewer/terminal-viewer.component.html","../../remote-access/terminal-viewer/c8y-ngx-components-remote-access-terminal-viewer.ts"],"sourcesContent":["import type { Terminal } from '@xterm/xterm';\n\nexport class TelnetNegotiator {\n constructor(\n private terminal: Terminal,\n private termType: string\n ) {}\n\n setTermType(type) {\n this.termType = type;\n }\n\n pushStr(str, arr) {\n for (let i = 0; i < str.length; i++) {\n arr.push(str.charCodeAt(i));\n }\n }\n\n negotiate(data) {\n const arrUint8 = new Uint8Array(data);\n const arr = [...arrUint8.values()];\n\n const sendQueue = [];\n let stringToDisplay = '';\n let chr: number;\n let code: number;\n let value: number;\n\n while (arr.length > 0) {\n chr = arr.shift();\n switch (chr) {\n case 255: // IAC\n code = arr.shift();\n value = arr.shift();\n switch (code) {\n case 253: // DO\n if (value === 24) {\n // Terminal type\n sendQueue.push(255, 251, value);\n } else if (value === 31) {\n // NAWS (Negotiate About Window Size)\n // client answers WILL NAWS\n sendQueue.push(255, 251, 31);\n // client sends IAC SB NAWS 0 terminalSize.cols 0 terminalSize.rows IAC SE\n sendQueue.push(\n 255,\n 250,\n 31,\n 0,\n this.terminal.cols,\n 0,\n this.terminal.rows,\n 255,\n 240\n );\n } else {\n // Refuse other DO requests with a WONT\n sendQueue.push(255, 252, value);\n }\n break;\n case 251: // WILL\n if (value === 1) {\n // Affirm echo with DO\n sendQueue.push(255, 253, value);\n } else {\n // Reject other WILL offers with a DONT\n sendQueue.push(255, 254, value);\n }\n break;\n case 250: // SB (subnegotiation)\n if (value === 24) {\n // TERM-TYPE subnegotiation\n if (arr[0] === 1 && arr[1] === 255 && arr[2] === 240) {\n arr.shift();\n arr.shift();\n arr.shift();\n sendQueue.push(255, 250, 24, 0);\n this.pushStr(this.termType, sendQueue);\n sendQueue.push(255, 240);\n } else {\n console.warn('Invalid subnegotiation received' + arr);\n }\n } else {\n console.warn('Ignoring SB ' + value);\n }\n break;\n case 254: // DONT\n case 252: // WONT\n default:\n break;\n }\n break;\n case 242: // Data Mark (Synch)\n code = arr.shift();\n value = arr.shift();\n break;\n default: // everything else\n stringToDisplay += String.fromCharCode(chr);\n break;\n }\n }\n\n return {\n dataToSend: sendQueue.length ? new Uint8Array(sendQueue) : '',\n isOutput: !!stringToDisplay.length\n };\n }\n}\n","import { TelnetNegotiator } from './telnet-negotiator';\nimport type { Terminal } from '@xterm/xterm';\n\nexport class ShellAdapter {\n constructor(\n private terminal: Terminal,\n private termType = 'xterm-256color'\n ) {}\n\n filterNonPrintable(str: string) {\n // get rid of �\n const helpArr = str.split('�');\n str = helpArr.join('');\n\n return str;\n }\n\n setTermType(type) {\n this.termType = type;\n }\n\n filterReceiveData(data) {\n // negotiate telnet signals, if any\n const telnet = new TelnetNegotiator(this.terminal, this.termType);\n const telnetData = telnet.negotiate(data);\n\n // decode text for display\n const textDecoder = new TextDecoder();\n const decodedToDisplay = textDecoder.decode(data);\n\n return {\n dataToSend: telnetData.dataToSend,\n dataToDisplay: telnetData.isOutput ? this.filterNonPrintable(decodedToDisplay) : ''\n };\n }\n\n filterSendData(data) {\n const sendQueue = [];\n for (let i = 0; i < data.length; i++) {\n sendQueue.push(data.charCodeAt(i));\n }\n\n return sendQueue.length ? new Uint8Array(sendQueue) : '';\n }\n}\n","/**\n * Wire model for the Cloud Remote Access first-use host-key confirmation flow (DM-6421).\n *\n * The remote-access WebSocket normally carries a raw telnet/binary shell stream. When the backend\n * runs a host-key probe (first use, `hostkey-autosave=false`, no key stored yet) it prepends a single\n * JSON control frame — delivered as a binary WebSocket frame — and then tears the socket down. The UI\n * distinguishes such a control frame from terminal bytes via the `type` discriminator.\n */\n\n/** Server host key captured during KEX, pushed to the UI for confirmation. */\nexport interface HostKeyProbeMessage {\n type: 'hostkey';\n hostname: string;\n port: number;\n /** SSH key type, e.g. `ssh-ed25519`, `ssh-rsa`. */\n keyType: string;\n /** Base64 of the raw SSH wire encoding of the key. */\n publicKey: string;\n /** OpenSSH-style SHA-256 fingerprint, e.g. `SHA256:abc123…`. Shown to the user for confirmation. */\n fingerprintSha256: string;\n /**\n * `null` = nothing stored yet (genuine first use); `true` = live key equals the stored key (safe);\n * `false` = live key differs from the stored key (rotation or MITM).\n */\n matchesStored: boolean | null;\n}\n\n/** Error raised while probing; surfaced to the user instead of a terminal session. */\nexport interface HostKeyErrorMessage {\n type: 'error';\n /** Machine-readable error identifier (contract shared with the backend `sendProbeError` frame). */\n code?: string;\n message: string;\n}\n\nexport type RemoteAccessControlFrame = HostKeyProbeMessage | HostKeyErrorMessage;\n\n/**\n * Attempts to parse an incoming WebSocket frame as a remote-access control frame. Returns the parsed\n * frame for a recognised `type`, or `null` when the data is a raw terminal byte stream (the normal\n * case) — the caller then falls through to the telnet/xterm path. Never throws.\n */\nexport function parseControlFrame(data: unknown): RemoteAccessControlFrame | null {\n if (data === null || typeof data !== 'object') {\n return null;\n }\n let bytes: Uint8Array;\n try {\n // The socket uses binaryType='arraybuffer', so frames arrive as ArrayBuffer. Constructing a\n // Uint8Array works across JS realms, unlike `instanceof ArrayBuffer` (which breaks under jsdom).\n bytes = data instanceof Uint8Array ? data : new Uint8Array(data as ArrayBuffer);\n } catch {\n return null;\n }\n // Control frames are JSON objects; a raw shell stream almost never starts with '{' (0x7b), so this\n // cheaply skips the JSON.parse attempt for terminal data.\n if (bytes.length === 0 || bytes[0] !== 0x7b) {\n return null;\n }\n try {\n const parsed = JSON.parse(new TextDecoder().decode(bytes));\n if (parsed?.type === 'hostkey' || parsed?.type === 'error') {\n return parsed as RemoteAccessControlFrame;\n }\n } catch {\n // Not JSON — raw terminal data that happened to start with '{'. Fall through to the terminal path.\n }\n return null;\n}\n\n/** Composes the OpenSSH authorized_keys-style string persisted in the configuration credentials. */\nexport function toStoredHostKey(frame: HostKeyProbeMessage): string {\n return `${frame.keyType} ${frame.publicKey}`;\n}\n","import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n OnDestroy,\n signal,\n ViewEncapsulation\n} from '@angular/core';\nimport {\n ActionBarItemComponent,\n AlertService,\n C8yTranslatePipe,\n IconDirective,\n ModalService,\n Status,\n TitleComponent\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Terminal } from '@xterm/xterm';\nimport { FitAddon } from '@xterm/addon-fit';\nimport { ShellAdapter } from './shell-adapter';\nimport { RemoteAccessService } from '@c8y/ngx-components/remote-access/data';\nimport { ActivatedRoute } from '@angular/router';\nimport {\n HostKeyProbeMessage,\n parseControlFrame,\n RemoteAccessControlFrame,\n toStoredHostKey\n} from './host-key.model';\n\n@Component({\n selector: 'c8y-terminal-viewer',\n templateUrl: './terminal-viewer.component.html',\n styleUrls: ['./terminal-viewer.component.scss'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [TitleComponent, C8yTranslatePipe, ActionBarItemComponent, IconDirective]\n})\nexport class TerminalViewerComponent implements AfterViewInit, OnDestroy {\n title = '';\n container: HTMLElement | null = null;\n terminal: Terminal | null = null;\n socket: WebSocket | null = null;\n /** True once real terminal bytes start flowing (not while a host-key control frame is handled). */\n readonly firstDeviceMessageReceived = signal(false);\n readonly configurationId: string;\n readonly deviceId: string;\n protected observer: ResizeObserver;\n\n private shellAdapter: ShellAdapter;\n /** Suppresses the \"device disconnected\" banner while a probe socket is torn down for confirmation. */\n private awaitingHostKeyConfirmation = false;\n\n constructor(\n private remoteAccess: RemoteAccessService,\n private activatedRoute: ActivatedRoute,\n private modalService: ModalService,\n private alertService: AlertService,\n private translateService: TranslateService\n ) {\n this.configurationId = this.activatedRoute.snapshot.params.configurationId;\n this.deviceId = this.activatedRoute.parent.snapshot.params.id;\n }\n\n ngOnDestroy(): void {\n this.observer?.disconnect();\n this.closeSocket();\n }\n\n ngAfterViewInit(): void {\n this.container = document.getElementById('terminal-screen');\n this.terminal = new Terminal({\n fontSize: 18,\n fontFamily: 'consolas, monospace',\n cursorBlink: true\n });\n const fitAddon = new FitAddon();\n this.terminal.loadAddon(fitAddon);\n this.terminal.open(this.container);\n fitAddon.fit();\n this.shellAdapter = new ShellAdapter(this.terminal);\n this.observer = new ResizeObserver(() => fitAddon.fit());\n this.observer.observe(this.container);\n this.terminal.focus();\n\n this.terminal.onData(data => {\n if (this.firstDeviceMessageReceived()) {\n const encodedToSend = this.shellAdapter.filterSendData(data);\n if (encodedToSend.length) {\n this.socket?.send(encodedToSend);\n }\n }\n });\n\n this.connect();\n }\n\n toggleFullscreen() {\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else {\n this.container.requestFullscreen();\n }\n }\n\n /** Opens (or re-opens) the remote-access WebSocket and wires up the frame handlers. */\n private connect(): void {\n this.closeSocket();\n this.firstDeviceMessageReceived.set(false);\n this.awaitingHostKeyConfirmation = false;\n\n this.socket = new WebSocket(\n // This terminal renders the first-use SSH host-key probe frame, so advertise that capability\n // to the backend (DM-6421); without it the backend skips the probe.\n this.remoteAccess.getWebSocketUri(this.deviceId, this.configurationId, {\n supportsHostKeyProbe: true\n }),\n 'binary'\n );\n this.socket.binaryType = 'arraybuffer';\n\n this.terminal.writeln('\u001b[92mEstablishing Websocket connection... \u001b[39m \\r\\n');\n this.socket.onopen = () => {\n this.terminal.writeln(\n '\u001b[92mWebsocket connection was established successfully, waiting for device... \u001b[39m \\r\\n'\n );\n };\n\n this.socket.onclose = () => {\n if (this.awaitingHostKeyConfirmation) {\n return;\n }\n this.terminal.writeln('');\n this.terminal.writeln('\\r\\n\u001b[91mDevice disconnected. \u001b[39m \\r\\n');\n this.terminal.writeln('\\r\\n\u001b[91mWebsocket connection was closed. \u001b[39m \\r\\n');\n };\n\n this.socket.onmessage = message => {\n // On first use the backend prepends a single JSON control frame (host-key probe or error) and\n // then closes the socket. Everything else is a raw telnet/binary shell stream handled as before.\n if (!this.firstDeviceMessageReceived()) {\n const frame = parseControlFrame(message.data);\n if (frame) {\n this.handleControlFrame(frame);\n return;\n }\n this.firstDeviceMessageReceived.set(true);\n this.terminal.writeln('\u001b[92mDevice connection was established successfully. \u001b[39m \\r\\n');\n }\n const filteredData = this.shellAdapter.filterReceiveData(message.data);\n if (filteredData.dataToSend.length) {\n this.socket.send(filteredData.dataToSend);\n }\n if (filteredData.dataToDisplay.length) {\n this.terminal.write(filteredData.dataToDisplay);\n }\n };\n }\n\n private handleControlFrame(frame: RemoteAccessControlFrame): void {\n if (frame.type === 'hostkey') {\n this.awaitingHostKeyConfirmation = true;\n void this.confirmHostKey(frame);\n } else {\n this.alertService.danger(\n this.translateService.instant(gettext('Host key verification failed.')),\n frame.message\n );\n }\n }\n\n /** Shows the fingerprint confirmation dialog; on accept persists the key and reconnects. */\n private async confirmHostKey(frame: HostKeyProbeMessage): Promise<void> {\n const changed = frame.matchesStored === false;\n try {\n await this.modalService.confirm(\n this.translateService.instant(\n changed ? gettext('Host key changed') : gettext('Confirm host key')\n ),\n this.buildConfirmBody(frame, changed),\n changed ? Status.DANGER : Status.INFO,\n { ok: this.translateService.instant(gettext('Trust and connect')) },\n {},\n undefined,\n // Require the user to retype a code before trusting a key that differs from the stored one.\n changed\n );\n } catch {\n // Dismissed: abort without persisting the key and without opening a session.\n this.terminal.writeln(\n `\\r\\n\u001b[91m${this.translateService.instant(\n gettext('Host key was not confirmed. Connection aborted.')\n )} \u001b[39m \\r\\n`\n );\n return;\n }\n\n try {\n await this.remoteAccess.updateHostKey(\n this.deviceId,\n this.configurationId,\n toStoredHostKey(frame)\n );\n this.connect();\n } catch {\n this.alertService.danger(\n this.translateService.instant(gettext('Failed to save the host key.'))\n );\n }\n }\n\n private buildConfirmBody(frame: HostKeyProbeMessage, changed: boolean): string {\n const endpoint = `<code>${this.escapeHtml(frame.hostname)}:${Number(frame.port)}</code>`;\n const intro = changed\n ? this.translateService.instant(\n gettext(\n 'The host key for {{ endpoint }} has changed since it was last stored. This can happen after a legitimate key rotation, but it can also indicate a man-in-the-middle attack. Only continue if you trust the new key.'\n ),\n { endpoint }\n )\n : this.translateService.instant(\n gettext(\n 'Confirm the host key for {{ endpoint }}. Only continue if the fingerprint matches the server you expect.'\n ),\n { endpoint }\n );\n const keyType = this.translateService.instant(gettext('Key type: {{ keyType }}'), {\n keyType: this.escapeHtml(frame.keyType)\n });\n const fingerprint = this.translateService.instant(\n gettext('Fingerprint (SHA-256): {{ value }}'),\n {\n value: `<code>${this.escapeHtml(frame.fingerprintSha256)}</code>`\n }\n );\n return `${intro}<br><br>${keyType}<br>${fingerprint}`;\n }\n\n /** Escapes values interpolated into the modal's HTML body to prevent markup injection. */\n private escapeHtml(value: string): string {\n const entities: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;'\n };\n return String(value).replace(/[&<>\"']/g, char => entities[char]);\n }\n\n private closeSocket(): void {\n if (!this.socket) {\n return;\n }\n const socket = this.socket;\n this.socket = null;\n // Detach the close handler before closing so our own teardown never triggers the\n // \"device disconnected\" banner — the async onclose would otherwise fire after this returns.\n socket.onclose = null;\n const stringToSend = 'exit\\n';\n const sendQueue = [];\n for (let i = 0; i < stringToSend.length; i++) {\n sendQueue.push(stringToSend.charCodeAt(i));\n }\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(new Uint8Array(sendQueue));\n }\n socket.close();\n }\n}\n","<c8y-title>Terminal Viewer: {{ title | translate }}</c8y-title>\n\n@if (firstDeviceMessageReceived()) {\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n}\n\n<div class=\"content-fullpage\">\n <div\n class=\"inner-scroll\"\n id=\"terminal-screen\"\n ></div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}