@c8y/ngx-components 1024.16.19 → 1024.18.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 (29) hide show
  1. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +14 -4
  2. package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
  3. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +1 -1
  4. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +1 -1
  6. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +77 -20
  8. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-widgets-definitions-linear-gauge.mjs +4 -3
  10. package/fesm2022/c8y-ngx-components-widgets-definitions-linear-gauge.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs +29 -7
  12. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-notes.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +24 -24
  14. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
  16. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components.mjs +159 -75
  18. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  19. package/locales/locales.pot +31 -17
  20. package/package.json +1 -1
  21. package/types/c8y-ngx-components-ai-agent-chat.d.ts +8 -1
  22. package/types/c8y-ngx-components-ai-agent-chat.d.ts.map +1 -1
  23. package/types/c8y-ngx-components-repository-configuration.d.ts +20 -4
  24. package/types/c8y-ngx-components-repository-configuration.d.ts.map +1 -1
  25. package/types/c8y-ngx-components-widgets-definitions-linear-gauge.d.ts.map +1 -1
  26. package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts +7 -0
  27. package/types/c8y-ngx-components-widgets-implementations-asset-notes.d.ts.map +1 -1
  28. package/types/c8y-ngx-components.d.ts +80 -23
  29. package/types/c8y-ngx-components.d.ts.map +1 -1
@@ -6,7 +6,7 @@ import * as i3$1 from '@c8y/client';
6
6
  import { OperationStatus, InventoryBinaryService } from '@c8y/client';
7
7
  import { gettext } from '@c8y/ngx-components/gettext';
8
8
  import * as i2 from '@c8y/ngx-components';
9
- import { IconDirective, SelectComponent, C8yTranslatePipe, BottomDrawerRef, AlertService, ValidationPattern, isBinaryFile, C8yTranslateDirective, FormGroupComponent, TypeaheadComponent, ForOfDirective, ListItemComponent, HighlightComponent, FilePickerComponent, MessagesComponent, RequiredInputPlaceholderDirective, Permissions, DatePipe, FilterInputComponent, ActionBarItemComponent, TabsetAriaDirective, EmptyStateComponent, hookRoute, ViewContext, DataGridService, BottomDrawerService, ModalService, BuiltInActionType, Status, TitleComponent, BreadcrumbComponent, BreadcrumbItemComponent, HelpComponent, DataGridComponent, EmptyStateContextDirective, GuideDocsComponent, GuideHrefDirective, NavigatorNode, hookNavigator, CoreModule, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
9
+ import { IconDirective, SelectComponent, C8yTranslatePipe, BottomDrawerRef, AlertService, ValidationPattern, isBinaryFile, C8yTranslateDirective, FormGroupComponent, TypeaheadComponent, ForOfDirective, ListItemComponent, HighlightComponent, FilePickerComponent, MessagesComponent, RequiredInputPlaceholderDirective, TextareaAutoresizeDirective, Permissions, EmptyStateComponent, DatePipe, FilterInputComponent, ActionBarItemComponent, TabsetAriaDirective, ResizableGridComponent, hookRoute, ViewContext, DataGridService, BottomDrawerService, ModalService, BuiltInActionType, Status, TitleComponent, BreadcrumbComponent, BreadcrumbItemComponent, HelpComponent, DataGridComponent, EmptyStateContextDirective, GuideDocsComponent, GuideHrefDirective, NavigatorNode, hookNavigator, CoreModule, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
10
10
  import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
11
11
  import * as i3 from '@c8y/ngx-components/repository/shared';
12
12
  import { DeviceConfigurationOperation, RepositoryService, RepositoryType, mimeTypeToEditorLanguage, SharedRepositoryModule, RepositoryItemNameGridColumn, DescriptionGridColumn, FileGridColumn, DeviceTypeGridColumn, TypeGridColumn } from '@c8y/ngx-components/repository/shared';
@@ -18,8 +18,9 @@ import { has, uniqBy } from 'lodash-es';
18
18
  import { saveAs } from 'file-saver';
19
19
  import { map } from 'rxjs/operators';
20
20
  import { pipe } from 'rxjs';
21
+ import { PopoverDirective } from 'ngx-bootstrap/popover';
21
22
  import * as i1$3 from 'ngx-bootstrap/tabs';
22
- import { TabsetComponent, TabDirective, TabsModule } from 'ngx-bootstrap/tabs';
23
+ import { TabsetComponent, TabDirective, TabHeadingDirective, TabsModule } from 'ngx-bootstrap/tabs';
23
24
  import * as i1$2 from 'ngx-bootstrap/modal';
24
25
  import { TranslateService } from '@ngx-translate/core';
25
26
 
@@ -212,7 +213,7 @@ class TextBasedConfigurationComponent {
212
213
  })).data;
213
214
  }
214
215
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TextBasedConfigurationComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.AlertService }, { token: i3.RepositoryService }, { token: DeviceConfigurationService }, { token: i3$1.InventoryService }], target: i0.ɵɵFactoryTarget.Component }); }
215
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: TextBasedConfigurationComponent, isStandalone: true, selector: "c8y-text-based-configuration", ngImport: i0, template: "<div\n class=\"d-flex d-col fit-h min-height-0\"\n [formGroup]=\"form\"\n>\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50 d-flex a-i-center\">\n <label\n class=\"m-r-8 flex-no-shrink\"\n for=\"textCfgEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"textCfgEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"language\"\n ></c8y-select>\n <div class=\"m-l-auto d-flex\">\n @if (showTextBasedConfigReload) {\n <button\n class=\"btn btn-default btn-sm a-s-center m-t-8 m-b-8\"\n title=\"{{ 'Get configuration from device' | translate }}\"\n type=\"button\"\n (click)=\"reloadConfiguration()\"\n [disabled]=\"reloadingConfig() || savingConfig()\"\n >\n @if (reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloadingConfig() }\"\n ></i>\n }\n @if (!reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"download\"\n ></i>\n }\n\n {{ 'Get configuration from device' | translate }}\n </button>\n }\n </div>\n </div>\n </fieldset>\n <div class=\"p-relative flex-grow min-height-0\">\n <c8y-editor\n class=\"p-absolute top-0 left-0 fit-w fit-h\"\n formControlName=\"config\"\n [editorOptions]=\"editorOptions()\"\n ></c8y-editor>\n </div>\n @if (latestOperation() !== undefined) {\n <c8y-operation-details\n class=\"bg-level-2 p-0\"\n [operation]=\"latestOperation()\"\n ></c8y-operation-details>\n }\n @if (showTextBasedConfigSave) {\n <div class=\"card-footer flex-no-shrink fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(configControl.value)\"\n [disabled]=\"reloadingConfig() || savingConfig() || !configControl.value\"\n [ngClass]=\"{ 'btn-pending': savingConfig() }\"\n >\n @if (!savingConfig()) {\n <span title=\"{{ 'Send' | translate }}\">\n {{ 'Send configuration to device' | translate }}\n </span>\n }\n @if (savingConfig()) {\n <span title=\"{{ 'Sending\u2026' | translate }}\">\n {{ 'Sending\u2026' | translate }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: SelectComponent, selector: "c8y-select", inputs: ["placeholder", "items", "selected", "container", "multi", "canSelectWithSpace", "disabled", "autoClose", "insideClick", "required", "canDeselect", "name", "icon", "filterItems"], outputs: ["onSelect", "onDeselect", "onIconClick"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
216
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: TextBasedConfigurationComponent, isStandalone: true, selector: "c8y-text-based-configuration", ngImport: i0, template: "<div\n class=\"d-flex d-col fit-h min-height-0\"\n [formGroup]=\"form\"\n>\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50 d-flex a-i-center\">\n <label\n class=\"m-r-8 flex-no-shrink\"\n for=\"textCfgEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"textCfgEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"language\"\n ></c8y-select>\n <div class=\"m-l-auto d-flex\">\n @if (showTextBasedConfigReload) {\n <button\n class=\"btn btn-default btn-sm a-s-center m-t-8 m-b-8\"\n title=\"{{ 'Get configuration from device' | translate }}\"\n type=\"button\"\n (click)=\"reloadConfiguration()\"\n [disabled]=\"reloadingConfig() || savingConfig()\"\n >\n @if (reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloadingConfig() }\"\n ></i>\n }\n @if (!reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"arrow-down\"\n ></i>\n }\n\n {{ 'Get configuration from device' | translate }}\n </button>\n }\n </div>\n </div>\n </fieldset>\n <div class=\"p-relative flex-grow min-height-0\">\n <c8y-editor\n class=\"p-absolute top-0 left-0 fit-w fit-h\"\n formControlName=\"config\"\n [editorOptions]=\"editorOptions()\"\n ></c8y-editor>\n </div>\n @if (latestOperation() !== undefined) {\n <c8y-operation-details\n class=\"bg-level-2 p-0\"\n [operation]=\"latestOperation()\"\n ></c8y-operation-details>\n }\n @if (showTextBasedConfigSave) {\n <div class=\"card-footer flex-no-shrink fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(configControl.value)\"\n [disabled]=\"reloadingConfig() || savingConfig() || !configControl.value\"\n [ngClass]=\"{ 'btn-pending': savingConfig() }\"\n >\n @if (!savingConfig()) {\n <span title=\"{{ 'Send' | translate }}\">\n {{ 'Send configuration to device' | translate }}\n </span>\n }\n @if (savingConfig()) {\n <span title=\"{{ 'Sending\u2026' | translate }}\">\n {{ 'Sending\u2026' | translate }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: SelectComponent, selector: "c8y-select", inputs: ["placeholder", "items", "selected", "container", "multi", "canSelectWithSpace", "disabled", "autoClose", "insideClick", "required", "canDeselect", "name", "icon", "filterItems"], outputs: ["onSelect", "onDeselect", "onIconClick"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
216
217
  }
