@c8y/ngx-components 1024.2.4 → 1024.8.3

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 (71) hide show
  1. package/fesm2022/{c8y-ngx-components-asset-property-grid.component-DhfJagxU.mjs → c8y-ngx-components-asset-property-grid.component-Ddva2QJW.mjs} +35 -19
  2. package/fesm2022/c8y-ngx-components-asset-property-grid.component-Ddva2QJW.mjs.map +1 -0
  3. package/fesm2022/c8y-ngx-components-bookmarks.mjs +33 -23
  4. package/fesm2022/c8y-ngx-components-bookmarks.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +30 -16
  6. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +3 -2
  8. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +2 -2
  10. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-device-profile.mjs +27 -9
  12. package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-icon-selector.mjs +1538 -59
  14. package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +9 -11
  16. package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-remote-access-data.mjs +52 -2
  18. package/fesm2022/c8y-ngx-components-remote-access-data.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +17 -3
  20. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs +184 -41
  22. package/fesm2022/c8y-ngx-components-remote-access-terminal-viewer.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +94 -49
  24. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  25. package/fesm2022/c8y-ngx-components-repository-firmware.mjs +5 -4
  26. package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
  27. package/fesm2022/c8y-ngx-components-repository-software.mjs +10 -4
  28. package/fesm2022/c8y-ngx-components-repository-software.mjs.map +1 -1
  29. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +5 -4
  30. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
  31. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +6 -5
  32. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
  33. package/fesm2022/c8y-ngx-components.mjs +10 -5
  34. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  35. package/locales/de.po +327 -8
  36. package/locales/es.po +327 -8
  37. package/locales/fr.po +327 -8
  38. package/locales/ja_JP.po +325 -9
  39. package/locales/ko.po +327 -8
  40. package/locales/locales.pot +326 -7
  41. package/locales/nl.po +327 -8
  42. package/locales/pl.po +327 -8
  43. package/locales/pt_BR.po +327 -8
  44. package/locales/zh_CN.po +327 -8
  45. package/locales/zh_TW.po +327 -8
  46. package/package.json +1 -1
  47. package/types/c8y-ngx-components-bookmarks.d.ts +7 -7
  48. package/types/c8y-ngx-components-bookmarks.d.ts.map +1 -1
  49. package/types/c8y-ngx-components-context-dashboard.d.ts +7 -3
  50. package/types/c8y-ngx-components-context-dashboard.d.ts.map +1 -1
  51. package/types/c8y-ngx-components-device-profile.d.ts +5 -2
  52. package/types/c8y-ngx-components-device-profile.d.ts.map +1 -1
  53. package/types/c8y-ngx-components-icon-selector.d.ts +286 -32
  54. package/types/c8y-ngx-components-icon-selector.d.ts.map +1 -1
  55. package/types/c8y-ngx-components-protocol-opcua.d.ts.map +1 -1
  56. package/types/c8y-ngx-components-remote-access-data.d.ts +27 -1
  57. package/types/c8y-ngx-components-remote-access-data.d.ts.map +1 -1
  58. package/types/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.d.ts +10 -3
  59. package/types/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.d.ts.map +1 -1
  60. package/types/c8y-ngx-components-remote-access-terminal-viewer.d.ts +20 -2
  61. package/types/c8y-ngx-components-remote-access-terminal-viewer.d.ts.map +1 -1
  62. package/types/c8y-ngx-components-repository-configuration.d.ts +20 -10
  63. package/types/c8y-ngx-components-repository-configuration.d.ts.map +1 -1
  64. package/types/c8y-ngx-components-repository-firmware.d.ts.map +1 -1
  65. package/types/c8y-ngx-components-repository-software.d.ts +2 -0
  66. package/types/c8y-ngx-components-repository-software.d.ts.map +1 -1
  67. package/types/c8y-ngx-components-trusted-certificates.d.ts.map +1 -1
  68. package/types/c8y-ngx-components-widgets-implementations-asset-table.d.ts.map +1 -1
  69. package/types/c8y-ngx-components.d.ts +5 -1
  70. package/types/c8y-ngx-components.d.ts.map +1 -1
  71. package/fesm2022/c8y-ngx-components-asset-property-grid.component-DhfJagxU.mjs.map +0 -1
