@c8y/ngx-components 1011.0.22 → 1011.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bundles/c8y-ngx-components-repository.umd.js +38 -15
  2. package/bundles/c8y-ngx-components-repository.umd.js.map +1 -1
  3. package/bundles/c8y-ngx-components-repository.umd.min.js +1 -1
  4. package/bundles/c8y-ngx-components-repository.umd.min.js.map +1 -1
  5. package/bundles/c8y-ngx-components-search.umd.js +7 -4
  6. package/bundles/c8y-ngx-components-search.umd.js.map +1 -1
  7. package/bundles/c8y-ngx-components-search.umd.min.js +1 -1
  8. package/bundles/c8y-ngx-components-search.umd.min.js.map +1 -1
  9. package/bundles/c8y-ngx-components-sensor-phone.umd.js +1 -1
  10. package/bundles/c8y-ngx-components-sensor-phone.umd.js.map +1 -1
  11. package/bundles/c8y-ngx-components-sensor-phone.umd.min.js +2 -2
  12. package/bundles/c8y-ngx-components-sensor-phone.umd.min.js.map +1 -1
  13. package/esm2015/repository/configuration/configuration-detail.component.js +7 -2
  14. package/esm2015/repository/configuration-device-tab/device-configuration.component.js +7 -2
  15. package/esm2015/repository/configuration-device-tab/device-configuration.guard.js +4 -2
  16. package/esm2015/repository/firmware-device-tab/firmware-device-tab.component.js +4 -3
  17. package/esm2015/repository/firmware-device-tab/firmware-device-tab.guard.js +4 -5
  18. package/esm2015/repository/software-device-tab/device-software-list.component.js +10 -3
  19. package/esm2015/repository/software-device-tab/installed-software.component.js +10 -2
  20. package/esm2015/repository/software-device-tab/software-device-tab.component.js +2 -2
  21. package/esm2015/repository/software-device-tab/software-device-tab.guard.js +9 -5
  22. package/esm2015/search/search-grid.component.js +2 -2
  23. package/esm2015/search/search.service.js +6 -4
  24. package/esm2015/sensor-phone/sensor-phone-modal.component.js +2 -2
  25. package/fesm2015/c8y-ngx-components-repository.js +43 -16
  26. package/fesm2015/c8y-ngx-components-repository.js.map +1 -1
  27. package/fesm2015/c8y-ngx-components-search.js +6 -4
  28. package/fesm2015/c8y-ngx-components-search.js.map +1 -1
  29. package/fesm2015/c8y-ngx-components-sensor-phone.js +1 -1
  30. package/fesm2015/c8y-ngx-components-sensor-phone.js.map +1 -1
  31. package/locales/locales.pot +13 -6
  32. package/package.json +2 -2
  33. package/repository/c8y-ngx-components-repository.metadata.json +1 -1
  34. package/repository/configuration/configuration-detail.component.d.ts +1 -0
  35. package/repository/configuration-device-tab/device-configuration.guard.d.ts +1 -1
  36. package/repository/firmware-device-tab/firmware-device-tab.component.d.ts +1 -0
  37. package/repository/firmware-device-tab/firmware-device-tab.guard.d.ts +1 -1
  38. package/repository/software-device-tab/device-software-list.component.d.ts +7 -2
  39. package/repository/software-device-tab/installed-software.component.d.ts +4 -0
  40. package/repository/software-device-tab/software-device-tab.guard.d.ts +2 -2
  41. package/search/c8y-ngx-components-search.metadata.json +1 -1
  42. package/search/search.service.d.ts +3 -1
  43. package/sensor-phone/c8y-ngx-components-sensor-phone.metadata.json +1 -1
@@ -7,7 +7,7 @@ import { PopoverModule } from 'ngx-bootstrap/popover';
7
7
  import { SingleOperationDetailsModule } from '@c8y/ngx-components/operations/single-operation-details';
8
8
  import { __awaiter, __decorate } from 'tslib';
9
9
  import { QueriesUtil, OperationStatus, InventoryService, InventoryBinaryService, OperationService, EventService, EventBinaryService, Realtime, UserService } from '@c8y/client';