217
218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TextBasedConfigurationComponent, decorators: [{
218
219
  type: Component,
@@ -224,7 +225,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
224
225
  OperationDetailsComponent,
225
226
  C8yTranslatePipe,
226
227
  SelectComponent
227
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div\n class=\"d-flex d-col fit-h min-height-0\"\n [formGroup]=\"form\"\n>\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50 d-flex a-i-center\">\n <label\n class=\"m-r-8 flex-no-shrink\"\n for=\"textCfgEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"textCfgEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"language\"\n ></c8y-select>\n <div class=\"m-l-auto d-flex\">\n @if (showTextBasedConfigReload) {\n <button\n class=\"btn btn-default btn-sm a-s-center m-t-8 m-b-8\"\n title=\"{{ 'Get configuration from device' | translate }}\"\n type=\"button\"\n (click)=\"reloadConfiguration()\"\n [disabled]=\"reloadingConfig() || savingConfig()\"\n >\n @if (reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloadingConfig() }\"\n ></i>\n }\n @if (!reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"download\"\n ></i>\n }\n\n {{ 'Get configuration from device' | translate }}\n </button>\n }\n </div>\n </div>\n </fieldset>\n <div class=\"p-relative flex-grow min-height-0\">\n <c8y-editor\n class=\"p-absolute top-0 left-0 fit-w fit-h\"\n formControlName=\"config\"\n [editorOptions]=\"editorOptions()\"\n ></c8y-editor>\n </div>\n @if (latestOperation() !== undefined) {\n <c8y-operation-details\n class=\"bg-level-2 p-0\"\n [operation]=\"latestOperation()\"\n ></c8y-operation-details>\n }\n @if (showTextBasedConfigSave) {\n <div class=\"card-footer flex-no-shrink fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(configControl.value)\"\n [disabled]=\"reloadingConfig() || savingConfig() || !configControl.value\"\n [ngClass]=\"{ 'btn-pending': savingConfig() }\"\n >\n @if (!savingConfig()) {\n <span title=\"{{ 'Send' | translate }}\">\n {{ 'Send configuration to device' | translate }}\n </span>\n }\n @if (savingConfig()) {\n <span title=\"{{ 'Sending\u2026' | translate }}\">\n {{ 'Sending\u2026' | translate }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n" }]
228
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div\n class=\"d-flex d-col fit-h min-height-0\"\n [formGroup]=\"form\"\n>\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50 d-flex a-i-center\">\n <label\n class=\"m-r-8 flex-no-shrink\"\n for=\"textCfgEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"textCfgEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"language\"\n ></c8y-select>\n <div class=\"m-l-auto d-flex\">\n @if (showTextBasedConfigReload) {\n <button\n class=\"btn btn-default btn-sm a-s-center m-t-8 m-b-8\"\n title=\"{{ 'Get configuration from device' | translate }}\"\n type=\"button\"\n (click)=\"reloadConfiguration()\"\n [disabled]=\"reloadingConfig() || savingConfig()\"\n >\n @if (reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloadingConfig() }\"\n ></i>\n }\n @if (!reloadingConfig()) {\n <i\n class=\"m-r-4\"\n c8yIcon=\"arrow-down\"\n ></i>\n }\n\n {{ 'Get configuration from device' | translate }}\n </button>\n }\n </div>\n </div>\n </fieldset>\n <div class=\"p-relative flex-grow min-height-0\">\n <c8y-editor\n class=\"p-absolute top-0 left-0 fit-w fit-h\"\n formControlName=\"config\"\n [editorOptions]=\"editorOptions()\"\n ></c8y-editor>\n </div>\n @if (latestOperation() !== undefined) {\n <c8y-operation-details\n class=\"bg-level-2 p-0\"\n [operation]=\"latestOperation()\"\n ></c8y-operation-details>\n }\n @if (showTextBasedConfigSave) {\n <div class=\"card-footer flex-no-shrink fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(configControl.value)\"\n [disabled]=\"reloadingConfig() || savingConfig() || !configControl.value\"\n [ngClass]=\"{ 'btn-pending': savingConfig() }\"\n >\n @if (!savingConfig()) {\n <span title=\"{{ 'Send' | translate }}\">\n {{ 'Send configuration to device' | translate }}\n </span>\n }\n @if (savingConfig()) {\n <span title=\"{{ 'Sending\u2026' | translate }}\">\n {{ 'Sending\u2026' | translate }}\n </span>\n }\n </button>\n </div>\n }\n</div>\n" }]
228
229
  }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.AlertService }, { type: i3.RepositoryService }, { type: DeviceConfigurationService }, { type: i3$1.InventoryService }] });
229
230
 