@@ -1,22 +1,22 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Injectable, Component, Pipe, inject, ChangeDetectorRef, signal, computed, Input, ChangeDetectionStrategy, Output, ViewChild, NgModule } from '@angular/core';
2
+ import { EventEmitter, Injectable, signal, computed, inject, DestroyRef, Component, Pipe, ChangeDetectorRef, Input, ChangeDetectionStrategy, Output, ViewChild, NgModule } from '@angular/core';
3
+ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
4
  import * as i1 from '@angular/router';
4
5
  import * as i3$1 from '@c8y/client';
5
6
  import { OperationStatus, InventoryBinaryService } from '@c8y/client';
6
7
  import { gettext } from '@c8y/ngx-components/gettext';
7
8
  import * as i2 from '@c8y/ngx-components';
8
- import { IconDirective, C8yTranslatePipe, BottomDrawerRef, AlertService, ValidationPattern, isBinaryFile, C8yTranslateDirective, FormGroupComponent, TypeaheadComponent, ForOfDirective, ListItemComponent, HighlightComponent, FilePickerComponent, MessagesComponent, RequiredInputPlaceholderDirective, SelectComponent, 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, 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';
10
+ import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
9
11
  import * as i3 from '@c8y/ngx-components/repository/shared';
10
12
  import { DeviceConfigurationOperation, RepositoryService, RepositoryType, mimeTypeToEditorLanguage, SharedRepositoryModule, RepositoryItemNameGridColumn, DescriptionGridColumn, FileGridColumn, DeviceTypeGridColumn, TypeGridColumn } from '@c8y/ngx-components/repository/shared';
11
13
  import { NgClass, NgIf, NgFor, AsyncPipe } from '@angular/common';
12
14
  import * as i1$1 from '@angular/forms';
13
- import { FormsModule, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
15
+ import { FormGroup, FormControl, ReactiveFormsModule, Validators, FormsModule } from '@angular/forms';
14
16
  import { OperationDetailsComponent, OperationDetailsModule } from '@c8y/ngx-components/operations/operation-details';
15
17
  import { has, uniqBy } from 'lodash-es';
16
18
  import { saveAs } from 'file-saver';
17
19
  import { map } from 'rxjs/operators';
18
- import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
19
- import { EditorComponent, MonacoEditorMarkerValidatorDirective } from '@c8y/ngx-components/editor';
20
20
  import { pipe } from 'rxjs';
21
21
  import * as i1$3 from 'ngx-bootstrap/tabs';
22
22
  import { TabsetComponent, TabDirective, TabsModule } from 'ngx-bootstrap/tabs';
@@ -67,6 +67,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
67
67
  type: Injectable
68
68
  }], ctorParameters: () => [{ type: i2.BottomDrawerService }] });
69
69
 