10
- import { isNil, set, assign, isUndefined, get, isString, head, cloneDeep, map as map$1, pick, remove, forEach, find, property, uniqBy, isEmpty, indexOf, filter as filter$1 } from 'lodash-es';
10
+ import { isNil, set, assign, isUndefined, get, isString, head, cloneDeep, map as map$1, pick, remove, forEach, find, property, uniqBy, isEmpty, indexOf, has, filter as filter$1 } from 'lodash-es';
11
11
  import { of, from, defer, throwError, merge, BehaviorSubject, pipe, combineLatest, Subject } from 'rxjs';
12
12
  import { map, take, switchMap, withLatestFrom, filter, takeWhile, tap, debounceTime, distinctUntilChanged, shareReplay, distinctUntilKeyChanged, takeUntil, mergeMap } from 'rxjs/operators';
13
13
  import { Router, ActivatedRoute } from '@angular/router';
@@ -1851,6 +1851,11 @@ class ConfigurationDetailComponent {
1851
1851
  this.mo = {};
1852
1852
  this.saving = false;
1853
1853
  this.uploadChoice = 'uploadBinary';
1854
+ this.textForConfigurationUrlPopover = gettext(`Path for binaries can vary depending on device agent implementation, e.g.:
1855
+ /configuration/binaries/configuration1.bin
1856
+ https://configuration/binary/123
1857
+ ftp://configuration/binary/123.tar.gz
1858
+ `);
1854
1859
  this.result = new Promise((resolve, reject) => {
1855
1860
  this._save = resolve;
1856
1861
  this._cancel = reject;
@@ -1927,7 +1932,7 @@ class ConfigurationDetailComponent {
1927
1932
  ConfigurationDetailComponent.decorators = [
1928
1933
  { type: Component, args: [{
1929
1934
  selector: 'c8y-configuration-detail',
1930
- template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'cogs'\"></i>\n <h4 translate *ngIf=\"mo.id\">Update configuration</h4>\n <h4 translate *ngIf=\"!mo.id\">Add configuration</h4>\n </div>\n\n <form class=\"d-contents\" #configurationForm=\"ngForm\" (ngSubmit)=\"configurationForm.form.valid && save()\">\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\">\n <c8y-form-group>\n <label translate>Name</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n autocomplete=\"off\"\n required\n maxlength=\"254\"\n [(ngModel)]=\"version\"\n name=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Device type</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n maxlength=\"254\"\n autocomplete=\"off\"\n [(ngModel)]=\"deviceType\"\n name=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Description</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g. Host configuration' | translate }} c8y_Linux\"\n maxlength=\"254\"\n autocomplete=\"off\"\n [(ngModel)]=\"description\"\n name=\"description\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Configuration type</label>\n <c8y-typeahead\n [(ngModel)]=\"selected\"\n name=\"confType\"\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n <c8y-li\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"selected = config; setPipe('')\"\n [active]=\"selected === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"pattern\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li class=\"bg-gray-lighter p-8\" *ngIf=\"pattern.length > 0\">\n <span translate>No match found, add new`configuration`?</span>\n <button title=\"Create new`configuration`\" type=\"button\" class=\"btn btn-primary btn-xs m-l-16\" translate>\n Create new`configuration`\n </button>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Configuration file</div>\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n (onFilesPicked)=\"onFile($event)\"\n [uploadChoice]=\"uploadChoice\"\n [fileUrl]=\"binary.url\"\n [fileBinary]=\"binary.file\"\n >\n </c8y-file-picker>\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n [disabled]=\"saving\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ submitButtonTitle | translate }}\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !configurationForm.valid ||\n configurationForm.pristine ||\n (!binary?.url && !binary?.file) ||\n saving\n \"\n >\n {{ submitButtonTitle | translate }}\n </button>\n </div>\n </form>\n</div>\n"
1935
+ template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'cogs'\"></i>\n <h4 translate *ngIf=\"mo.id\">Update configuration</h4>\n <h4 translate *ngIf=\"!mo.id\">Add configuration</h4>\n </div>\n\n <form class=\"d-contents\" #configurationForm=\"ngForm\" (ngSubmit)=\"configurationForm.form.valid && save()\">\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\">\n <c8y-form-group>\n <label translate>Name</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} hosts\"\n autocomplete=\"off\"\n required\n maxlength=\"254\"\n [(ngModel)]=\"version\"\n name=\"version\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Device type</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n maxlength=\"254\"\n autocomplete=\"off\"\n [(ngModel)]=\"deviceType\"\n name=\"deviceType\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Description</label>\n <input\n type=\"text\"\n class=\"form-control\"\n placeholder=\"{{ 'e.g. Host configuration' | translate }} c8y_Linux\"\n maxlength=\"254\"\n autocomplete=\"off\"\n [(ngModel)]=\"description\"\n name=\"description\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label translate>Configuration type</label>\n <c8y-typeahead\n [(ngModel)]=\"selected\"\n name=\"confType\"\n placeholder=\"{{ 'e.g.' | translate }} ssh\"\n (onSearch)=\"setPipe($event)\"\n displayProperty=\"configurationType\"\n >\n <c8y-li\n *c8yFor=\"let config of configs; pipe: filterPipe; notFound: notFoundTemplate\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"selected = config; setPipe('')\"\n [active]=\"selected === config\"\n >\n <c8y-highlight\n [text]=\"config.configurationType || '--'\"\n [pattern]=\"pattern\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li class=\"bg-gray-lighter p-8\" *ngIf=\"pattern.length > 0\">\n <span translate>No match found, add new`configuration`?</span>\n <button title=\"Create new`configuration`\" type=\"button\" class=\"btn btn-primary btn-xs m-l-16\" translate>\n Create new`configuration`\n </button>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Configuration file</div>\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n (onFilesPicked)=\"onFile($event)\"\n [uploadChoice]=\"uploadChoice\"\n [fileUrl]=\"binary.url\"\n [fileBinary]=\"binary.file\"\n [fileUrlPopover]=\"textForConfigurationUrlPopover\"\n >\n </c8y-file-picker>\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n [disabled]=\"saving\"\n >\n <span translate>Cancel</span>\n </button>\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ submitButtonTitle | translate }}\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !configurationForm.valid ||\n configurationForm.pristine ||\n (!binary?.url && !binary?.file) ||\n saving\n \"\n >\n {{ submitButtonTitle | translate }}\n </button>\n </div>\n </form>\n</div>\n"
1931
1936
  },] }
1932
1937
  ];
1933
1938
  ConfigurationDetailComponent.ctorParameters = () => [
@@ -2381,6 +2386,7 @@ class FirmwareDeviceTabComponent {
2381
2386
  return of([]);
2382
2387
  }
2383
2388
  }), shareReplay(1));
2389
+ this.supportsFirmwareOperations$ = this.device$.pipe(map((device) => get(device, 'c8y_SupportedOperations', []).indexOf('c8y_Firmware') > -1));
2384
2390
  this.changesOperation$ = new BehaviorSubject(null);
2385
2391
  this.changesInProgress$ = this.changesOperation$.pipe(map(operation => this.isInProgress(operation)));
2386
2392
  }
@@ -2515,7 +2521,7 @@ class FirmwareDeviceTabComponent {
2515
2521
  FirmwareDeviceTabComponent.decorators = [
2516
2522
  { type: Component, args: [{
2517
2523
  selector: 'c8y-firmware-device-tab',
2518
- template: "<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card\">\n <div class=\"card-header separator\">\n <h4 class=\"card-title\" translate>Current firmware</h4>\n </div>\n <div class=\"inner-scroll\">\n <fieldset *ngIf=\"changesOperation$ | async\" class=\"card-block bg-gray-white\">\n <c8y-single-operation [operation]=\"changesOperation$ | async\"></c8y-single-operation>\n </fieldset>\n <div class=\"card-block p-t-0 p-b-0\">\n \n <!-- EMPTY STATE -->\n <ng-container *ngIf=\"isEmpty(deviceFirmwareFragment$ | async); else firmwareBlock\">\n <div class=\"c8y-empty-state text-center\">\n <h1 c8yIcon=\"c8y-firmware\" class=\"c8y-icon-duocolor\"></h1>\n <p>\n <strong translate>No firmware installed.</strong> <br />\n <small translate>Click below to install firmware into this device.</small>\n </p>\n </div>\n </ng-container>\n\n <!-- FIRMWARE -->\n <ng-template #firmwareBlock>\n <c8y-list-group class=\"no-border-last\">\n <c8y-li>\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body *ngIf=\"deviceFirmwareFragment$ | async as deviceFirmwareFragment\">\n <!-- Firmware title -->\n <p class=\"m-b-16 text-medium\">\n {{ deviceFirmwareFragment.name }}\n </p>\n <!-- Firmware description -->\n <div *ngIf=\"repositoryEntry$ | async as repositoryEntry\">\n <p class=\"text-label-small\" translate>\n Description\n </p>\n <p>\n {{ repositoryEntry.description }}\n </p>\n </div>\n\n <!-- BASE/PATCH VERSION -->\n <div class=\"m-b-16\">\n <p class=\"text-label-small\" translate>\n Version\n </p>\n <p *ngIf=\"deviceFirmwareFragment.version; else versionNotSpecified\">\n {{ deviceFirmwareFragment.version }}\n </p>\n <ng-template #versionNotSpecified>\n <p>\n <em class=\"text-muted\"> ({{ 'not specified`version`' | translate }}) </em>\n </p>\n </ng-template>\n </div>\n\n <!-- ADD PATCH -->\n <button\n *ngIf=\"(this.patches$ | async)?.length > 0\"\n (click)=\"addPatch()\"\n class=\"btn btn-xs btn-primary\"\n [disabled]=\"changesInProgress$ | async\"\n title=\"{{ 'Patches available' | translate }}\"\n >\n {{ 'Patches available' | translate }}\n </button>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </ng-template>\n </div>\n </div>\n <div class=\"card-footer separator-top\">\n\n <!-- INSTALL FIRMWARE -->\n <button\n *ngIf=\"isEmpty(deviceFirmwareFragment$ | async)\"\n class=\"btn btn-primary\"\n (click)=\"installFirmware()\"\n title=\"{{ 'Install firmware' | translate }}\"\n >\n {{ 'Install firmware' | translate }}\n </button>\n\n <!-- REPLACE FIRMWARE -->\n <button\n *ngIf=\"!isEmpty(deviceFirmwareFragment$ | async)\"\n class=\"btn btn-primary\"\n (click)=\"installFirmware()\"\n [disabled]=\"changesInProgress$ | async\"\n title=\"{{ 'Replace firmware' | translate }}\"\n >\n {{ 'Replace firmware' | translate }}\n </button>\n </div>\n </div>\n </div>\n</div>\n"
2524
+ template: "<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card\">\n <div class=\"card-header separator\">\n <h4 class=\"card-title\" translate>Current firmware</h4>\n </div>\n <div class=\"inner-scroll\">\n <fieldset *ngIf=\"changesOperation$ | async\" class=\"card-block bg-gray-white\">\n <c8y-single-operation [operation]=\"changesOperation$ | async\"></c8y-single-operation>\n </fieldset>\n <div class=\"card-block p-t-0 p-b-0\">\n <!-- EMPTY STATE -->\n <ng-container *ngIf=\"isEmpty(deviceFirmwareFragment$ | async); else firmwareBlock\">\n <div class=\"c8y-empty-state text-center\">\n <h1 c8yIcon=\"c8y-firmware\" class=\"c8y-icon-duocolor\"></h1>\n <p>\n <strong translate>No firmware installed.</strong> <br />\n <small translate>Click below to install firmware into this device.</small>\n </p>\n </div>\n </ng-container>\n\n <!-- FIRMWARE -->\n <ng-template #firmwareBlock>\n <c8y-list-group class=\"no-border-last\">\n <c8y-li>\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body *ngIf=\"deviceFirmwareFragment$ | async as deviceFirmwareFragment\">\n <!-- Firmware title -->\n <p class=\"m-b-16 text-medium\">\n {{ deviceFirmwareFragment.name }}\n </p>\n <!-- Firmware description -->\n <div *ngIf=\"repositoryEntry$ | async as repositoryEntry\">\n <p class=\"text-label-small\" translate>Description</p>\n <p>\n {{ repositoryEntry.description }}\n </p>\n </div>\n\n <!-- BASE/PATCH VERSION -->\n <div class=\"m-b-16\">\n <p class=\"text-label-small\" translate>Version</p>\n <p *ngIf=\"deviceFirmwareFragment.version; else versionNotSpecified\">\n {{ deviceFirmwareFragment.version }}\n </p>\n <ng-template #versionNotSpecified>\n <p>\n <em class=\"text-muted\"> ({{ 'not specified`version`' | translate }}) </em>\n </p>\n </ng-template>\n </div>\n\n <!-- ADD PATCH -->\n <button\n *ngIf=\"\n (supportsFirmwareOperations$ | async) && (this.patches$ | async)?.length > 0\n \"\n (click)=\"addPatch()\"\n class=\"btn btn-xs btn-primary\"\n [disabled]=\"changesInProgress$ | async\"\n title=\"{{ 'Patches available' | translate }}\"\n >\n {{ 'Patches available' | translate }}\n </button>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </ng-template>\n </div>\n </div>\n <div *ngIf=\"supportsFirmwareOperations$ | async\" class=\"card-footer separator-top\">\n <!-- INSTALL FIRMWARE -->\n <button\n *ngIf=\"isEmpty(deviceFirmwareFragment$ | async)\"\n class=\"btn btn-primary\"\n (click)=\"installFirmware()\"\n title=\"{{ 'Install firmware' | translate }}\"\n >\n {{ 'Install firmware' | translate }}\n </button>\n\n <!-- REPLACE FIRMWARE -->\n <button\n *ngIf=\"!isEmpty(deviceFirmwareFragment$ | async)\"\n class=\"btn btn-primary\"\n (click)=\"installFirmware()\"\n [disabled]=\"changesInProgress$ | async\"\n title=\"{{ 'Replace firmware' | translate }}\"\n >\n {{ 'Replace firmware' | translate }}\n </button>\n </div>\n </div>\n </div>\n</div>\n"
2519
2525
  },] }
2520
2526
  ];
2521
2527
  FirmwareDeviceTabComponent.ctorParameters = () => [
@@ -2531,9 +2537,8 @@ class FirmwareDeviceTabGuard {
2531
2537
  canActivate(route) {
2532
2538
  const contextData = get(route, 'data.contextData') || get(route, 'parent.data.contextData');
2533
2539
  const supportedOperations = get(contextData, SUPPORTED_OPERATIONS_FRAGMENT);
2534
- return !!supportedOperations
2535
- ? indexOf(supportedOperations, FIRMWARE_FRAGMENT) >= 0
2536
- : false;
2540
+ return ((!!supportedOperations ? indexOf(supportedOperations, FIRMWARE_FRAGMENT) >= 0 : false) ||
2541
+ has(contextData, 'c8y_Firmware'));
2537
2542
  }
2538
2543
  }
2539
2544
  FirmwareDeviceTabGuard.decorators = [
@@ -2629,7 +2634,7 @@ class SoftwareDeviceTabComponent {
2629
2634
  SoftwareDeviceTabComponent.decorators = [
2630
2635
  { type: Component, args: [{
2631
2636
  selector: 'c8y-software-device-tab',
2632
- template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\" (click)=\"loadDevice()\">\n <i c8yIcon=\"refresh\" [ngClass]=\"{ 'icon-spin': reloading }\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card d-grid grid__col--8-4--md m-b-0\">\n <c8y-installed-software\n class=\"card--fullpage bg-white\"\n [deviceTypeQuery]=\"deviceTypeQuery$ | async\"\n [softwareList]=\"list$ | async\"\n [deviceSoftwareChanges]=\"changes$ | async\"\n [deviceSoftwareChangesOperation]=\"changesOperation$ | async\"\n [deviceSoftwareChangesInProgress]=\"changesInProgress$ | async\"\n (changes)=\"addChanges($event)\"\n ></c8y-installed-software>\n <c8y-device-software-changes\n class=\"card--fullpage bg-gray-white\"\n [changes]=\"changes$ | async\"\n [changesInProgress]=\"changesInProgress$ | async\"\n (clear)=\"clearChanges()\"\n (drop)=\"dropChange($event)\"\n (apply)=\"applyChanges()\"\n ></c8y-device-software-changes>\n</div>\n"
2637
+ template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\" (click)=\"loadDevice()\">\n <i c8yIcon=\"refresh\" [ngClass]=\"{ 'icon-spin': reloading }\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"card d-grid grid__col--8-4--md m-b-0\">\n <c8y-installed-software\n class=\"card--fullpage bg-white\"\n [device]=\"device$ | async\"\n [deviceTypeQuery]=\"deviceTypeQuery$ | async\"\n [softwareList]=\"list$ | async\"\n [deviceSoftwareChanges]=\"changes$ | async\"\n [deviceSoftwareChangesOperation]=\"changesOperation$ | async\"\n [deviceSoftwareChangesInProgress]=\"changesInProgress$ | async\"\n (changes)=\"addChanges($event)\"\n ></c8y-installed-software>\n <c8y-device-software-changes\n class=\"card--fullpage bg-gray-white\"\n [changes]=\"changes$ | async\"\n [changesInProgress]=\"changesInProgress$ | async\"\n (clear)=\"clearChanges()\"\n (drop)=\"dropChange($event)\"\n (apply)=\"applyChanges()\"\n ></c8y-device-software-changes>\n</div>\n"
2633
2638
  },] }
2634
2639
  ];
2635
2640
  SoftwareDeviceTabComponent.ctorParameters = () => [
@@ -2643,11 +2648,14 @@ class SoftwareDeviceTabGuard {
2643
2648
  this.operations = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
2644
2649
  }
2645
2650
  canActivate(route) {
2646
- return this.isAnyOperationSupported(route);
2647
- }
2648
- isAnyOperationSupported(route) {
2649
- const device = route.data.contextData || route.parent.data.contextData;
2650
- const supportedOperations = (device && device.c8y_SupportedOperations) || [];
2651
+ const device = get(route, 'data.contextData') || get(route, 'parent.data.contextData');
2652
+ return (this.isAnyOperationSupported(device) ||
2653
+ has(device, 'c8y_Software') ||
2654
+ has(device, 'c8y_SoftwareList') ||
2655
+ has(device, 'c8y_SupportedSoftwareTypes'));
2656
+ }
2657
+ isAnyOperationSupported(device) {
2658
+ const supportedOperations = (device === null || device === void 0 ? void 0 : device.c8y_SupportedOperations) || [];
2651
2659
  return this.operations.some(operation => supportedOperations.indexOf(operation) >= 0);
2652
2660
  }
2653
2661
  }
@@ -2661,6 +2669,12 @@ class InstalledSoftwareComponent {
2661
2669
  this.inventory = inventory;
2662
2670
  this.bsModal = bsModal;
2663
2671
  this.changes = new EventEmitter();
2672
+ this.supportsSoftwareOperations = false;
2673
+ this.operationTypes = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
2674
+ }
2675
+ ngOnInit() {
2676
+ const supportedOperations = get(this.device, 'c8y_SupportedOperations', []);
2677
+ this.supportsSoftwareOperations = this.operationTypes.some(operationType => supportedOperations.indexOf(operationType) > -1);
2664
2678
  }
2665
2679
  installSoftware() {
2666
2680
  this.displaySoftwareSelectModal({
@@ -2735,7 +2749,7 @@ class InstalledSoftwareComponent {
2735
2749
  InstalledSoftwareComponent.decorators = [
2736
2750
  { type: Component, args: [{
2737
2751
  selector: 'c8y-installed-software',
2738
- template: "<div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header large-padding separator sticky-top\">\n <h4 class=\"card-title\" translate>Installed software</h4>\n </div>\n <div class=\"flex-grow\">\n <fieldset *ngIf=\"deviceSoftwareChangesOperation\" class=\"card-block large-padding bg-gray-lighter\">\n <c8y-single-operation [operation]=\"deviceSoftwareChangesOperation\"></c8y-single-operation>\n </fieldset>\n\n <fieldset class=\"d-contents\" [disabled]=\"deviceSoftwareChangesInProgress\">\n <!-- EMPTY STATE -->\n <div class=\"card-block\" *ngIf=\"softwareList.length === 0\">\n <div class=\"c8y-empty-state text-center m-t-16\">\n <h1 class=\"c8y-icon c8y-icon-tools c8y-icon-duocolor\"></h1>\n <p>\n <strong translate>No software installed.</strong> <br />\n <small translate>Click below to install software into this device.</small>\n </p>\n </div>\n </div>\n\n <!-- NOT EMPTY STATE -->\n <ng-container *ngIf=\"softwareList.length > 0\">\n <c8y-device-software-list\n [softwareList]=\"softwareList\"\n [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n (update)=\"updateSoftware($event)\"\n (remove)=\"removeSoftware($event)\"\n class=\"d-block p-l-16 p-r-16\"\n >\n </c8y-device-software-list>\n </ng-container>\n </fieldset>\n </div>\n<!-- INSTALL SOFTWARE-->\n <div class=\"card-footer large-padding separator sticky-bottom\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Install software' | translate }}\"\n (click)=\"installSoftware()\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install software' | translate }}\n </button>\n </div>\n</div>\n"
2752
+ template: "<div class=\"inner-scroll d-flex d-col\">\n <div class=\"card-header large-padding separator sticky-top\">\n <h4 class=\"card-title\" translate>Installed software</h4>\n </div>\n <div class=\"flex-grow\">\n <fieldset *ngIf=\"deviceSoftwareChangesOperation\" class=\"card-block large-padding bg-gray-lighter\">\n <c8y-single-operation [operation]=\"deviceSoftwareChangesOperation\"></c8y-single-operation>\n </fieldset>\n\n <fieldset class=\"d-contents\" [disabled]=\"deviceSoftwareChangesInProgress\">\n <!-- EMPTY STATE -->\n <div class=\"card-block\" *ngIf=\"softwareList.length === 0\">\n <div class=\"c8y-empty-state text-center m-t-16\">\n <h1 class=\"c8y-icon c8y-icon-tools c8y-icon-duocolor\"></h1>\n <p>\n <strong translate>No software installed.</strong> <br />\n <small translate>Click below to install software into this device.</small>\n </p>\n </div>\n </div>\n\n <!-- NOT EMPTY STATE -->\n <ng-container *ngIf=\"softwareList.length > 0\">\n <c8y-device-software-list\n [device]=\"device\"\n [softwareList]=\"softwareList\"\n [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n (update)=\"updateSoftware($event)\"\n (remove)=\"removeSoftware($event)\"\n class=\"d-block p-l-16 p-r-16\"\n >\n </c8y-device-software-list>\n </ng-container>\n </fieldset>\n </div>\n <!-- INSTALL SOFTWARE-->\n <div *ngIf=\"supportsSoftwareOperations\" class=\"card-footer large-padding separator sticky-bottom\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Install software' | translate }}\"\n (click)=\"installSoftware()\"\n [disabled]=\"deviceSoftwareChangesInProgress\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install software' | translate }}\n </button>\n </div>\n</div>\n"
2739
2753
  },] }
2740
2754
  ];
2741
2755
  InstalledSoftwareComponent.ctorParameters = () => [
@@ -2744,6 +2758,7 @@ InstalledSoftwareComponent.ctorParameters = () => [
2744
2758
  { type: BsModalService }
2745
2759
  ];
2746
2760
  InstalledSoftwareComponent.propDecorators = {
2761
+ device: [{ type: Input }],
2747
2762
  softwareList: [{ type: Input }],
2748
2763
  deviceSoftwareChanges: [{ type: Input }],
2749
2764
  deviceSoftwareChangesOperation: [{ type: Input }],
@@ -2756,6 +2771,12 @@ class DeviceSoftwareListComponent {
2756
2771
  constructor() {
2757
2772
  this.update = new EventEmitter();
2758
2773
  this.remove = new EventEmitter();
2774
+ this.supportsSoftwareOperations = false;
2775
+ this.operationTypes = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
2776
+ }
2777
+ ngOnInit() {
2778
+ const supportedOperations = get(this.device, 'c8y_SupportedOperations', []);
2779
+ this.supportsSoftwareOperations = this.operationTypes.some(operationType => supportedOperations.indexOf(operationType) > -1);
2759
2780
  }
2760
2781
  ngAfterContentInit() {
2761
2782
  this.showUpdate = this.update.observers.length > 0;
@@ -2769,11 +2790,12 @@ class DeviceSoftwareListComponent {
2769
2790
  DeviceSoftwareListComponent.decorators = [
2770
2791
  { type: Component, args: [{
2771
2792
  selector: 'c8y-device-software-list',
2772
- template: "<c8y-list-group class=\"no-border-last\">\n <c8y-li\n [ngClass]=\"{ disabled: isSoftwareGoingToBeChanged(software) }\"\n *ngFor=\"let software of softwareList\"\n >\n <!-- SOFTWARE ICON -->\n <c8y-li-icon>\n <i c8yIcon=\"c8y-tools\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-20\">\n <div title=\"{{ software.name }}\" class=\"col-8\">\n <!-- SOFTWARE NAME -->\n <p class=\"text-truncate\">{{ software.name }}</p>\n <!-- SOFTWARE VERSION -->\n <p class=\"text-truncate\">\n <span class=\"text-label-small m-r-4\" translate>\n Version\n </span>\n <span title=\"{{ software.version }}\">\n {{ software.version }}\n </span>\n </p>\n </div>\n\n <div *ngIf=\"showUpdate || showRemove\" class=\"col-4 text-right\">\n <!-- UPDATE SOFTWARE -->\n <button\n *ngIf=\"showUpdate && !isSoftwareGoingToBeChanged(software)\"\n class=\"btn btn-default btn-xs showOnHover\"\n (click)=\"update.emit(software)\"\n title=\"{{ 'Update`software,verb`' | translate }}\"\n translate\n >\n Update\n </button>\n\n <!-- REMOVE SOFTWARE -->\n <button\n *ngIf=\"showRemove && !isSoftwareGoingToBeChanged(software)\"\n title=\"{{ 'Remove`software`' | translate }}\"\n class=\"showOnHover btn btn-dot pull-right\"\n (click)=\"remove.emit(software)\"\n >\n <i c8yIcon=\"minus-circle\" class=\"text-danger\"></i>\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n</c8y-list-group>\n"
2793
+ template: "<c8y-list-group class=\"no-border-last\">\n <c8y-li\n [ngClass]=\"{ disabled: isSoftwareGoingToBeChanged(software) }\"\n *ngFor=\"let software of softwareList\"\n >\n <!-- SOFTWARE ICON -->\n <c8y-li-icon>\n <i c8yIcon=\"c8y-tools\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-20\">\n <div title=\"{{ software.name }}\" class=\"col-8\">\n <!-- SOFTWARE NAME -->\n <p class=\"text-truncate\">{{ software.name }}</p>\n <!-- SOFTWARE VERSION -->\n <p class=\"text-truncate\">\n <span class=\"text-label-small m-r-4\" translate>\n Version\n </span>\n <span title=\"{{ software.version }}\">\n {{ software.version }}\n </span>\n </p>\n </div>\n\n <div\n *ngIf=\"supportsSoftwareOperations && (showUpdate || showRemove)\"\n class=\"col-4 text-right\"\n >\n <!-- UPDATE SOFTWARE -->\n <button\n *ngIf=\"showUpdate && !isSoftwareGoingToBeChanged(software)\"\n class=\"btn btn-default btn-xs showOnHover\"\n (click)=\"update.emit(software)\"\n title=\"{{ 'Update`software,verb`' | translate }}\"\n translate\n >\n Update\n </button>\n\n <!-- REMOVE SOFTWARE -->\n <button\n *ngIf=\"showRemove && !isSoftwareGoingToBeChanged(software)\"\n title=\"{{ 'Remove`software`' | translate }}\"\n class=\"showOnHover btn btn-dot pull-right\"\n (click)=\"remove.emit(software)\"\n >\n <i c8yIcon=\"minus-circle\" class=\"text-danger\"></i>\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n</c8y-list-group>\n"
2773
2794
  },] }
2774
2795
  ];
2775
2796
  DeviceSoftwareListComponent.propDecorators = {
2776
2797
  softwareList: [{ type: Input }],
2798
+ device: [{ type: Input }],
2777
2799
  deviceSoftwareChanges: [{ type: Input }],
2778
2800
  update: [{ type: Output }],
2779
2801
  remove: [{ type: Output }]
@@ -2992,7 +3014,11 @@ class DeviceConfigurationComponent {
2992
3014
  title: gettext('No configurations available.'),
2993
3015
  text: gettext('Add configuration to configuration repository')
2994
3016
  };
2995
- this.showTextBasedConfig = this.deviceConfigurationService.hasAnySupportedOperation(this.device, [DeviceConfigurationOperation.CONFIG, DeviceConfigurationOperation.SEND_CONFIG]);
3017
+ this.showTextBasedConfig =
3018
+ this.deviceConfigurationService.hasAnySupportedOperation(this.device, [
3019
+ DeviceConfigurationOperation.CONFIG,
3020
+ DeviceConfigurationOperation.SEND_CONFIG
3021
+ ]) || has(this.device, 'c8y_Configuration');
2996
3022
  }
2997
3023
  onConfigTypeSelected(config) {
2998
3024
  return __awaiter(this, void 0, void 0, function* () {
@@ -3334,7 +3360,8 @@ class DeviceConfigurationGuard {
3334
3360
  DeviceConfigurationOperation.UPLOAD_CONFIG,
3335
3361
  DeviceConfigurationOperation.CONFIG,
3336
3362
  DeviceConfigurationOperation.SEND_CONFIG
3337
- ]));
3363
+ ]) ||
3364
+ has(contextData, 'c8y_Configuration'));
3338
3365
  }
3339
3366
  }
3340
3367
  DeviceConfigurationGuard.decorators = [