230
231
  class DeviceConfigurationGuard {
@@ -325,6 +326,12 @@ class ConfigurationDetailComponent {
325
326
  this.cdr = inject(ChangeDetectorRef);
326
327
  this.binary = { file: undefined, url: undefined };
327
328
  this.mo = {};
329
+ /**
330
+ * Whether the drawer was opened from a device's Configuration tab rather than the
331
+ * Configuration Repository itself — controls whether titles/warnings spell out that
332
+ * the change lands in the shared repository, which isn't obvious from that context.
333
+ */
334
+ this.isDeviceContext = false;
328
335
  this.form = new FormGroup({
329
336
  version: new FormControl('', [
330
337
  Validators.required,
@@ -376,7 +383,14 @@ class ConfigurationDetailComponent {
376
383
  : picked;
377
384
  }, ...(ngDevMode ? [{ debugName: "editorLanguage" }] : /* istanbul ignore next */ []));
378
385
  this.editorLanguages = [AUTO_LANGUAGE_OPTION, ...EDITOR_LANGUAGES];
379
- this.submitButtonTitle = computed(() => this.mo?.id ? gettext('Update configuration') : gettext('Add configuration'), ...(ngDevMode ? [{ debugName: "submitButtonTitle" }] : /* istanbul ignore next */ []));
386
+ this.drawerTitle = computed(() => {
387
+ if (this.isDeviceContext) {
388
+ return this.mo?.id
389
+ ? gettext('Edit configuration in repository')
390
+ : gettext('Save configuration to repository');
391
+ }
392
+ return this.mo?.id ? gettext('Edit configuration') : gettext('Add configuration');
393
+ }, ...(ngDevMode ? [{ debugName: "drawerTitle" }] : /* istanbul ignore next */ []));
380
394
  this.form.controls.uploadChoice.valueChanges.pipe(takeUntilDestroyed()).subscribe(choice => {
381
395
  const ctrl = this.form.controls.editorFilename;
382
396
  if (choice === 'editInline') {
@@ -532,7 +546,7 @@ class ConfigurationDetailComponent {
532
546
  }
533
547
  }
534
548
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ConfigurationDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
535
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: ConfigurationDetailComponent, isStandalone: true, selector: "c8y-configuration-detail", inputs: { version: "version", description: "description", binary: "binary", deviceType: "deviceType", mo: "mo" }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div class=\"card-header j-c-center separator flex-no-shrink p-24\">\n <i\n class=\"m-r-8\"\n [c8yIcon]=\"'cogs'\"\n aria-hidden=\"true\"\n ></i>\n <h4 id=\"drawerTitle\">\n @if (mo?.id) {\n {{ 'Update configuration' | translate }}\n } @else {\n {{ 'Add configuration' | translate }}\n }\n </h4>\n</div>\n\n<form\n class=\"d-contents\"\n [formGroup]=\"form\"\n (ngSubmit)=\"save()\"\n>\n <div\n class=\"card-body inner-scroll p-24\"\n [class.d-col]=\"form.value.uploadChoice === 'editInline'\"\n >\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confVersion\"\n translate\n >\n Name\n </label>\n <input\n class=\"form-control\"\n id=\"confVersion\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDeviceType\"\n translate\n >\n Device type\n </label>\n <input\n class=\"form-control\"\n id=\"confDeviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDescription\"\n translate\n >\n Description\n </label>\n <input\n class=\"form-control\"\n id=\"confDescription\"\n placeholder=\"{{ 'e.g.' | translate }} Host configuration\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"description\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label translate>Configuration type</label>\n <c8y-typeahead\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n name=\"confType\"\n data-cy=\"conf-detail--configuration-type\"\n [ngModel]=\"configurationTypeMO\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"configurationTypeMO = $event\"\n maxlength=\"254\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n @let patternStr = pattern();\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n (click)=\"configurationTypeMO = config; setPipe('')\"\n [active]=\"configurationTypeMO === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"patternStr\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n @if (patternStr.length > 0) {\n <c8y-li class=\"bg-level-2 p-8\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n title=\"{{ 'Add new`configuration type`' | translate }}\"\n type=\"button\"\n translate\n >\n Add new`configuration type`\n </button>\n </c8y-li>\n }\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n\n <fieldset\n class=\"d-col\"\n [class.flex-grow]=\"form.value.uploadChoice === 'editInline'\"\n [class.min-height-0]=\"form.value.uploadChoice === 'editInline'\"\n >\n <legend\n class=\"legend form-block m-t-40\"\n translate\n >\n Configuration file\n </legend>\n\n @if (isExternalUrl()) {\n <p\n class=\"text-muted m-b-8\"\n translate\n >\n Content is sourced from a remote URL and cannot be edited inline.\n </p>\n <c8y-form-group>\n <label\n for=\"confFileUrl\"\n translate\n >\n File URL\n </label>\n <input\n class=\"form-control\"\n id=\"confFileUrl\"\n placeholder=\"https://...\"\n type=\"url\"\n autocomplete=\"off\"\n [ngModel]=\"binary.url\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"binary = { url: $event }; form.markAsDirty()\"\n />\n </c8y-form-group>\n } @else {\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'editInline']\"\n [uploadChoice]=\"form.controls.uploadChoice.value\"\n (uploadChoiceChange)=\"onUploadChoiceChange($event)\"\n [fileUrl]=\"binary.url\"\n (fileUrlChange)=\"onFileUrlChange($event)\"\n [fileBinary]=\"binary.file\"\n (fileBinaryChange)=\"onFileBinaryChange($event)\"\n (textFilePicked)=\"onTextFilePicked($event)\"\n [fileUrlPopover]=\"textForConfigurationUrlPopover\"\n >\n <ng-container c8yInlineEditor>\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-9\">\n <label\n for=\"confEditorFilename\"\n translate\n >\n Filename\n </label>\n <input\n class=\"form-control\"\n id=\"confEditorFilename\"\n placeholder=\"config.json\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"editorFilename\"\n />\n </c8y-form-group>\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"confEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"editorLanguage\"\n ></c8y-select>\n </c8y-form-group>\n </div>\n <c8y-form-group class=\"d-col flex-grow min-height-0 m-b-0\">\n <label\n for=\"confEditorContent\"\n translate\n >\n Content\n </label>\n <c8y-editor\n class=\"flex-grow\"\n style=\"min-height: 95px\"\n id=\"confEditorContent\"\n formControlName=\"editorContent\"\n monacoEditorMarkerValidator\n [editorOptions]=\"{ language: editorLanguage() }\"\n ></c8y-editor>\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n </ng-container>\n </c8y-file-picker>\n }\n </fieldset>\n </div>\n\n <div class=\"card-footer j-c-between separator flex-no-shrink p-24\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving()\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n [class.btn-pending]=\"saving()\"\n [title]=\"submitButtonTitle() | translate\"\n type=\"submit\"\n [disabled]=\"isSaveDisabled\"\n >\n {{ submitButtonTitle() | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "title", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: FilePickerComponent, selector: "c8y-file-picker", inputs: ["maxAllowedFiles", "uploadChoice", "allowedUploadChoices", "fileUrl", "fileBinary", "config", "filePickerIndex", "fileUrlPopover", "editInlineConfirmTitle", "editInlineConfirmMessage"], outputs: ["onFilesPicked", "uploadChoiceChange", "fileBinaryChange", "fileUrlChange", "textFilePicked"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "directive", type: MonacoEditorMarkerValidatorDirective, selector: "c8y-editor [monacoEditorMarkerValidator]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: SelectComponent, selector: "c8y-select", inputs: ["placeholder", "items", "selected", "container", "multi", "canSelectWithSpace", "disabled", "autoClose", "insideClick", "required", "canDeselect", "name", "icon", "filterItems"], outputs: ["onSelect", "onDeselect", "onIconClick"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
549
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: ConfigurationDetailComponent, isStandalone: true, selector: "c8y-configuration-detail", inputs: { version: "version", description: "description", binary: "binary", deviceType: "deviceType", mo: "mo", isDeviceContext: "isDeviceContext" }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div class=\"card-header j-c-center separator flex-no-shrink p-24\">\n <i\n class=\"m-r-8\"\n [c8yIcon]=\"'gears'\"\n aria-hidden=\"true\"\n ></i>\n <h4 id=\"drawerTitle\">\n {{ drawerTitle() | translate }}\n </h4>\n</div>\n\n<form\n class=\"d-contents\"\n [formGroup]=\"form\"\n (ngSubmit)=\"save()\"\n>\n <div\n class=\"card-body inner-scroll p-24\"\n [class.d-col]=\"form.value.uploadChoice === 'editInline'\"\n >\n @if (isDeviceContext) {\n <div\n class=\"alert alert-warning fit-w max-width-100\"\n translate\n >\n Changes apply to the configuration repository and affect ongoing updates and future device\n deployments.\n </div>\n }\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confVersion\"\n translate\n >\n Name\n </label>\n <input\n class=\"form-control\"\n id=\"confVersion\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDescription\"\n translate\n >\n Description\n </label>\n <textarea\n class=\"form-control no-resize\"\n id=\"confDescription\"\n placeholder=\"{{ 'e.g.' | translate }} Host configuration\"\n rows=\"1\"\n autocomplete=\"off\"\n formControlName=\"description\"\n c8y-textarea-autoresize\n ></textarea>\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDeviceType\"\n translate\n >\n Device type\n </label>\n <input\n class=\"form-control\"\n id=\"confDeviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label translate>Configuration type</label>\n <c8y-typeahead\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n name=\"confType\"\n data-cy=\"conf-detail--configuration-type\"\n [ngModel]=\"configurationTypeMO\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"configurationTypeMO = $event\"\n maxlength=\"254\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n @let patternStr = pattern();\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n (click)=\"configurationTypeMO = config; setPipe('')\"\n [active]=\"configurationTypeMO === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"patternStr\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n @if (patternStr.length > 0) {\n <c8y-li class=\"bg-level-2 p-8\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n title=\"{{ 'Add new`configuration type`' | translate }}\"\n type=\"button\"\n translate\n >\n Add new`configuration type`\n </button>\n </c8y-li>\n }\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n\n <fieldset\n class=\"d-col\"\n [class.flex-grow]=\"form.value.uploadChoice === 'editInline'\"\n [class.min-height-0]=\"form.value.uploadChoice === 'editInline'\"\n >\n <legend\n class=\"legend form-block m-t-40\"\n translate\n >\n Configuration file\n </legend>\n\n @if (isExternalUrl()) {\n <p\n class=\"text-muted m-b-8\"\n translate\n >\n Content is sourced from a remote URL and cannot be edited inline.\n </p>\n <c8y-form-group>\n <label\n for=\"confFileUrl\"\n translate\n >\n File URL\n </label>\n <input\n class=\"form-control\"\n id=\"confFileUrl\"\n placeholder=\"https://...\"\n type=\"url\"\n autocomplete=\"off\"\n [ngModel]=\"binary.url\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"binary = { url: $event }; form.markAsDirty()\"\n />\n </c8y-form-group>\n } @else {\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'editInline']\"\n [uploadChoice]=\"form.controls.uploadChoice.value\"\n (uploadChoiceChange)=\"onUploadChoiceChange($event)\"\n [fileUrl]=\"binary.url\"\n (fileUrlChange)=\"onFileUrlChange($event)\"\n [fileBinary]=\"binary.file\"\n (fileBinaryChange)=\"onFileBinaryChange($event)\"\n (textFilePicked)=\"onTextFilePicked($event)\"\n [fileUrlPopover]=\"textForConfigurationUrlPopover\"\n >\n <ng-container c8yInlineEditor>\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-9\">\n <label\n for=\"confEditorFilename\"\n translate\n >\n Filename\n </label>\n <input\n class=\"form-control\"\n id=\"confEditorFilename\"\n placeholder=\"config.json\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"editorFilename\"\n />\n </c8y-form-group>\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"confEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"editorLanguage\"\n ></c8y-select>\n </c8y-form-group>\n </div>\n <c8y-form-group class=\"d-col flex-grow min-height-0 m-b-0\">\n <label\n for=\"confEditorContent\"\n translate\n >\n Content\n </label>\n <c8y-editor\n class=\"flex-grow\"\n style=\"min-height: 95px\"\n id=\"confEditorContent\"\n formControlName=\"editorContent\"\n monacoEditorMarkerValidator\n [editorOptions]=\"{ language: editorLanguage() }\"\n ></c8y-editor>\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n </ng-container>\n </c8y-file-picker>\n }\n </fieldset>\n </div>\n\n <div class=\"card-footer j-c-between separator flex-no-shrink p-24\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving()\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n [class.btn-pending]=\"saving()\"\n [title]=\"drawerTitle() | translate\"\n type=\"submit\"\n [disabled]=\"isSaveDisabled\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "title", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: FilePickerComponent, selector: "c8y-file-picker", inputs: ["maxAllowedFiles", "uploadChoice", "allowedUploadChoices", "fileUrl", "fileBinary", "config", "filePickerIndex", "fileUrlPopover", "editInlineConfirmTitle", "editInlineConfirmMessage"], outputs: ["onFilesPicked", "uploadChoiceChange", "fileBinaryChange", "fileUrlChange", "textFilePicked"] }, { kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "directive", type: MonacoEditorMarkerValidatorDirective, selector: "c8y-editor [monacoEditorMarkerValidator]" }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: SelectComponent, selector: "c8y-select", inputs: ["placeholder", "items", "selected", "container", "multi", "canSelectWithSpace", "disabled", "autoClose", "insideClick", "required", "canDeselect", "name", "icon", "filterItems"], outputs: ["onSelect", "onDeselect", "onIconClick"] }, { kind: "directive", type: TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
536
550
  }
537
551
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ConfigurationDetailComponent, decorators: [{
538
552
  type: Component,
@@ -553,8 +567,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
553
567
  MonacoEditorMarkerValidatorDirective,
554
568
  MessagesComponent,
555
569
  RequiredInputPlaceholderDirective,
556
- SelectComponent
557
- ], template: "<div class=\"card-header j-c-center separator flex-no-shrink p-24\">\n <i\n class=\"m-r-8\"\n [c8yIcon]=\"'cogs'\"\n aria-hidden=\"true\"\n ></i>\n <h4 id=\"drawerTitle\">\n @if (mo?.id) {\n {{ 'Update configuration' | translate }}\n } @else {\n {{ 'Add configuration' | translate }}\n }\n </h4>\n</div>\n\n<form\n class=\"d-contents\"\n [formGroup]=\"form\"\n (ngSubmit)=\"save()\"\n>\n <div\n class=\"card-body inner-scroll p-24\"\n [class.d-col]=\"form.value.uploadChoice === 'editInline'\"\n >\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confVersion\"\n translate\n >\n Name\n </label>\n <input\n class=\"form-control\"\n id=\"confVersion\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDeviceType\"\n translate\n >\n Device type\n </label>\n <input\n class=\"form-control\"\n id=\"confDeviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDescription\"\n translate\n >\n Description\n </label>\n <input\n class=\"form-control\"\n id=\"confDescription\"\n placeholder=\"{{ 'e.g.' | translate }} Host configuration\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"description\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label translate>Configuration type</label>\n <c8y-typeahead\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n name=\"confType\"\n data-cy=\"conf-detail--configuration-type\"\n [ngModel]=\"configurationTypeMO\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"configurationTypeMO = $event\"\n maxlength=\"254\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n @let patternStr = pattern();\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n (click)=\"configurationTypeMO = config; setPipe('')\"\n [active]=\"configurationTypeMO === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"patternStr\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n @if (patternStr.length > 0) {\n <c8y-li class=\"bg-level-2 p-8\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n title=\"{{ 'Add new`configuration type`' | translate }}\"\n type=\"button\"\n translate\n >\n Add new`configuration type`\n </button>\n </c8y-li>\n }\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n\n <fieldset\n class=\"d-col\"\n [class.flex-grow]=\"form.value.uploadChoice === 'editInline'\"\n [class.min-height-0]=\"form.value.uploadChoice === 'editInline'\"\n >\n <legend\n class=\"legend form-block m-t-40\"\n translate\n >\n Configuration file\n </legend>\n\n @if (isExternalUrl()) {\n <p\n class=\"text-muted m-b-8\"\n translate\n >\n Content is sourced from a remote URL and cannot be edited inline.\n </p>\n <c8y-form-group>\n <label\n for=\"confFileUrl\"\n translate\n >\n File URL\n </label>\n <input\n class=\"form-control\"\n id=\"confFileUrl\"\n placeholder=\"https://...\"\n type=\"url\"\n autocomplete=\"off\"\n [ngModel]=\"binary.url\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"binary = { url: $event }; form.markAsDirty()\"\n />\n </c8y-form-group>\n } @else {\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'editInline']\"\n [uploadChoice]=\"form.controls.uploadChoice.value\"\n (uploadChoiceChange)=\"onUploadChoiceChange($event)\"\n [fileUrl]=\"binary.url\"\n (fileUrlChange)=\"onFileUrlChange($event)\"\n [fileBinary]=\"binary.file\"\n (fileBinaryChange)=\"onFileBinaryChange($event)\"\n (textFilePicked)=\"onTextFilePicked($event)\"\n [fileUrlPopover]=\"textForConfigurationUrlPopover\"\n >\n <ng-container c8yInlineEditor>\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-9\">\n <label\n for=\"confEditorFilename\"\n translate\n >\n Filename\n </label>\n <input\n class=\"form-control\"\n id=\"confEditorFilename\"\n placeholder=\"config.json\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"editorFilename\"\n />\n </c8y-form-group>\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"confEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"editorLanguage\"\n ></c8y-select>\n </c8y-form-group>\n </div>\n <c8y-form-group class=\"d-col flex-grow min-height-0 m-b-0\">\n <label\n for=\"confEditorContent\"\n translate\n >\n Content\n </label>\n <c8y-editor\n class=\"flex-grow\"\n style=\"min-height: 95px\"\n id=\"confEditorContent\"\n formControlName=\"editorContent\"\n monacoEditorMarkerValidator\n [editorOptions]=\"{ language: editorLanguage() }\"\n ></c8y-editor>\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n </ng-container>\n </c8y-file-picker>\n }\n </fieldset>\n </div>\n\n <div class=\"card-footer j-c-between separator flex-no-shrink p-24\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving()\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n [class.btn-pending]=\"saving()\"\n [title]=\"submitButtonTitle() | translate\"\n type=\"submit\"\n [disabled]=\"isSaveDisabled\"\n >\n {{ submitButtonTitle() | translate }}\n </button>\n </div>\n</form>\n" }]
570
+ SelectComponent,
571
+ TextareaAutoresizeDirective
572
+ ], template: "<div class=\"card-header j-c-center separator flex-no-shrink p-24\">\n <i\n class=\"m-r-8\"\n [c8yIcon]=\"'gears'\"\n aria-hidden=\"true\"\n ></i>\n <h4 id=\"drawerTitle\">\n {{ drawerTitle() | translate }}\n </h4>\n</div>\n\n<form\n class=\"d-contents\"\n [formGroup]=\"form\"\n (ngSubmit)=\"save()\"\n>\n <div\n class=\"card-body inner-scroll p-24\"\n [class.d-col]=\"form.value.uploadChoice === 'editInline'\"\n >\n @if (isDeviceContext) {\n <div\n class=\"alert alert-warning fit-w max-width-100\"\n translate\n >\n Changes apply to the configuration repository and affect ongoing updates and future device\n deployments.\n </div>\n }\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confVersion\"\n translate\n >\n Name\n </label>\n <input\n class=\"form-control\"\n id=\"confVersion\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDescription\"\n translate\n >\n Description\n </label>\n <textarea\n class=\"form-control no-resize\"\n id=\"confDescription\"\n placeholder=\"{{ 'e.g.' | translate }} Host configuration\"\n rows=\"1\"\n autocomplete=\"off\"\n formControlName=\"description\"\n c8y-textarea-autoresize\n ></textarea>\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confDeviceType\"\n translate\n >\n Device type\n </label>\n <input\n class=\"form-control\"\n id=\"confDeviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group class=\"col-sm-3\">\n <label translate>Configuration type</label>\n <c8y-typeahead\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n name=\"confType\"\n data-cy=\"conf-detail--configuration-type\"\n [ngModel]=\"configurationTypeMO\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"configurationTypeMO = $event\"\n maxlength=\"254\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n @let patternStr = pattern();\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n (click)=\"configurationTypeMO = config; setPipe('')\"\n [active]=\"configurationTypeMO === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"patternStr\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n @if (patternStr.length > 0) {\n <c8y-li class=\"bg-level-2 p-8\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n title=\"{{ 'Add new`configuration type`' | translate }}\"\n type=\"button\"\n translate\n >\n Add new`configuration type`\n </button>\n </c8y-li>\n }\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n </div>\n\n <fieldset\n class=\"d-col\"\n [class.flex-grow]=\"form.value.uploadChoice === 'editInline'\"\n [class.min-height-0]=\"form.value.uploadChoice === 'editInline'\"\n >\n <legend\n class=\"legend form-block m-t-40\"\n translate\n >\n Configuration file\n </legend>\n\n @if (isExternalUrl()) {\n <p\n class=\"text-muted m-b-8\"\n translate\n >\n Content is sourced from a remote URL and cannot be edited inline.\n </p>\n <c8y-form-group>\n <label\n for=\"confFileUrl\"\n translate\n >\n File URL\n </label>\n <input\n class=\"form-control\"\n id=\"confFileUrl\"\n placeholder=\"https://...\"\n type=\"url\"\n autocomplete=\"off\"\n [ngModel]=\"binary.url\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"binary = { url: $event }; form.markAsDirty()\"\n />\n </c8y-form-group>\n } @else {\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'editInline']\"\n [uploadChoice]=\"form.controls.uploadChoice.value\"\n (uploadChoiceChange)=\"onUploadChoiceChange($event)\"\n [fileUrl]=\"binary.url\"\n (fileUrlChange)=\"onFileUrlChange($event)\"\n [fileBinary]=\"binary.file\"\n (fileBinaryChange)=\"onFileBinaryChange($event)\"\n (textFilePicked)=\"onTextFilePicked($event)\"\n [fileUrlPopover]=\"textForConfigurationUrlPopover\"\n >\n <ng-container c8yInlineEditor>\n <div class=\"row\">\n <c8y-form-group class=\"col-sm-9\">\n <label\n for=\"confEditorFilename\"\n translate\n >\n Filename\n </label>\n <input\n class=\"form-control\"\n id=\"confEditorFilename\"\n placeholder=\"config.json\"\n aria-required=\"true\"\n type=\"text\"\n autocomplete=\"off\"\n formControlName=\"editorFilename\"\n />\n </c8y-form-group>\n <c8y-form-group class=\"col-sm-3\">\n <label\n for=\"confEditorLanguage\"\n translate\n >\n Language\n </label>\n <c8y-select\n aria-label=\"{{ 'Editor language' | translate }}\"\n id=\"confEditorLanguage\"\n [items]=\"editorLanguages\"\n formControlName=\"editorLanguage\"\n ></c8y-select>\n </c8y-form-group>\n </div>\n <c8y-form-group class=\"d-col flex-grow min-height-0 m-b-0\">\n <label\n for=\"confEditorContent\"\n translate\n >\n Content\n </label>\n <c8y-editor\n class=\"flex-grow\"\n style=\"min-height: 95px\"\n id=\"confEditorContent\"\n formControlName=\"editorContent\"\n monacoEditorMarkerValidator\n [editorOptions]=\"{ language: editorLanguage() }\"\n ></c8y-editor>\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n </ng-container>\n </c8y-file-picker>\n }\n </fieldset>\n </div>\n\n <div class=\"card-footer j-c-between separator flex-no-shrink p-24\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving()\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n [class.btn-pending]=\"saving()\"\n [title]=\"drawerTitle() | translate\"\n type=\"submit\"\n [disabled]=\"isSaveDisabled\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n</form>\n" }]
558
573
  }], ctorParameters: () => [], propDecorators: { version: [{
559
574
  type: Input
560
575
  }], description: [{
@@ -565,6 +580,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
565
580
  type: Input
566
581
  }], mo: [{
567
582
  type: Input
583
+ }], isDeviceContext: [{
584
+ type: Input
568
585
  }] } });
569
586
 
570
587
  class SourceCodePreviewComponent {
@@ -591,11 +608,11 @@ class SourceCodePreviewComponent {
591
608
  };
592
609
  }
593
610
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SourceCodePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
594
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: SourceCodePreviewComponent, isStandalone: true, selector: "c8y-source-code-preview", inputs: { isDisabled: "isDisabled", text: "text", binaryType: "binaryType" }, usesOnChanges: true, ngImport: i0, template: "<c8y-editor\n class=\"flex-grow\"\n [ngModel]=\"text\"\n [editorOptions]=\"editorOptions\"\n (editorInit)=\"onEditorInit()\"\n></c8y-editor>\n", dependencies: [{ kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
611
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: SourceCodePreviewComponent, isStandalone: true, selector: "c8y-source-code-preview", inputs: { isDisabled: "isDisabled", text: "text", binaryType: "binaryType" }, usesOnChanges: true, ngImport: i0, template: "<c8y-editor\n class=\"flex-grow min-height-0\"\n [ngModel]=\"text\"\n [editorOptions]=\"editorOptions\"\n (editorInit)=\"onEditorInit()\"\n></c8y-editor>\n", dependencies: [{ kind: "component", type: EditorComponent, selector: "c8y-editor", inputs: ["editorOptions", "theme"], outputs: ["editorInit"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
595
612
  }
596
613
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SourceCodePreviewComponent, decorators: [{
597
614
  type: Component,
598
- args: [{ selector: 'c8y-source-code-preview', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [EditorComponent, FormsModule], template: "<c8y-editor\n class=\"flex-grow\"\n [ngModel]=\"text\"\n [editorOptions]=\"editorOptions\"\n (editorInit)=\"onEditorInit()\"\n></c8y-editor>\n" }]
615
+ args: [{ selector: 'c8y-source-code-preview', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [EditorComponent, FormsModule], template: "<c8y-editor\n class=\"flex-grow min-height-0\"\n [ngModel]=\"text\"\n [editorOptions]=\"editorOptions\"\n (editorInit)=\"onEditorInit()\"\n></c8y-editor>\n" }]
599
616
  }], propDecorators: { isDisabled: [{
600
617
  type: Input
601
618
  }], text: [{
@@ -624,6 +641,12 @@ class ConfigurationPreviewComponent {
624
641
  this.editInRepository = new EventEmitter();
625
642
  this.canCallAction = true;
626
643
  this.deviceConfigurationOperation = DeviceConfigurationOperation;
644
+ /**
645
+ * Whether the previewed content is binary. Binary bytes are not rendered in the editor:
646
+ * they are unreadable as text and make the editor warn about invisible unicode characters,
647
+ * a warning the user cannot act on.
648
+ */
649
+ this.isBinaryContent = signal(false, ...(ngDevMode ? [{ debugName: "isBinaryContent" }] : /* istanbul ignore next */ []));
627
650
  }
628
651
  async ngOnInit() {
629
652
  this.setCanCallAction();
@@ -719,7 +742,8 @@ class ConfigurationPreviewComponent {
719
742
  binary: { file },
720
743
  // No id — the drawer treats this as a new entry, but carries the
721
744
  // configuration type so the user can review and edit before saving.
722
- mo: { configurationType: snapshot.configurationType }
745
+ mo: { configurationType: snapshot.configurationType },
746
+ isDeviceContext: true
723
747
  });
724
748
  if (saved) {
725
749
  this.deviceConfigurationService.updateConfigurations(true);
@@ -739,11 +763,34 @@ class ConfigurationPreviewComponent {
739
763
  Permissions.ROLE_BINARY_CREATE
740
764
  ])));
741
765
  }
766
+ ngOnChanges(changes) {
767
+ if (changes.configSnapshot) {
768
+ void this.detectBinaryContent();
769
+ }
770
+ }
742
771
  ngOnDestroy() {
743
772
  if (this.operationsSubscription) {
744
773
  this.operationsSubscription.unsubscribe();
745
774
  }
746
775
  }
776
+ async detectBinaryContent() {
777
+ const snapshot = this.configSnapshot;
778
+ this.inspectedSnapshot = snapshot;
779
+ if (!snapshot?.binary) {
780
+ this.isBinaryContent.set(false);
781
+ return;
782
+ }
783
+ // Prefer the original bytes when they were preserved; otherwise re-encode the text the
784
+ // platform already decoded, which keeps null and replacement characters intact.
785
+ const file = snapshot.binaryFile ??
786
+ new File([snapshot.binary], snapshot.name ?? '', { type: snapshot.binaryType });
787
+ // Decide from the content, not the declared MIME type: platform-served binaries are
788
+ // often labelled text/plain.
789
+ const isBinary = await isBinaryFile(file, { ignoreMimeType: true });
790
+ if (this.inspectedSnapshot === snapshot) {
791
+ this.isBinaryContent.set(isBinary);
792
+ }
793
+ }
747
794
  async updateSnapshotsOnConfigUpload(operation) {
748
795
  if (operation[DeviceConfigurationOperation.UPLOAD_CONFIG] &&
749
796
  operation.status === OperationStatus.SUCCESSFUL) {
@@ -751,7 +798,7 @@ class ConfigurationPreviewComponent {
751
798
  }
752
799
  }
753
800
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ConfigurationPreviewComponent, deps: [{ token: DeviceConfigurationService }, { token: i2.OperationRealtimeService }, { token: i3$1.UserService }, { token: i2.AppStateService }, { token: i3.RepositoryService }, { token: i3$1.OperationService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
754
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: ConfigurationPreviewComponent, isStandalone: true, selector: "c8y-device-configuration-preview", inputs: { device: "device", configurationType: "configurationType", configSnapshot: "configSnapshot", canSaveSnapshot: "canSaveSnapshot", actionButtonText: "actionButtonText", actionButtonIcon: "actionButtonIcon", isLegacy: "isLegacy", operationToTrigger: "operationToTrigger", editableRepositoryMo: "editableRepositoryMo" }, outputs: { editInRepository: "editInRepository" }, ngImport: i0, template: "<div class=\"content-flex-55 p-b-16\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Configuration</span\n >\n @if (configSnapshot?.name) {\n <span>\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n } @else {\n ---\n }\n </p>\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Last updated</span\n >\n @if (configSnapshot?.time) {\n <small>\n {{ configSnapshot.time | c8yDate }}\n </small>\n } @else {\n ---\n }\n </p>\n </div>\n <div class=\"col-5 d-flex j-c-end gap-4\">\n @if (editableRepositoryMo) {\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Edit in repository' | translate }}\"\n type=\"button\"\n (click)=\"editInRepository.emit(editableRepositoryMo)\"\n >\n <i\n [c8yIcon]=\"'pencil'\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Edit in repository' | translate }}\n </button>\n }\n @if (canCallAction) {\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ actionButtonText | translate }}\"\n id=\"action-btn\"\n type=\"button\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n }\n </div>\n</div>\n@if (!configSnapshot?.binary && showBinary()) {\n <div class=\"c8y-empty-state text-left\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n @if (configSnapshot?.binary !== '') {\n <small translate> The file is not available. </small>\n } @else {\n <small translate>The file is empty.</small>\n }\n </p>\n </div>\n}\n@if (configSnapshot?.binary && showBinary()) {\n <div class=\"flex-grow d-flex d-col\">\n <c8y-source-code-preview\n class=\"d-contents\"\n [text]=\"configSnapshot.binary\"\n [binaryType]=\"configSnapshot.binaryType\"\n [isDisabled]=\"true\"\n ></c8y-source-code-preview>\n @if (canSaveSnapshot) {\n <div class=\"p-t-16\">\n <button\n class=\"btn btn-primary btn-sm pull-right m-l-8\"\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n (click)=\"download()\"\n >\n {{ 'Download' | translate }}\n </button>\n @if (hasPermission()) {\n <button\n class=\"btn btn-default btn-sm pull-right\"\n title=\"{{ 'Save to repository' | translate }}\"\n type=\"button\"\n (click)=\"saveToRepository()\"\n >\n {{ 'Save to repository' | translate }}\n </button>\n }\n </div>\n }\n </div>\n}\n@if (showOperation()) {\n <div>\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n </div>\n}\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: SourceCodePreviewComponent, selector: "c8y-source-code-preview", inputs: ["isDisabled", "text", "binaryType"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
801
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: ConfigurationPreviewComponent, isStandalone: true, selector: "c8y-device-configuration-preview", inputs: { device: "device", configurationType: "configurationType", configSnapshot: "configSnapshot", canSaveSnapshot: "canSaveSnapshot", actionButtonText: "actionButtonText", actionButtonIcon: "actionButtonIcon", isLegacy: "isLegacy", operationToTrigger: "operationToTrigger", editableRepositoryMo: "editableRepositoryMo" }, outputs: { editInRepository: "editInRepository" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"content-flex-55 p-b-16 flex-no-shrink\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Configuration</span\n >\n @if (configSnapshot?.name) {\n <span>\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n } @else {\n ---\n }\n </p>\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Last updated</span\n >\n @if (configSnapshot?.time) {\n <small>\n {{ configSnapshot.time | c8yDate }}\n </small>\n } @else {\n ---\n }\n </p>\n </div>\n <div class=\"col-5 d-flex j-c-end gap-4\">\n @if (canCallAction) {\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ actionButtonText | translate }}\"\n id=\"action-btn\"\n type=\"button\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n }\n </div>\n</div>\n<fieldset class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\">\n <legend translate>Preview</legend>\n @if (showOperation()) {\n <div>\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n </div>\n }\n @if (!configSnapshot?.binary && showBinary()) {\n <div class=\"c8y-empty-state text-left\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n @if (configSnapshot?.binary !== '') {\n <small translate>\n Try getting a snapshot from the device or open it in the repository\n </small>\n } @else {\n <small translate>The file is empty.</small>\n }\n </p>\n </div>\n }\n @if (configSnapshot?.binary && showBinary()) {\n <div class=\"flex-grow d-flex d-col min-height-0\">\n @if (isBinaryContent()) {\n <c8y-ui-empty-state\n class=\"flex-grow\"\n [icon]=\"'file-o'\"\n [title]=\"'No preview available.' | translate\"\n [subtitle]=\"\n 'This configuration is a binary file and cannot be shown as text.' | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n } @else {\n <c8y-source-code-preview\n class=\"d-contents\"\n [text]=\"configSnapshot.binary\"\n [binaryType]=\"configSnapshot.binaryType\"\n [isDisabled]=\"true\"\n ></c8y-source-code-preview>\n }\n @if (canSaveSnapshot) {\n <div class=\"p-t-16 flex-no-shrink\">\n <button\n class=\"btn btn-default btn-sm pull-right m-l-8\"\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n (click)=\"download()\"\n >\n <i\n c8yIcon=\"download\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Download' | translate }}\n </button>\n @if (hasPermission()) {\n <button\n class=\"btn btn-default btn-sm pull-right\"\n title=\"{{ 'Save to repository' | translate }}\"\n type=\"button\"\n (click)=\"saveToRepository()\"\n >\n <i\n c8yIcon=\"archive-file\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Save to repository' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (editableRepositoryMo) {\n <div class=\"d-flex j-c-end p-t-8 flex-no-shrink\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Edit in repository' | translate }}\"\n type=\"button\"\n (click)=\"editInRepository.emit(editableRepositoryMo)\"\n >\n <i\n [c8yIcon]=\"'pencil'\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Edit in repository' | translate }}\n </button>\n </div>\n }\n</fieldset>\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: SourceCodePreviewComponent, selector: "c8y-source-code-preview", inputs: ["isDisabled", "text", "binaryType"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
755
802
  }
756
803
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ConfigurationPreviewComponent, decorators: [{
757
804
  type: Component,
@@ -761,8 +808,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
761
808
  SourceCodePreviewComponent,
762
809
  OperationDetailsComponent,
763
810
  C8yTranslatePipe,
764
- DatePipe
765
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div class=\"content-flex-55 p-b-16\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Configuration</span\n >\n @if (configSnapshot?.name) {\n <span>\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n } @else {\n ---\n }\n </p>\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Last updated</span\n >\n @if (configSnapshot?.time) {\n <small>\n {{ configSnapshot.time | c8yDate }}\n </small>\n } @else {\n ---\n }\n </p>\n </div>\n <div class=\"col-5 d-flex j-c-end gap-4\">\n @if (editableRepositoryMo) {\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Edit in repository' | translate }}\"\n type=\"button\"\n (click)=\"editInRepository.emit(editableRepositoryMo)\"\n >\n <i\n [c8yIcon]=\"'pencil'\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Edit in repository' | translate }}\n </button>\n }\n @if (canCallAction) {\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ actionButtonText | translate }}\"\n id=\"action-btn\"\n type=\"button\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n }\n </div>\n</div>\n@if (!configSnapshot?.binary && showBinary()) {\n <div class=\"c8y-empty-state text-left\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n @if (configSnapshot?.binary !== '') {\n <small translate> The file is not available. </small>\n } @else {\n <small translate>The file is empty.</small>\n }\n </p>\n </div>\n}\n@if (configSnapshot?.binary && showBinary()) {\n <div class=\"flex-grow d-flex d-col\">\n <c8y-source-code-preview\n class=\"d-contents\"\n [text]=\"configSnapshot.binary\"\n [binaryType]=\"configSnapshot.binaryType\"\n [isDisabled]=\"true\"\n ></c8y-source-code-preview>\n @if (canSaveSnapshot) {\n <div class=\"p-t-16\">\n <button\n class=\"btn btn-primary btn-sm pull-right m-l-8\"\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n (click)=\"download()\"\n >\n {{ 'Download' | translate }}\n </button>\n @if (hasPermission()) {\n <button\n class=\"btn btn-default btn-sm pull-right\"\n title=\"{{ 'Save to repository' | translate }}\"\n type=\"button\"\n (click)=\"saveToRepository()\"\n >\n {{ 'Save to repository' | translate }}\n </button>\n }\n </div>\n }\n </div>\n}\n@if (showOperation()) {\n <div>\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n </div>\n}\n" }]
811
+ DatePipe,
812
+ EmptyStateComponent
813
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div class=\"content-flex-55 p-b-16 flex-no-shrink\">\n <div class=\"col-7 p-t-4\">\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Configuration</span\n >\n @if (configSnapshot?.name) {\n <span>\n <strong>{{ configSnapshot.name }}</strong>\n </span>\n } @else {\n ---\n }\n </p>\n <p>\n <span\n class=\"text-label-small text-uppercase m-r-4\"\n translate\n >Last updated</span\n >\n @if (configSnapshot?.time) {\n <small>\n {{ configSnapshot.time | c8yDate }}\n </small>\n } @else {\n ---\n }\n </p>\n </div>\n <div class=\"col-5 d-flex j-c-end gap-4\">\n @if (canCallAction) {\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ actionButtonText | translate }}\"\n id=\"action-btn\"\n type=\"button\"\n (click)=\"createDeviceOperation()\"\n [disabled]=\"isCreateOperationDisabled()\"\n >\n <i [c8yIcon]=\"actionButtonIcon\"></i>\n {{ actionButtonText | translate }}\n </button>\n }\n </div>\n</div>\n<fieldset class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\">\n <legend translate>Preview</legend>\n @if (showOperation()) {\n <div>\n <c8y-operation-details [operation]=\"operation\"></c8y-operation-details>\n </div>\n }\n @if (!configSnapshot?.binary && showBinary()) {\n <div class=\"c8y-empty-state text-left\">\n <h1 [c8yIcon]=\"'file-image-o'\"></h1>\n <p>\n <strong translate>No preview available.</strong>\n <br />\n @if (configSnapshot?.binary !== '') {\n <small translate>\n Try getting a snapshot from the device or open it in the repository\n </small>\n } @else {\n <small translate>The file is empty.</small>\n }\n </p>\n </div>\n }\n @if (configSnapshot?.binary && showBinary()) {\n <div class=\"flex-grow d-flex d-col min-height-0\">\n @if (isBinaryContent()) {\n <c8y-ui-empty-state\n class=\"flex-grow\"\n [icon]=\"'file-o'\"\n [title]=\"'No preview available.' | translate\"\n [subtitle]=\"\n 'This configuration is a binary file and cannot be shown as text.' | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n } @else {\n <c8y-source-code-preview\n class=\"d-contents\"\n [text]=\"configSnapshot.binary\"\n [binaryType]=\"configSnapshot.binaryType\"\n [isDisabled]=\"true\"\n ></c8y-source-code-preview>\n }\n @if (canSaveSnapshot) {\n <div class=\"p-t-16 flex-no-shrink\">\n <button\n class=\"btn btn-default btn-sm pull-right m-l-8\"\n title=\"{{ 'Download' | translate }}\"\n type=\"button\"\n (click)=\"download()\"\n >\n <i\n c8yIcon=\"download\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Download' | translate }}\n </button>\n @if (hasPermission()) {\n <button\n class=\"btn btn-default btn-sm pull-right\"\n title=\"{{ 'Save to repository' | translate }}\"\n type=\"button\"\n (click)=\"saveToRepository()\"\n >\n <i\n c8yIcon=\"archive-file\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Save to repository' | translate }}\n </button>\n }\n </div>\n }\n </div>\n }\n @if (editableRepositoryMo) {\n <div class=\"d-flex j-c-end p-t-8 flex-no-shrink\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Edit in repository' | translate }}\"\n type=\"button\"\n (click)=\"editInRepository.emit(editableRepositoryMo)\"\n >\n <i\n [c8yIcon]=\"'pencil'\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Edit in repository' | translate }}\n </button>\n </div>\n }\n</fieldset>\n" }]
766
814
  }], ctorParameters: () => [{ type: DeviceConfigurationService }, { type: i2.OperationRealtimeService }, { type: i3$1.UserService }, { type: i2.AppStateService }, { type: i3.RepositoryService }, { type: i3$1.OperationService }, { type: i2.AlertService }], propDecorators: { device: [{
767
815
  type: Input
768
816
  }], configurationType: [{
@@ -887,8 +935,13 @@ class DeviceConfigurationComponent {
887
935
  allowExternal: false
888
936
  });
889
937
  if (binary) {
890
- this.repositorySnapshot.binary = await binary.text();
891
- this.repositorySnapshot.binaryType = binary.type || undefined;
938
+ // Replace the snapshot rather than mutating it: the preview binds to this object
939
+ // and only re-inspects the content when the reference changes.
940
+ this.repositorySnapshot = {
941
+ ...this.repositorySnapshot,
942
+ binary: await binary.text(),
943
+ binaryType: binary.type || undefined
944
+ };
892
945
  }
893
946
  }
894
947
  catch {
@@ -924,14 +977,15 @@ class DeviceConfigurationComponent {
924
977
  deviceType: mo.deviceType,
925
978
  description: mo.description,
926
979
  binary: { file: fileBinary, url: mo.url },
927
- mo
980
+ mo,
981
+ isDeviceContext: true
928
982
  });
929
983
  if (saved) {
930
984
  this.updateSnapshots(true);
931
985
  }
932
986
  }
933
987
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DeviceConfigurationComponent, deps: [{ token: i1.ActivatedRoute }, { token: DeviceConfigurationService }, { token: i3.RepositoryService }], target: i0.ɵɵFactoryTarget.Component }); }
934
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: DeviceConfigurationComponent, isStandalone: true, selector: "c8y-device-configuration", viewQueries: [{ propertyName: "textBasedConfigurationComponent", first: true, predicate: TextBasedConfigurationComponent, descendants: true }], ngImport: i0, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"updateSnapshots()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage card-has-tabs\">\n <tabset>\n @if (showBinaryBasedConfig && !showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Configurations' | translate }}</div>\n </div>\n }\n @if (!showBinaryBasedConfig && showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Text-based configuration' | translate }}</div>\n </div>\n }\n @if (showBinaryBasedConfig) {\n <tab heading=\"{{ 'Configurations' | translate }}\">\n <div class=\"card--grid card grid__col--4-8--md grid__row--6-6--md m-b-0\">\n <!-- DEVICE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span translate>Device-supported configurations</span>\n </h5>\n </div>\n <c8y-device-configuration-list\n [itemIcon]=\"'gears'\"\n [items]=\"supportedConfigurations\"\n (configSelected)=\"onConfigTypeSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div class=\"card--grid__inner-scroll d-flex d-col flex-grow\">\n <div class=\"card-block d-flex d-col flex-grow\">\n <h5 class=\"legend form-block\"><span translate>Preview</span></h5>\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <!-- PREVIEW AVAILABLE STATE -->\n @if (configurationType) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow\"\n [actionButtonIcon]=\"'download'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"configSnapshot\"\n [canSaveSnapshot]=\"true\"\n [operationToTrigger]=\"'c8y_UploadConfigFile'\"\n [actionButtonText]=\"'Get snapshot from device' | translate\"\n [isLegacy]=\"isLegacy\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n <!-- AVAILABLE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <div class=\"p-l-16 p-r-16\">\n <h5\n class=\"legend form-block\"\n translate\n >\n Available supported configurations\n </h5>\n </div>\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'gears'\"\n [title]=\"'No selection.' | translate\"\n [subtitle]=\"\n 'Select a configuration from the device-supported configuration list.' | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n @if (configurationType) {\n <div class=\"p-r-16\">\n <c8y-device-configuration-list\n [itemIcon]=\"'file-text'\"\n [items]=\"repositorySnapshots\"\n [emptyState]=\"repositorySnapshotsEmptyState\"\n [isFilterEnabled]=\"true\"\n (configSelected)=\"onRepositoryConfigSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n }\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div class=\"card--grid__inner-scroll d-flex d-col flex-grow\">\n <div class=\"card-block flex-grow d-flex d-col\">\n <h5\n class=\"legend form-block\"\n translate\n >\n Preview\n </h5>\n <!-- EMPTY STATE -->\n @if (!repositorySnapshot) {\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <!-- CONFIGURATION SELECTED STATE -->\n @if (repositorySnapshot) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow\"\n [actionButtonIcon]=\"'upload'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"repositorySnapshot\"\n [operationToTrigger]=\"'c8y_DownloadConfigFile'\"\n [actionButtonText]=\"'Send configuration to device' | translate\"\n [isLegacy]=\"isLegacy\"\n [editableRepositoryMo]=\"selectedRepositoryMo\"\n (editInRepository)=\"openEditInRepository($event)\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </tab>\n }\n @if (showTextBasedConfig) {\n <tab heading=\"{{ 'Text-based configuration' | translate }}\">\n <c8y-text-based-configuration></c8y-text-based-configuration>\n </tab>\n }\n </tabset>\n</div>\n", dependencies: [{ kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TabsetAriaDirective, selector: "tabset" }, { kind: "component", type: TabsetComponent, selector: "tabset", inputs: ["vertical", "justified", "type"] }, { kind: "directive", type: TabDirective, selector: "tab, [tab]", inputs: ["heading", "id", "disabled", "removable", "tabOrder", "customClass", "active"], outputs: ["selectTab", "deselect", "removed"], exportAs: ["tab"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: DeviceConfigurationListComponent, selector: "c8y-device-configuration-list", inputs: ["items", "itemIcon", "emptyState", "isFilterEnabled"], outputs: ["configSelected"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: ConfigurationPreviewComponent, selector: "c8y-device-configuration-preview", inputs: ["device", "configurationType", "configSnapshot", "canSaveSnapshot", "actionButtonText", "actionButtonIcon", "isLegacy", "operationToTrigger", "editableRepositoryMo"], outputs: ["editInRepository"] }, { kind: "component", type: TextBasedConfigurationComponent, selector: "c8y-text-based-configuration" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: DeviceConfigurationComponent, isStandalone: true, selector: "c8y-device-configuration", viewQueries: [{ propertyName: "textBasedConfigurationComponent", first: true, predicate: TextBasedConfigurationComponent, descendants: true }], ngImport: i0, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"updateSnapshots()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage card-has-tabs\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Configurations\n </div>\n </div>\n <tabset>\n @if (showBinaryBasedConfig && !showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'From repository' | translate }}</div>\n </div>\n }\n @if (!showBinaryBasedConfig && showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Custom' | translate }}</div>\n </div>\n }\n @if (showBinaryBasedConfig) {\n <tab>\n <ng-template tabHeading>\n <i\n c8yIcon=\"gears\"\n aria-hidden=\"true\"\n ></i>\n {{ 'From repository' | translate }}\n </ng-template>\n <c8y-resizable-grid\n [orientation]=\"'vertical'\"\n [trackId]=\"'c8y-device-configuration-split-view'\"\n [leftColumnWidth]=\"'50%'\"\n [collapsible]=\"false\"\n >\n <!-- ON DEVICE -->\n <div\n class=\"d-flex d-col fit-h min-height-0\"\n left-pane\n >\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span translate>On device</span>\n </h5>\n </div>\n <div class=\"card--grid grid__col--4-8--md m-b-0 flex-grow min-height-0\">\n <!-- DEVICE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <c8y-device-configuration-list\n [itemIcon]=\"'gears'\"\n [items]=\"supportedConfigurations\"\n (configSelected)=\"onConfigTypeSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div\n class=\"card--grid__inner-scroll d-flex d-col flex-grow min-height-0 bg-component\"\n >\n <div class=\"card-block d-flex d-col flex-grow min-height-0\">\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <fieldset\n class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\"\n >\n <legend translate>Preview</legend>\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </fieldset>\n }\n <!-- PREVIEW AVAILABLE STATE -->\n @if (configurationType) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow min-height-0\"\n [actionButtonIcon]=\"'arrow-down'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"configSnapshot\"\n [canSaveSnapshot]=\"true\"\n [operationToTrigger]=\"'c8y_UploadConfigFile'\"\n [actionButtonText]=\"'Get snapshot from device' | translate\"\n [isLegacy]=\"isLegacy\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- AVAILABLE FROM REPOSITORY: depends on the on-device selection above -->\n <div\n class=\"d-flex d-col fit-h min-height-0\"\n right-pane\n >\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span\n class=\"m-r-8\"\n translate\n >\n Available from repository\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Supported predefined configurations you can send to this device' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n >\n <i c8yIcon=\"question-circle-o\"></i>\n </button>\n </h5>\n </div>\n <div class=\"card--grid grid__col--4-8--md m-b-0 flex-grow min-height-0\">\n <!-- AVAILABLE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'gears'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"\n 'Select a configuration type from the list above to view matching repository items.'\n | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n @if (configurationType) {\n <div class=\"p-r-16\">\n <c8y-device-configuration-list\n [itemIcon]=\"'file-text'\"\n [items]=\"repositorySnapshots\"\n [emptyState]=\"repositorySnapshotsEmptyState\"\n [isFilterEnabled]=\"true\"\n (configSelected)=\"onRepositoryConfigSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n }\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div\n class=\"card--grid__inner-scroll d-flex d-col flex-grow min-height-0 bg-component\"\n >\n <div class=\"card-block d-flex d-col flex-grow min-height-0\">\n <!-- EMPTY STATE -->\n @if (!repositorySnapshot) {\n <fieldset\n class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\"\n >\n <legend translate>Preview</legend>\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </fieldset>\n }\n <!-- CONFIGURATION SELECTED STATE -->\n @if (repositorySnapshot) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow min-height-0\"\n [actionButtonIcon]=\"'arrow-up'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"repositorySnapshot\"\n [operationToTrigger]=\"'c8y_DownloadConfigFile'\"\n [actionButtonText]=\"'Send configuration to device' | translate\"\n [isLegacy]=\"isLegacy\"\n [editableRepositoryMo]=\"selectedRepositoryMo\"\n (editInRepository)=\"openEditInRepository($event)\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </div>\n </c8y-resizable-grid>\n </tab>\n }\n @if (showTextBasedConfig) {\n <tab>\n <ng-template tabHeading>\n <i\n c8yIcon=\"code\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Custom' | translate }}\n </ng-template>\n <c8y-text-based-configuration></c8y-text-based-configuration>\n </tab>\n }\n </tabset>\n</div>\n", dependencies: [{ kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TabsetAriaDirective, selector: "tabset" }, { kind: "component", type: TabsetComponent, selector: "tabset", inputs: ["vertical", "justified", "type"] }, { kind: "directive", type: TabDirective, selector: "tab, [tab]", inputs: ["heading", "id", "disabled", "removable", "tabOrder", "customClass", "active"], outputs: ["selectTab", "deselect", "removed"], exportAs: ["tab"] }, { kind: "directive", type: TabHeadingDirective, selector: "[tabHeading]" }, { kind: "directive", type: PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: DeviceConfigurationListComponent, selector: "c8y-device-configuration-list", inputs: ["items", "itemIcon", "emptyState", "isFilterEnabled"], outputs: ["configSelected"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: ConfigurationPreviewComponent, selector: "c8y-device-configuration-preview", inputs: ["device", "configurationType", "configSnapshot", "canSaveSnapshot", "actionButtonText", "actionButtonIcon", "isLegacy", "operationToTrigger", "editableRepositoryMo"], outputs: ["editInRepository"] }, { kind: "component", type: TextBasedConfigurationComponent, selector: "c8y-text-based-configuration" }, { kind: "component", type: ResizableGridComponent, selector: "c8y-resizable-grid", inputs: ["leftColumnWidth", "trackId", "collapseThreshold", "collapsible", "orientation"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
935
989
  }
936
990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DeviceConfigurationComponent, decorators: [{
937
991
  type: Component,
@@ -942,13 +996,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
942
996
  TabsetAriaDirective,
943
997
  TabsetComponent,
944
998
  TabDirective,
999
+ TabHeadingDirective,
1000
+ PopoverDirective,
945
1001
  C8yTranslateDirective,
946
1002
  DeviceConfigurationListComponent,
947
1003
  EmptyStateComponent,
948
1004
  ConfigurationPreviewComponent,
949
1005
  TextBasedConfigurationComponent,
950
- C8yTranslatePipe
951
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"updateSnapshots()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage card-has-tabs\">\n <tabset>\n @if (showBinaryBasedConfig && !showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Configurations' | translate }}</div>\n </div>\n }\n @if (!showBinaryBasedConfig && showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Text-based configuration' | translate }}</div>\n </div>\n }\n @if (showBinaryBasedConfig) {\n <tab heading=\"{{ 'Configurations' | translate }}\">\n <div class=\"card--grid card grid__col--4-8--md grid__row--6-6--md m-b-0\">\n <!-- DEVICE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span translate>Device-supported configurations</span>\n </h5>\n </div>\n <c8y-device-configuration-list\n [itemIcon]=\"'gears'\"\n [items]=\"supportedConfigurations\"\n (configSelected)=\"onConfigTypeSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div class=\"card--grid__inner-scroll d-flex d-col flex-grow\">\n <div class=\"card-block d-flex d-col flex-grow\">\n <h5 class=\"legend form-block\"><span translate>Preview</span></h5>\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <!-- PREVIEW AVAILABLE STATE -->\n @if (configurationType) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow\"\n [actionButtonIcon]=\"'download'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"configSnapshot\"\n [canSaveSnapshot]=\"true\"\n [operationToTrigger]=\"'c8y_UploadConfigFile'\"\n [actionButtonText]=\"'Get snapshot from device' | translate\"\n [isLegacy]=\"isLegacy\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n <!-- AVAILABLE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <div class=\"p-l-16 p-r-16\">\n <h5\n class=\"legend form-block\"\n translate\n >\n Available supported configurations\n </h5>\n </div>\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'gears'\"\n [title]=\"'No selection.' | translate\"\n [subtitle]=\"\n 'Select a configuration from the device-supported configuration list.' | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n @if (configurationType) {\n <div class=\"p-r-16\">\n <c8y-device-configuration-list\n [itemIcon]=\"'file-text'\"\n [items]=\"repositorySnapshots\"\n [emptyState]=\"repositorySnapshotsEmptyState\"\n [isFilterEnabled]=\"true\"\n (configSelected)=\"onRepositoryConfigSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n }\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div class=\"card--grid__inner-scroll d-flex d-col flex-grow\">\n <div class=\"card-block flex-grow d-flex d-col\">\n <h5\n class=\"legend form-block\"\n translate\n >\n Preview\n </h5>\n <!-- EMPTY STATE -->\n @if (!repositorySnapshot) {\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n <!-- CONFIGURATION SELECTED STATE -->\n @if (repositorySnapshot) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow\"\n [actionButtonIcon]=\"'upload'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"repositorySnapshot\"\n [operationToTrigger]=\"'c8y_DownloadConfigFile'\"\n [actionButtonText]=\"'Send configuration to device' | translate\"\n [isLegacy]=\"isLegacy\"\n [editableRepositoryMo]=\"selectedRepositoryMo\"\n (editInRepository)=\"openEditInRepository($event)\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </tab>\n }\n @if (showTextBasedConfig) {\n <tab heading=\"{{ 'Text-based configuration' | translate }}\">\n <c8y-text-based-configuration></c8y-text-based-configuration>\n </tab>\n }\n </tabset>\n</div>\n" }]
1006
+ C8yTranslatePipe,
1007
+ ResizableGridComponent
1008
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"updateSnapshots()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card content-fullpage card-has-tabs\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Configurations\n </div>\n </div>\n <tabset>\n @if (showBinaryBasedConfig && !showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'From repository' | translate }}</div>\n </div>\n }\n @if (!showBinaryBasedConfig && showTextBasedConfig) {\n <div class=\"card-header separator\">\n <div class=\"card-title\">{{ 'Custom' | translate }}</div>\n </div>\n }\n @if (showBinaryBasedConfig) {\n <tab>\n <ng-template tabHeading>\n <i\n c8yIcon=\"gears\"\n aria-hidden=\"true\"\n ></i>\n {{ 'From repository' | translate }}\n </ng-template>\n <c8y-resizable-grid\n [orientation]=\"'vertical'\"\n [trackId]=\"'c8y-device-configuration-split-view'\"\n [leftColumnWidth]=\"'50%'\"\n [collapsible]=\"false\"\n >\n <!-- ON DEVICE -->\n <div\n class=\"d-flex d-col fit-h min-height-0\"\n left-pane\n >\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span translate>On device</span>\n </h5>\n </div>\n <div class=\"card--grid grid__col--4-8--md m-b-0 flex-grow min-height-0\">\n <!-- DEVICE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <c8y-device-configuration-list\n [itemIcon]=\"'gears'\"\n [items]=\"supportedConfigurations\"\n (configSelected)=\"onConfigTypeSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div\n class=\"card--grid__inner-scroll d-flex d-col flex-grow min-height-0 bg-component\"\n >\n <div class=\"card-block d-flex d-col flex-grow min-height-0\">\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <fieldset\n class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\"\n >\n <legend translate>Preview</legend>\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </fieldset>\n }\n <!-- PREVIEW AVAILABLE STATE -->\n @if (configurationType) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow min-height-0\"\n [actionButtonIcon]=\"'arrow-down'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"configSnapshot\"\n [canSaveSnapshot]=\"true\"\n [operationToTrigger]=\"'c8y_UploadConfigFile'\"\n [actionButtonText]=\"'Get snapshot from device' | translate\"\n [isLegacy]=\"isLegacy\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </div>\n\n <!-- AVAILABLE FROM REPOSITORY: depends on the on-device selection above -->\n <div\n class=\"d-flex d-col fit-h min-height-0\"\n right-pane\n >\n <div class=\"p-l-16 p-r-16\">\n <h5 class=\"legend form-block\">\n <span\n class=\"m-r-8\"\n translate\n >\n Available from repository\n </span>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Supported predefined configurations you can send to this device' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n >\n <i c8yIcon=\"question-circle-o\"></i>\n </button>\n </h5>\n </div>\n <div class=\"card--grid grid__col--4-8--md m-b-0 flex-grow min-height-0\">\n <!-- AVAILABLE SUPPORTED CONFIGURATIONS -->\n <div class=\"card--grid__inner-scroll bg-level-1\">\n <!-- EMPTY STATE -->\n @if (!configurationType) {\n <c8y-ui-empty-state\n [icon]=\"'gears'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"\n 'Select a configuration type from the list above to view matching repository items.'\n | translate\n \"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n @if (configurationType) {\n <div class=\"p-r-16\">\n <c8y-device-configuration-list\n [itemIcon]=\"'file-text'\"\n [items]=\"repositorySnapshots\"\n [emptyState]=\"repositorySnapshotsEmptyState\"\n [isFilterEnabled]=\"true\"\n (configSelected)=\"onRepositoryConfigSelected($event)\"\n ></c8y-device-configuration-list>\n </div>\n }\n </div>\n <!-- CONFIGURATION PREVIEW -->\n <div\n class=\"card--grid__inner-scroll d-flex d-col flex-grow min-height-0 bg-component\"\n >\n <div class=\"card-block d-flex d-col flex-grow min-height-0\">\n <!-- EMPTY STATE -->\n @if (!repositorySnapshot) {\n <fieldset\n class=\"c8y-fieldset p-l-16 p-r-16 p-b-16 flex-grow d-flex d-col min-height-0\"\n >\n <legend translate>Preview</legend>\n <c8y-ui-empty-state\n [icon]=\"'file-text'\"\n [title]=\"'No configuration selected.' | translate\"\n [subtitle]=\"'Select a configuration to preview.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </fieldset>\n }\n <!-- CONFIGURATION SELECTED STATE -->\n @if (repositorySnapshot) {\n <c8y-device-configuration-preview\n class=\"d-flex d-col flex-grow min-height-0\"\n [actionButtonIcon]=\"'arrow-up'\"\n [device]=\"device\"\n [configurationType]=\"configurationType\"\n [configSnapshot]=\"repositorySnapshot\"\n [operationToTrigger]=\"'c8y_DownloadConfigFile'\"\n [actionButtonText]=\"'Send configuration to device' | translate\"\n [isLegacy]=\"isLegacy\"\n [editableRepositoryMo]=\"selectedRepositoryMo\"\n (editInRepository)=\"openEditInRepository($event)\"\n ></c8y-device-configuration-preview>\n }\n </div>\n </div>\n </div>\n </div>\n </c8y-resizable-grid>\n </tab>\n }\n @if (showTextBasedConfig) {\n <tab>\n <ng-template tabHeading>\n <i\n c8yIcon=\"code\"\n aria-hidden=\"true\"\n ></i>\n {{ 'Custom' | translate }}\n </ng-template>\n <c8y-text-based-configuration></c8y-text-based-configuration>\n </tab>\n }\n </tabset>\n</div>\n" }]
952
1009
  }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: DeviceConfigurationService }, { type: i3.RepositoryService }], propDecorators: { textBasedConfigurationComponent: [{
953
1010
  type: ViewChild,
954
1011
  args: [TextBasedConfigurationComponent]