70
+ /** Shared language list for Monaco-based configuration editors (no "Auto" option). */
71
+ const EDITOR_LANGUAGES = [
72
+ { value: 'json', label: gettext('JSON') },
73
+ { value: 'javascript', label: gettext('JavaScript') },
74
+ { value: 'typescript', label: gettext('TypeScript') },
75
+ { value: 'css', label: gettext('CSS') },
76
+ { value: 'html', label: gettext('HTML') },
77
+ { value: 'yaml', label: gettext('YAML') },
78
+ { value: 'markdown', label: gettext('Markdown') },
79
+ { value: 'xml', label: gettext('XML') },
80
+ { value: 'ini', label: gettext('INI / TOML / Properties') },
81
+ { value: 'shell', label: gettext('Shell') },
82
+ { value: 'plaintext', label: gettext('Plain text') }
83
+ ];
84
+
85
+ // Device text configs are plain text by default — put plaintext first in the picker.
86
+ const PLAINTEXT_OPTION = EDITOR_LANGUAGES[EDITOR_LANGUAGES.length - 1];
87
+ const TEXT_EDITOR_LANGUAGES = [
88
+ PLAINTEXT_OPTION,
89
+ ...EDITOR_LANGUAGES.slice(0, -1)
90
+ ];
70
91
  class TextBasedConfigurationComponent {
71
92
  constructor(route, alertService, repositoryService, deviceConfigurationService, inventoryService) {
72
93
  this.route = route;
@@ -74,7 +95,38 @@ class TextBasedConfigurationComponent {
74
95
  this.repositoryService = repositoryService;
75
96
  this.deviceConfigurationService = deviceConfigurationService;
76
97
  this.inventoryService = inventoryService;
77
- this.reloadingConfig = false;
98
+ this.reloadingConfig = signal(false, ...(ngDevMode ? [{ debugName: "reloadingConfig" }] : /* istanbul ignore next */ []));
99
+ this.latestOperation = signal(undefined, ...(ngDevMode ? [{ debugName: "latestOperation" }] : /* istanbul ignore next */ []));
100
+ this.form = new FormGroup({
101
+ config: new FormControl(''),
102
+ language: new FormControl(PLAINTEXT_OPTION)
103
+ });
104
+ this.editorLanguages = TEXT_EDITOR_LANGUAGES;
105
+ this.editorLanguageValue = toSignal(this.form.controls.language.valueChanges, {
106
+ initialValue: PLAINTEXT_OPTION
107
+ });
108
+ this.editorLanguage = computed(() => this.editorLanguageValue()?.value ?? 'plaintext', ...(ngDevMode ? [{ debugName: "editorLanguage" }] : /* istanbul ignore next */ []));
109
+ this.savingConfig = computed(() => {
110
+ const operation = this.latestOperation();
111
+ return operation
112
+ ? !!operation.c8y_Configuration &&
113
+ (operation.status === OperationStatus.PENDING ||
114
+ operation.status === OperationStatus.EXECUTING)
115
+ : false;
116
+ }, ...(ngDevMode ? [{ debugName: "savingConfig" }] : /* istanbul ignore next */ []));
117
+ // Read-only is driven through editorOptions (not the form control's disabled state) because
118
+ // the editor only applies the disabled state at creation time. computed() keeps the reference
119
+ // stable until read-only actually changes, so the editor does not re-run updateOptions() needlessly.
120
+ this.editorOptions = computed(() => ({
121
+ language: this.editorLanguage(),
122
+ readOnly: this.reloadingConfig() || this.savingConfig(),
123
+ minimap: { enabled: false },
124
+ scrollBeyondLastLine: false
125
+ }), ...(ngDevMode ? [{ debugName: "editorOptions" }] : /* istanbul ignore next */ []));
126
+ this.destroyRef = inject(DestroyRef);
127
+ }
128
+ get configControl() {
129
+ return this.form.controls.config;
78
130
  }
79
131
  async ngOnInit() {
80
132
  await this.load();
@@ -86,35 +138,30 @@ class TextBasedConfigurationComponent {
86
138
  this.showTextBasedConfigReload = this.deviceConfigurationService.hasAnySupportedOperation(this.device, [DeviceConfigurationOperation.SEND_CONFIG]);
87
139
  this.showTextBasedConfigSave = this.deviceConfigurationService.hasAnySupportedOperation(this.device, [DeviceConfigurationOperation.CONFIG]);
88
140
  if (this.device.c8y_Configuration && this.device.c8y_Configuration.config) {
89
- this.config = this.device.c8y_Configuration.config;
141
+ this.configControl.setValue(this.device.c8y_Configuration.config);
90
142
  }
91
143
  }
92
144
  async loadOperation() {
93
145
  const operation = await this.repositoryService.getLastConfigUpdateOperation(this.device.id);
94
146
  if (operation !== null) {
95
- this.reloadingConfig =
96
- !!operation.c8y_SendConfiguration &&
97
- (operation.status === OperationStatus.PENDING ||
98
- operation.status === OperationStatus.EXECUTING);
99
- this.repositoryService.observeOperation(operation).subscribe(operationUpdate => {
147
+ this.reloadingConfig.set(!!operation.c8y_SendConfiguration &&
148
+ (operation.status === OperationStatus.PENDING ||
149
+ operation.status === OperationStatus.EXECUTING));
150
+ this.repositoryService
151
+ .observeOperation(operation)
152
+ .pipe(takeUntilDestroyed(this.destroyRef))
153
+ .subscribe(operationUpdate => {
100
154
  if (operationUpdate.status === OperationStatus.PENDING ||
101
155
  operationUpdate.status === OperationStatus.EXECUTING) {
102
- this.latestOperation = operationUpdate;
156
+ this.latestOperation.set(operationUpdate);
103
157
  }
104
158
  else
105
- this.latestOperation = null;
159
+ this.latestOperation.set(null);
106
160
  });
107
161
  }
108
162
  }
109
- get savingConfig() {
110
- return this.latestOperation
111
- ? !!this.latestOperation.c8y_Configuration &&
112
- (this.latestOperation.status === OperationStatus.PENDING ||
113
- this.latestOperation.status === OperationStatus.EXECUTING)
114
- : false;
115
- }
116
163
  async reloadConfiguration() {
117
- this.reloadingConfig = true;
164
+ this.reloadingConfig.set(true);
118
165
  const operationCfg = await this.repositoryService.createTextBasedConfigurationReloadOperation(this.device);
119
166
  try {
120
167
  this.repositoryService.createObservedOperation(operationCfg).subscribe(operationUpdate => this.onOperationReloadSuccess(operationUpdate), operationUpdate => this.onOperationReloadError(operationUpdate), () => this.onOperationReloadComplete());
@@ -133,31 +180,31 @@ class TextBasedConfigurationComponent {
133
180
  }
134
181
  }
135
182
  onOperationReloadSuccess(operationUpdate) {
136
- this.latestOperation = operationUpdate;
183
+ this.latestOperation.set(operationUpdate);
137
184
  if (operationUpdate.status === OperationStatus.PENDING) {
138
185
  this.alertService.success(gettext('Configuration will be reloaded.'));
139
186
  }
140
187
  }
141
188
  onOperationReloadError(operationUpdate) {
142
- this.latestOperation = operationUpdate;
143
- this.reloadingConfig = false;
189
+ this.latestOperation.set(operationUpdate);
190
+ this.reloadingConfig.set(false);
144
191
  }
145
192
  async onOperationReloadComplete() {
146
193
  await this.loadDevice();
147
- this.config = this.device.c8y_Configuration.config;
148
- this.reloadingConfig = false;
194
+ this.configControl.setValue(this.device.c8y_Configuration.config);
195
+ this.reloadingConfig.set(false);
149
196
  }
150
197
  onOperationUpdateSuccess(operationUpdate) {
151
- this.latestOperation = operationUpdate;
198
+ this.latestOperation.set(operationUpdate);
152
199
  if (operationUpdate.status === OperationStatus.PENDING) {
153
200
  this.alertService.success(gettext('Configuration will be updated.'));
154
201
  }
155
202
  }
156
203
  onOperationUpdateError(operationUpdate) {
157
- this.latestOperation = operationUpdate;
204
+ this.latestOperation.set(operationUpdate);
158
205
  }
159
206
  onOperationUpdateComplete() {
160
- this.device.c8y_Configuration.config = this.config;
207
+ this.device.c8y_Configuration.config = this.configControl.value;
161
208
  }
162
209
  async loadDevice() {
163
210
  this.device = (await this.inventoryService.detail(this.device.id, {
@@ -165,11 +212,19 @@ class TextBasedConfigurationComponent {
165
212
  })).data;
166
213
  }
167
214
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TextBasedConfigurationComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.AlertService }, { token: i3.RepositoryService }, { token: DeviceConfigurationService }, { token: i3$1.InventoryService }], target: i0.ɵɵFactoryTarget.Component }); }
168
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TextBasedConfigurationComponent, isStandalone: true, selector: "c8y-text-based-configuration", ngImport: i0, template: "<div class=\"d-flex d-col fit-h\">\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50\">\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=\"flex-grow\">\n <textarea\n class=\"form-control fit-h p-r-16 p-l-16\"\n [attr.aria-label]=\"'Operations' | translate\"\n [(ngModel)]=\"config\"\n [disabled]=\"reloadingConfig || savingConfig\"\n c8y-spellcheck=\"false\"\n ></textarea>\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 fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(config)\"\n [disabled]=\"reloadingConfig || savingConfig || !config\"\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: FormsModule }, { 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.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
215
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", 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" }] }); }
169
216
  }
170
217
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TextBasedConfigurationComponent, decorators: [{
171
218
  type: Component,
172
- args: [{ selector: 'c8y-text-based-configuration', imports: [IconDirective, NgClass, FormsModule, OperationDetailsComponent, C8yTranslatePipe], template: "<div class=\"d-flex d-col fit-h\">\n <fieldset class=\"card-block bg-level-1 fit-w\">\n <div class=\"content-flex-50\">\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=\"flex-grow\">\n <textarea\n class=\"form-control fit-h p-r-16 p-l-16\"\n [attr.aria-label]=\"'Operations' | translate\"\n [(ngModel)]=\"config\"\n [disabled]=\"reloadingConfig || savingConfig\"\n c8y-spellcheck=\"false\"\n ></textarea>\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 fit-w separator\">\n <button\n class=\"btn btn-primary\"\n id=\"send-config-btn\"\n type=\"button\"\n (click)=\"updateConfiguration(config)\"\n [disabled]=\"reloadingConfig || savingConfig || !config\"\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" }]
219
+ args: [{ selector: 'c8y-text-based-configuration', imports: [
220
+ IconDirective,
221
+ NgClass,
222
+ ReactiveFormsModule,
223
+ EditorComponent,
224
+ OperationDetailsComponent,
225
+ C8yTranslatePipe,
226
+ SelectComponent
227
+ ], 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" }]
173
228
  }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.AlertService }, { type: i3.RepositoryService }, { type: DeviceConfigurationService }, { type: i3$1.InventoryService }] });
174
229
 
175
230
  class DeviceConfigurationGuard {
@@ -257,20 +312,10 @@ function mimeForFilename(filename) {
257
312
  }
258
313
  /** Sentinel value meaning "derive language from filename". */
259
314
  const AUTO_LANGUAGE = 'auto';
260
- const EDITOR_LANGUAGES = [
261
- { value: AUTO_LANGUAGE, label: gettext('Auto (from filename)') },
262
- { value: 'json', label: gettext('JSON') },
263
- { value: 'javascript', label: gettext('JavaScript') },
264
- { value: 'typescript', label: gettext('TypeScript') },
265
- { value: 'css', label: gettext('CSS') },
266
- { value: 'html', label: gettext('HTML') },
267
- { value: 'yaml', label: gettext('YAML') },
268
- { value: 'markdown', label: gettext('Markdown') },
269
- { value: 'xml', label: gettext('XML') },
270
- { value: 'ini', label: gettext('INI / TOML / Properties') },
271
- { value: 'shell', label: gettext('Shell') },
272
- { value: 'plaintext', label: gettext('Plain text') }
273
- ];
315
+ const AUTO_LANGUAGE_OPTION = {
316
+ value: AUTO_LANGUAGE,
317
+ label: gettext('Auto (from filename)')
318
+ };
274
319
  class ConfigurationDetailComponent {
275
320
  constructor() {
276
321
  this.repositoryService = inject(RepositoryService);
@@ -298,7 +343,7 @@ class ConfigurationDetailComponent {
298
343
  editorFilename: new FormControl('', [
299
344
  Validators.pattern(ValidationPattern.rules.noWhiteSpaceOnly.pattern)
300
345
  ]),
301
- editorLanguage: new FormControl(EDITOR_LANGUAGES[0]),
346
+ editorLanguage: new FormControl(AUTO_LANGUAGE_OPTION),
302
347
  editorContent: new FormControl('')
303
348
  });
304
349
  this.configurationTypeMO = {};
@@ -321,7 +366,7 @@ class ConfigurationDetailComponent {
321
366
  initialValue: ''
322
367
  });
323
368
  this.editorLanguageValue = toSignal(this.form.controls.editorLanguage.valueChanges, {
324
- initialValue: EDITOR_LANGUAGES[0]
369
+ initialValue: AUTO_LANGUAGE_OPTION
325
370
  });
326
371
  /** User's manual pick (when not "auto") wins over auto-detection from filename. */
327
372
  this.editorLanguage = computed(() => {
@@ -330,7 +375,7 @@ class ConfigurationDetailComponent {
330
375
  ? detectLanguage(this.editorFilenameValue() ?? '')
331
376
  : picked;
332
377
  }, ...(ngDevMode ? [{ debugName: "editorLanguage" }] : /* istanbul ignore next */ []));
333
- this.editorLanguages = EDITOR_LANGUAGES;
378
+ this.editorLanguages = [AUTO_LANGUAGE_OPTION, ...EDITOR_LANGUAGES];
334
379
  this.submitButtonTitle = computed(() => this.mo?.id ? gettext('Update configuration') : gettext('Add configuration'), ...(ngDevMode ? [{ debugName: "submitButtonTitle" }] : /* istanbul ignore next */ []));
335
380
  this.form.controls.uploadChoice.valueChanges.pipe(takeUntilDestroyed()).subscribe(choice => {
336
381
  const ctrl = this.form.controls.editorFilename;