@c8y/ngx-components 1024.18.1 → 1024.18.9

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 (87) hide show
  1. package/fesm2022/c8y-ngx-components-actility-device-registration.mjs +1 -1
  2. package/fesm2022/c8y-ngx-components-actility-device-registration.mjs.map +1 -1
  3. package/fesm2022/c8y-ngx-components-asset-properties.mjs +67 -20
  4. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-assets-navigator.mjs +75 -13
  6. package/fesm2022/c8y-ngx-components-assets-navigator.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs +2 -4
  8. package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs +6 -8
  10. package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +98 -19
  12. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-dashboard-manager.mjs +4 -4
  14. package/fesm2022/c8y-ngx-components-dashboard-manager.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +7 -7
  16. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +5 -3
  18. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-echart-models.mjs.map +1 -1
  20. package/fesm2022/c8y-ngx-components-echart.mjs +52 -7
  21. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  22. package/fesm2022/c8y-ngx-components-ecosystem.mjs +1 -1
  23. package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
  24. package/fesm2022/c8y-ngx-components-file-preview.mjs +2 -2
  25. package/fesm2022/c8y-ngx-components-file-preview.mjs.map +1 -1
  26. package/fesm2022/c8y-ngx-components-icon-selector.mjs +6 -6
  27. package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
  28. package/fesm2022/c8y-ngx-components-loriot-device-registration.mjs +1 -1
  29. package/fesm2022/c8y-ngx-components-loriot-device-registration.mjs.map +1 -1
  30. package/fesm2022/c8y-ngx-components-operation-picker.mjs +2 -2
  31. package/fesm2022/c8y-ngx-components-operation-picker.mjs.map +1 -1
  32. package/fesm2022/c8y-ngx-components-register-device.mjs +4 -4
  33. package/fesm2022/c8y-ngx-components-register-device.mjs.map +1 -1
  34. package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs +2 -3
  35. package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs.map +1 -1
  36. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs +2 -2
  37. package/fesm2022/c8y-ngx-components-remote-access-shared.mjs.map +1 -1
  38. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +2 -2
  39. package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -1
  40. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +2 -4
  41. package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs.map +1 -1
  42. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +2 -3
  43. package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map +1 -1
  44. package/fesm2022/c8y-ngx-components-sigfox-device-registration.mjs +1 -1
  45. package/fesm2022/c8y-ngx-components-sigfox-device-registration.mjs.map +1 -1
  46. package/fesm2022/c8y-ngx-components-static-assets-modal.mjs +2 -2
  47. package/fesm2022/c8y-ngx-components-static-assets-modal.mjs.map +1 -1
  48. package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs +3 -4
  49. package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs.map +1 -1
  50. package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs +10 -1
  51. package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs.map +1 -1
  52. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +4 -4
  53. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
  54. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +18 -3
  55. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  56. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
  57. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
  58. package/fesm2022/c8y-ngx-components.mjs +59 -19
  59. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  60. package/locales/de.po +3 -2
  61. package/locales/es.po +3 -3
  62. package/locales/fr.po +3 -3
  63. package/locales/ja_JP.po +2 -2
  64. package/locales/ko.po +3 -3
  65. package/locales/locales.pot +1 -1
  66. package/locales/nl.po +3 -3
  67. package/locales/pl.po +2 -3
  68. package/locales/pt_BR.po +2 -3
  69. package/locales/zh_CN.po +2 -2
  70. package/locales/zh_TW.po +3 -3
  71. package/package.json +1 -1
  72. package/types/c8y-ngx-components-asset-properties.d.ts +9 -1
  73. package/types/c8y-ngx-components-asset-properties.d.ts.map +1 -1
  74. package/types/c8y-ngx-components-assets-navigator.d.ts +30 -3
  75. package/types/c8y-ngx-components-assets-navigator.d.ts.map +1 -1
  76. package/types/c8y-ngx-components-branding-shared-lazy-add-branding-modal.d.ts.map +1 -1
  77. package/types/c8y-ngx-components-context-dashboard.d.ts +44 -1
  78. package/types/c8y-ngx-components-context-dashboard.d.ts.map +1 -1
  79. package/types/c8y-ngx-components-echart-models.d.ts +9 -0
  80. package/types/c8y-ngx-components-echart-models.d.ts.map +1 -1
  81. package/types/c8y-ngx-components-echart.d.ts +32 -5
  82. package/types/c8y-ngx-components-echart.d.ts.map +1 -1
  83. package/types/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.d.ts.map +1 -1
  84. package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts +6 -0
  85. package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts.map +1 -1
  86. package/types/c8y-ngx-components.d.ts +50 -2
  87. package/types/c8y-ngx-components.d.ts.map +1 -1
@@ -18,6 +18,7 @@ import { isArray, isNumber, isString, isObject } from 'lodash';
18
18
  import { NgIf, NgStyle, NgClass, NgFor, AsyncPipe } from '@angular/common';
19
19
  import * as i4 from '@angular/forms';
20
20
  import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
21
+ import * as i4$1 from '@angular/cdk/a11y';
21
22
 
22
23
  var AssetsNavigatorAction;
23
24
  (function (AssetsNavigatorAction) {
@@ -1381,6 +1382,14 @@ class UnassignedDevicesNode extends GroupNode {
1381
1382
  * Displays a hierarchical tree selector for assets.
1382
1383
  */
1383
1384
  class AssetSelectorComponent extends AssetSelectorBase {
1385
+ /**
1386
+ * True when this column sits behind another one in a single column miller view, which scrolls it
1387
+ * out of sight. Such a column is marked `inert` so that it leaves the tab order and the
1388
+ * accessibility tree, instead of collecting invisible tab stops.
1389
+ */
1390
+ get isScrolledOutOfView() {
1391
+ return this.config.view === 'miller' && this.config.singleColumn && !!this.active;
1392
+ }
1384
1393
  /**
1385
1394
  * @ignore only DI
1386
1395
  */
@@ -1699,7 +1708,7 @@ class AssetSelectorComponent extends AssetSelectorBase {
1699
1708
  return false;
1700
1709
  }
1701
1710
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AssetSelectorComponent, deps: [{ token: GroupNodeService }, { token: i2.InventoryService }, { token: AssetSelectorService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1702
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: AssetSelectorComponent, isStandalone: true, selector: "c8y-asset-selector", inputs: { config: "config", active: "active", index: "index", asset: "asset", selectedDevice: "selectedDevice", selected: "selected", rootNode: "rootNode", selectedItems: "selectedItems", container: "container", isNodeSelectable: "isNodeSelectable", disabled: "disabled" }, outputs: { onSelected: "onSelected", onClearSelected: "onClearSelected", onRowSelected: "onRowSelected", onLoad: "onLoad" }, providers: [
1711
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: AssetSelectorComponent, isStandalone: true, selector: "c8y-asset-selector", inputs: { config: "config", active: "active", index: "index", asset: "asset", selectedDevice: "selectedDevice", selected: "selected", rootNode: "rootNode", selectedItems: "selectedItems", container: "container", isNodeSelectable: "isNodeSelectable", disabled: "disabled" }, outputs: { onSelected: "onSelected", onClearSelected: "onClearSelected", onRowSelected: "onRowSelected", onLoad: "onLoad" }, providers: [
1703
1712
  {
1704
1713
  provide: NG_VALUE_ACCESSOR,
1705
1714
  multi: true,
@@ -1711,7 +1720,7 @@ class AssetSelectorComponent extends AssetSelectorBase {
1711
1720
  multi: true
1712
1721
  },
1713
1722
  AssetSelectorService
1714
- ], viewQueries: [{ propertyName: "header", first: true, predicate: ["header"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"bg-inherit p-t-8 p-b-8 separator-bottom p-r-16 p-l-16 sticky-top\"\n [ngStyle]=\"{ 'z-index': config.singleColumn && config.search ? '30' : '20' }\"\n #header\n [ngClass]=\"{\n 'p-absolute miller-column__selection d-flex flex-wrap a-i-center': config.view === 'miller',\n 'miller-column__search': config.search,\n 'miller-column__show-selected': config.showSelected\n }\"\n *ngIf=\"\n !selectedDevice &&\n index === 0 &&\n (config.search || config.multi || config.label?.length || config.showSelected)\n \"\n>\n <p\n class=\"text-medium flex-no-shrink a-s-center\"\n [ngClass]=\"{\n 'm-b-4': config.search && root && config.singleColumn,\n 'm-r-8': !config.singleColumn && !config.search,\n 'fit-w': config.singleColumn\n }\"\n *ngIf=\"config.label?.length\"\n >\n {{ config.label | translate }}\n </p>\n <c8y-search-input\n [ngStyle]=\"{ 'min-width': !config.singleColumn && config.label.length ? '50%' : 'inherit' }\"\n *ngIf=\"config.search && root\"\n (onClick)=\"onSearchResultClick($event)\"\n (reset)=\"onSearchResultReset($event)\"\n [mode]=\"'select'\"\n [container]=\"container\"\n class=\"input-group-sm\"\n [groupsOnly]=\"config.groupsOnly\"\n [ngClass]=\"{\n 'm-l-auto': !config.singleColumn && config.label.length,\n 'fit-w': config.singleColumn || !config.label.length\n }\"\n ></c8y-search-input>\n <div\n class=\"bg-inherit d-flex gap-4 fit-w\"\n *ngIf=\"config.showSelected\"\n [ngClass]=\"{ 'm-t-4': config.search }\"\n >\n <span class=\"text-label-small m-r-4 a-s-center l-h-1\">{{ 'Selected' | translate }}</span>\n <div class=\"flex-grow inner-scroll d-flex gap-4 a-i-center\">\n <ng-container *ngIf=\"!selected.length\">\n <em class=\"text-12 text-muted d-flex a-i-center fit-h-20\">{{ 'None' | translate }}</em>\n </ng-container>\n <span\n class=\"tag tag--info chip flex-no-shrink\"\n *ngFor=\"let selectedItem of selected\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ selectedItem.name }}\"\n [disabled]=\"disabled\"\n type=\"button\"\n (click)=\"config.multi ? deselect(selectedItem) : deselectAll()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n {{ selectedItem.name || (ASSET_CONST | translate: { assetId: selectedItem.id }) }}\n </span>\n </div>\n </div>\n</div>\n\n<div\n class=\"p-r-16\"\n *ngIf=\"selectedDevice\"\n>\n <div class=\"d-flex p-b-4\">\n <p\n class=\"text-medium p-t-8 m-r-8\"\n *ngIf=\"selectedDevice; else multiAssets\"\n >\n {{ 'Selected asset' | translate }}\n </p>\n <ng-template #multiAssets>\n <p class=\"text-medium m-r-8\">{{ 'Selected assets' | translate }}</p>\n </ng-template>\n <button\n class=\"btn btn-default btn-xs a-s-center m-t-4 m-l-auto\"\n title=\"{{ 'Change' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); clearSelectedDevices()\"\n >\n {{ 'Change' | translate }}\n </button>\n </div>\n <div class=\"d-flex\">\n <i\n class=\"text-success p-l-0 p-r-8\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <i\n class=\"m-r-4 icon-20\"\n [c8yIcon]=\"selectedDevice | getGroupIcon | async\"\n ></i>\n <span>{{ selectedDevice.name }}</span>\n </div>\n</div>\n\n<!-- miller columns header -->\n<div\n class=\"miller-column__header sticky-top bg-inherit separator-bottom\"\n *ngIf=\"\n config.view === 'miller' &&\n ((config.showFilter && !rootNode.root) || config.columnHeaders) &&\n !selectedDevice\n \"\n [ngClass]=\"{ 'p-t-8': config.search }\"\n>\n <div class=\"d-flex\" *ngIf=\"config.singleColumn && index !== 0\">\n <i\n class=\"m-r-4\"\n c8yIcon=\"home\"\n ></i>\n <p\n class=\"text-12 text-muted text-truncate text-rtl m-b-4\"\n title=\"{{ rootNode.breadcrumb || rootNode.label | translate }}\"\n >\n {{ rootNode.breadcrumb || rootNode.label | translate }}\n </p>\n </div>\n <div\n class=\"d-flex a-i-center\"\n *ngIf=\"config.columnHeaders || config.singleColumn\"\n >\n <button\n class=\"btn btn-default btn-xs m-r-8 p-t-0 p-b-0 p-l-4 p-r-4 l-h-1\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"config.singleColumn && !rootNode.root && index !== 0\"\n (click)=\"$event.stopPropagation(); back()\"\n >\n <i c8yIcon=\"angle-left\"></i>\n </button>\n <label\n class=\"c8y-radio checkbox-inline m-r-8\"\n *ngIf=\"!rootNode.root && index === 0 && (config.groupsSelectable || !rootNode.isGroup())\"\n >\n <input\n title=\"{{ 'Select group' | translate }}\"\n type=\"radio\"\n (change)=\"select(rootNode.mo)\"\n [checked]=\"isGroupSelected()\"\n />\n <span></span>\n </label>\n\n <i\n class=\"icon-20 c8y-icon-duocolor m-r-4\"\n [c8yIcon]=\"this.rootNode.mo | getGroupIcon: true : this.rootNode.icon | async\"\n *ngIf=\"config.columnHeaders && (config.singleColumn || (!rootNode.root && index === 0))\"\n ></i>\n <p\n class=\"text-truncate\"\n title=\"{{ rootNode.label | translate }}\"\n *ngIf=\"config.columnHeaders\"\n [ngClass]=\"{\n 'text-label-small': !config.singleColumn,\n 'text-medium': config.singleColumn\n }\"\n >\n {{ rootNode.label | translate }}\n </p>\n </div>\n\n <div\n *ngIf=\"!rootNode.root && config.showFilter\"\n [ngClass]=\"{ 'p-t-4': config.columnHeaders }\"\n >\n <div class=\"input-group input-group-sm input-group-search\">\n <input\n class=\"form-control text-truncate\"\n placeholder=\"{{ 'Filter this column\u2026' | translate }}\"\n [(ngModel)]=\"filterText\"\n (keyup.enter)=\"applyFilter('*' + filterText + '*')\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot p-l-4\"\n title=\"{{ 'Apply filter' | translate }}\"\n type=\"button\"\n (click)=\"applyFilter('*' + filterText + '*')\"\n >\n <i c8yIcon=\"filter\"></i>\n </button>\n <button\n class=\"btn btn-dot p-l-4\"\n title=\" {{ 'Clear filters' | translate }}\"\n type=\"button\"\n (click)=\"clearFilters()\"\n *ngIf=\"filterText.length\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </span>\n </div>\n </div>\n</div>\n\n<c8y-asset-selector-node\n class=\"d-block bg-inherit p-relative\"\n style=\"z-index: 9\"\n *ngIf=\"rootNode && !selectedDevice\"\n [node]=\"rootNode\"\n [rootNode]=\"rootNode\"\n [preselected]=\"selected\"\n [multi]=\"config.multi\"\n [view]=\"config.view\"\n [index]=\"index\"\n [active]=\"active\"\n [disabled]=\"disabled\"\n [handleNextMillerViewColumn]=\"handleNextMillerViewColumn.bind(this)\"\n (isLoadingState)=\"onLoading($event)\"\n (onSelect)=\"onSelect($event)\"\n (onDeselect)=\"onDeselect($event)\"\n [ngClass]=\"{ 'collapse show': !rootNode.root && !rootNode.hidden && config.view !== 'miller' }\"\n></c8y-asset-selector-node>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SearchInputComponent, selector: "c8y-search-input", inputs: ["mode", "enableCustomTemplatePlaceholder", "customPlaceholder", "externalTerm", "customDataQuery", "container", "groupsOnly"], outputs: ["filter", "search", "reset", "onClick", "onOpenToggle"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AssetSelectorNodeComponent, selector: "c8y-asset-selector-node", inputs: ["node", "rootNode", "preselected", "showPath", "multi", "view", "index", "active", "handleNextMillerViewColumn", "disabled"], outputs: ["isLoadingState", "onSelect", "onDeselect"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: GetGroupIconPipe, name: "getGroupIcon" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1723
+ ], viewQueries: [{ propertyName: "header", first: true, predicate: ["header"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (\n !selectedDevice &&\n index === 0 &&\n (config.search || config.multi || config.label?.length || config.showSelected)\n) {\n <div\n class=\"bg-inherit p-t-8 p-b-8 separator-bottom p-r-16 p-l-16 sticky-top\"\n [ngStyle]=\"{ 'z-index': config.singleColumn && config.search ? '30' : '20' }\"\n #header\n [ngClass]=\"{\n 'p-absolute miller-column__selection d-flex flex-wrap a-i-center': config.view === 'miller',\n 'miller-column__search': config.search,\n 'miller-column__show-selected': config.showSelected\n }\"\n >\n @if (config.label?.length) {\n <p\n class=\"text-medium flex-no-shrink a-s-center\"\n [ngClass]=\"{\n 'm-b-4': config.search && root && config.singleColumn,\n 'm-r-8': !config.singleColumn && !config.search,\n 'fit-w': config.singleColumn\n }\"\n >\n {{ config.label | translate }}\n </p>\n }\n @if (config.search && root) {\n <c8y-search-input\n class=\"input-group-sm\"\n [ngStyle]=\"{ 'min-width': !config.singleColumn && config.label.length ? '50%' : 'inherit' }\"\n (onClick)=\"onSearchResultClick($event)\"\n (reset)=\"onSearchResultReset($event)\"\n [mode]=\"'select'\"\n [container]=\"container\"\n [groupsOnly]=\"config.groupsOnly\"\n [ngClass]=\"{\n 'm-l-auto': !config.singleColumn && config.label.length,\n 'fit-w': config.singleColumn || !config.label.length\n }\"\n ></c8y-search-input>\n }\n @if (config.showSelected) {\n <div\n class=\"bg-inherit d-flex gap-4 fit-w\"\n [ngClass]=\"{ 'm-t-4': config.search }\"\n >\n <span class=\"text-label-small m-r-4 a-s-center l-h-1\">{{ 'Selected' | translate }}</span>\n <div class=\"flex-grow inner-scroll d-flex gap-4 a-i-center\">\n @if (!selected.length) {\n <em class=\"text-12 text-muted d-flex a-i-center fit-h-20\">{{ 'None' | translate }}</em>\n }\n @for (selectedItem of selected; track selectedItem) {\n <span class=\"tag tag--info chip flex-no-shrink\">\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ selectedItem.name }}\"\n type=\"button\"\n [disabled]=\"disabled\"\n (click)=\"config.multi ? deselect(selectedItem) : deselectAll()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n {{ selectedItem.name || (ASSET_CONST | translate: { assetId: selectedItem.id }) }}\n </span>\n }\n </div>\n </div>\n }\n </div>\n}\n\n@if (selectedDevice) {\n <div class=\"p-r-16\">\n <div class=\"d-flex p-b-4\">\n @if (selectedDevice) {\n <p class=\"text-medium p-t-8 m-r-8\">\n {{ 'Selected asset' | translate }}\n </p>\n } @else {\n <p class=\"text-medium m-r-8\">{{ 'Selected assets' | translate }}</p>\n }\n <button\n class=\"btn btn-default btn-xs a-s-center m-t-4 m-l-auto\"\n title=\"{{ 'Change' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); clearSelectedDevices()\"\n >\n {{ 'Change' | translate }}\n </button>\n </div>\n <div class=\"d-flex\">\n <i\n class=\"text-success p-l-0 p-r-8\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <i\n class=\"m-r-4 icon-20\"\n [c8yIcon]=\"selectedDevice | getGroupIcon | async\"\n ></i>\n <span>{{ selectedDevice.name }}</span>\n </div>\n </div>\n}\n\n<!-- miller columns header -->\n@if (\n config.view === 'miller' &&\n ((config.showFilter && !rootNode.root) || config.columnHeaders) &&\n !selectedDevice\n) {\n <div\n class=\"miller-column__header sticky-top bg-inherit separator-bottom\"\n [attr.inert]=\"isScrolledOutOfView ? '' : null\"\n [ngClass]=\"{ 'p-t-8': config.search }\"\n >\n @if (config.singleColumn && index !== 0) {\n <div class=\"d-flex\">\n <i\n class=\"m-r-4\"\n c8yIcon=\"home\"\n ></i>\n <p\n class=\"text-12 text-muted text-truncate text-rtl m-b-4\"\n title=\"{{ rootNode.breadcrumb || rootNode.label | translate }}\"\n >\n {{ rootNode.breadcrumb || rootNode.label | translate }}\n </p>\n </div>\n }\n @if (config.columnHeaders || config.singleColumn) {\n <div class=\"d-flex a-i-center\">\n @if (config.singleColumn && !rootNode.root && index !== 0) {\n <button\n class=\"btn btn-default btn-xs m-r-8 p-t-0 p-b-0 p-l-4 p-r-4 l-h-1\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); back()\"\n >\n <i c8yIcon=\"angle-left\"></i>\n </button>\n }\n @if (!rootNode.root && index === 0 && (config.groupsSelectable || !rootNode.isGroup())) {\n <label class=\"c8y-radio checkbox-inline m-r-8\">\n <input\n title=\"{{ 'Select group' | translate }}\"\n type=\"radio\"\n (change)=\"select(rootNode.mo)\"\n [checked]=\"isGroupSelected()\"\n />\n <span></span>\n </label>\n }\n\n @if (config.columnHeaders && (config.singleColumn || (!rootNode.root && index === 0))) {\n <i\n class=\"icon-20 c8y-icon-duocolor m-r-4\"\n [c8yIcon]=\"this.rootNode.mo | getGroupIcon: true : this.rootNode.icon | async\"\n ></i>\n }\n @if (config.columnHeaders) {\n <p\n class=\"text-truncate\"\n title=\"{{ rootNode.label | translate }}\"\n [ngClass]=\"{\n 'text-label-small': !config.singleColumn,\n 'text-medium': config.singleColumn\n }\"\n >\n {{ rootNode.label | translate }}\n </p>\n }\n </div>\n }\n\n @if (!rootNode.root && config.showFilter) {\n <div [ngClass]=\"{ 'p-t-4': config.columnHeaders }\">\n <div class=\"input-group input-group-sm input-group-search\">\n <input\n class=\"form-control text-truncate\"\n placeholder=\"{{ 'Filter this column\u2026' | translate }}\"\n [(ngModel)]=\"filterText\"\n (keyup.enter)=\"applyFilter('*' + filterText + '*')\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot p-l-4\"\n title=\"{{ 'Apply filter' | translate }}\"\n type=\"button\"\n (click)=\"applyFilter('*' + filterText + '*')\"\n >\n <i c8yIcon=\"filter\"></i>\n </button>\n @if (filterText.length) {\n <button\n class=\"btn btn-dot p-l-4\"\n title=\" {{ 'Clear filters' | translate }}\"\n type=\"button\"\n (click)=\"clearFilters()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n }\n </span>\n </div>\n </div>\n }\n </div>\n}\n\n@if (rootNode && !selectedDevice) {\n <c8y-asset-selector-node\n class=\"d-block bg-inherit p-relative\"\n style=\"z-index: 9\"\n [attr.inert]=\"isScrolledOutOfView ? '' : null\"\n [node]=\"rootNode\"\n [rootNode]=\"rootNode\"\n [preselected]=\"selected\"\n [multi]=\"config.multi\"\n [view]=\"config.view\"\n [index]=\"index\"\n [active]=\"active\"\n [disabled]=\"disabled\"\n [handleNextMillerViewColumn]=\"handleNextMillerViewColumn.bind(this)\"\n (isLoadingState)=\"onLoading($event)\"\n (onSelect)=\"onSelect($event)\"\n (onDeselect)=\"onDeselect($event)\"\n [ngClass]=\"{ 'collapse show': !rootNode.root && !rootNode.hidden && config.view !== 'miller' }\"\n ></c8y-asset-selector-node>\n}\n", dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SearchInputComponent, selector: "c8y-search-input", inputs: ["mode", "enableCustomTemplatePlaceholder", "customPlaceholder", "externalTerm", "customDataQuery", "container", "groupsOnly"], outputs: ["filter", "search", "reset", "onClick", "onOpenToggle"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AssetSelectorNodeComponent, selector: "c8y-asset-selector-node", inputs: ["node", "rootNode", "preselected", "showPath", "multi", "view", "index", "active", "handleNextMillerViewColumn", "disabled"], outputs: ["isLoadingState", "onSelect", "onDeselect"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: GetGroupIconPipe, name: "getGroupIcon" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1715
1724
  }
1716
1725
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AssetSelectorComponent, decorators: [{
1717
1726
  type: Component,
@@ -1728,18 +1737,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1728
1737
  },
1729
1738
  AssetSelectorService
1730
1739
  ], imports: [
1731
- NgIf,
1732
1740
  NgStyle,
1733
1741
  NgClass,
1734
1742
  SearchInputComponent,
1735
- NgFor,
1736
1743
  IconDirective,
1737
1744
  FormsModule,
1738
1745
  AssetSelectorNodeComponent,
1739
1746
  C8yTranslatePipe,
1740
1747
  AsyncPipe,
1741
1748
  GetGroupIconPipe
1742
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div\n class=\"bg-inherit p-t-8 p-b-8 separator-bottom p-r-16 p-l-16 sticky-top\"\n [ngStyle]=\"{ 'z-index': config.singleColumn && config.search ? '30' : '20' }\"\n #header\n [ngClass]=\"{\n 'p-absolute miller-column__selection d-flex flex-wrap a-i-center': config.view === 'miller',\n 'miller-column__search': config.search,\n 'miller-column__show-selected': config.showSelected\n }\"\n *ngIf=\"\n !selectedDevice &&\n index === 0 &&\n (config.search || config.multi || config.label?.length || config.showSelected)\n \"\n>\n <p\n class=\"text-medium flex-no-shrink a-s-center\"\n [ngClass]=\"{\n 'm-b-4': config.search && root && config.singleColumn,\n 'm-r-8': !config.singleColumn && !config.search,\n 'fit-w': config.singleColumn\n }\"\n *ngIf=\"config.label?.length\"\n >\n {{ config.label | translate }}\n </p>\n <c8y-search-input\n [ngStyle]=\"{ 'min-width': !config.singleColumn && config.label.length ? '50%' : 'inherit' }\"\n *ngIf=\"config.search && root\"\n (onClick)=\"onSearchResultClick($event)\"\n (reset)=\"onSearchResultReset($event)\"\n [mode]=\"'select'\"\n [container]=\"container\"\n class=\"input-group-sm\"\n [groupsOnly]=\"config.groupsOnly\"\n [ngClass]=\"{\n 'm-l-auto': !config.singleColumn && config.label.length,\n 'fit-w': config.singleColumn || !config.label.length\n }\"\n ></c8y-search-input>\n <div\n class=\"bg-inherit d-flex gap-4 fit-w\"\n *ngIf=\"config.showSelected\"\n [ngClass]=\"{ 'm-t-4': config.search }\"\n >\n <span class=\"text-label-small m-r-4 a-s-center l-h-1\">{{ 'Selected' | translate }}</span>\n <div class=\"flex-grow inner-scroll d-flex gap-4 a-i-center\">\n <ng-container *ngIf=\"!selected.length\">\n <em class=\"text-12 text-muted d-flex a-i-center fit-h-20\">{{ 'None' | translate }}</em>\n </ng-container>\n <span\n class=\"tag tag--info chip flex-no-shrink\"\n *ngFor=\"let selectedItem of selected\"\n >\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ selectedItem.name }}\"\n [disabled]=\"disabled\"\n type=\"button\"\n (click)=\"config.multi ? deselect(selectedItem) : deselectAll()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n {{ selectedItem.name || (ASSET_CONST | translate: { assetId: selectedItem.id }) }}\n </span>\n </div>\n </div>\n</div>\n\n<div\n class=\"p-r-16\"\n *ngIf=\"selectedDevice\"\n>\n <div class=\"d-flex p-b-4\">\n <p\n class=\"text-medium p-t-8 m-r-8\"\n *ngIf=\"selectedDevice; else multiAssets\"\n >\n {{ 'Selected asset' | translate }}\n </p>\n <ng-template #multiAssets>\n <p class=\"text-medium m-r-8\">{{ 'Selected assets' | translate }}</p>\n </ng-template>\n <button\n class=\"btn btn-default btn-xs a-s-center m-t-4 m-l-auto\"\n title=\"{{ 'Change' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); clearSelectedDevices()\"\n >\n {{ 'Change' | translate }}\n </button>\n </div>\n <div class=\"d-flex\">\n <i\n class=\"text-success p-l-0 p-r-8\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <i\n class=\"m-r-4 icon-20\"\n [c8yIcon]=\"selectedDevice | getGroupIcon | async\"\n ></i>\n <span>{{ selectedDevice.name }}</span>\n </div>\n</div>\n\n<!-- miller columns header -->\n<div\n class=\"miller-column__header sticky-top bg-inherit separator-bottom\"\n *ngIf=\"\n config.view === 'miller' &&\n ((config.showFilter && !rootNode.root) || config.columnHeaders) &&\n !selectedDevice\n \"\n [ngClass]=\"{ 'p-t-8': config.search }\"\n>\n <div class=\"d-flex\" *ngIf=\"config.singleColumn && index !== 0\">\n <i\n class=\"m-r-4\"\n c8yIcon=\"home\"\n ></i>\n <p\n class=\"text-12 text-muted text-truncate text-rtl m-b-4\"\n title=\"{{ rootNode.breadcrumb || rootNode.label | translate }}\"\n >\n {{ rootNode.breadcrumb || rootNode.label | translate }}\n </p>\n </div>\n <div\n class=\"d-flex a-i-center\"\n *ngIf=\"config.columnHeaders || config.singleColumn\"\n >\n <button\n class=\"btn btn-default btn-xs m-r-8 p-t-0 p-b-0 p-l-4 p-r-4 l-h-1\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"config.singleColumn && !rootNode.root && index !== 0\"\n (click)=\"$event.stopPropagation(); back()\"\n >\n <i c8yIcon=\"angle-left\"></i>\n </button>\n <label\n class=\"c8y-radio checkbox-inline m-r-8\"\n *ngIf=\"!rootNode.root && index === 0 && (config.groupsSelectable || !rootNode.isGroup())\"\n >\n <input\n title=\"{{ 'Select group' | translate }}\"\n type=\"radio\"\n (change)=\"select(rootNode.mo)\"\n [checked]=\"isGroupSelected()\"\n />\n <span></span>\n </label>\n\n <i\n class=\"icon-20 c8y-icon-duocolor m-r-4\"\n [c8yIcon]=\"this.rootNode.mo | getGroupIcon: true : this.rootNode.icon | async\"\n *ngIf=\"config.columnHeaders && (config.singleColumn || (!rootNode.root && index === 0))\"\n ></i>\n <p\n class=\"text-truncate\"\n title=\"{{ rootNode.label | translate }}\"\n *ngIf=\"config.columnHeaders\"\n [ngClass]=\"{\n 'text-label-small': !config.singleColumn,\n 'text-medium': config.singleColumn\n }\"\n >\n {{ rootNode.label | translate }}\n </p>\n </div>\n\n <div\n *ngIf=\"!rootNode.root && config.showFilter\"\n [ngClass]=\"{ 'p-t-4': config.columnHeaders }\"\n >\n <div class=\"input-group input-group-sm input-group-search\">\n <input\n class=\"form-control text-truncate\"\n placeholder=\"{{ 'Filter this column\u2026' | translate }}\"\n [(ngModel)]=\"filterText\"\n (keyup.enter)=\"applyFilter('*' + filterText + '*')\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot p-l-4\"\n title=\"{{ 'Apply filter' | translate }}\"\n type=\"button\"\n (click)=\"applyFilter('*' + filterText + '*')\"\n >\n <i c8yIcon=\"filter\"></i>\n </button>\n <button\n class=\"btn btn-dot p-l-4\"\n title=\" {{ 'Clear filters' | translate }}\"\n type=\"button\"\n (click)=\"clearFilters()\"\n *ngIf=\"filterText.length\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n </span>\n </div>\n </div>\n</div>\n\n<c8y-asset-selector-node\n class=\"d-block bg-inherit p-relative\"\n style=\"z-index: 9\"\n *ngIf=\"rootNode && !selectedDevice\"\n [node]=\"rootNode\"\n [rootNode]=\"rootNode\"\n [preselected]=\"selected\"\n [multi]=\"config.multi\"\n [view]=\"config.view\"\n [index]=\"index\"\n [active]=\"active\"\n [disabled]=\"disabled\"\n [handleNextMillerViewColumn]=\"handleNextMillerViewColumn.bind(this)\"\n (isLoadingState)=\"onLoading($event)\"\n (onSelect)=\"onSelect($event)\"\n (onDeselect)=\"onDeselect($event)\"\n [ngClass]=\"{ 'collapse show': !rootNode.root && !rootNode.hidden && config.view !== 'miller' }\"\n></c8y-asset-selector-node>\n" }]
1749
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "@if (\n !selectedDevice &&\n index === 0 &&\n (config.search || config.multi || config.label?.length || config.showSelected)\n) {\n <div\n class=\"bg-inherit p-t-8 p-b-8 separator-bottom p-r-16 p-l-16 sticky-top\"\n [ngStyle]=\"{ 'z-index': config.singleColumn && config.search ? '30' : '20' }\"\n #header\n [ngClass]=\"{\n 'p-absolute miller-column__selection d-flex flex-wrap a-i-center': config.view === 'miller',\n 'miller-column__search': config.search,\n 'miller-column__show-selected': config.showSelected\n }\"\n >\n @if (config.label?.length) {\n <p\n class=\"text-medium flex-no-shrink a-s-center\"\n [ngClass]=\"{\n 'm-b-4': config.search && root && config.singleColumn,\n 'm-r-8': !config.singleColumn && !config.search,\n 'fit-w': config.singleColumn\n }\"\n >\n {{ config.label | translate }}\n </p>\n }\n @if (config.search && root) {\n <c8y-search-input\n class=\"input-group-sm\"\n [ngStyle]=\"{ 'min-width': !config.singleColumn && config.label.length ? '50%' : 'inherit' }\"\n (onClick)=\"onSearchResultClick($event)\"\n (reset)=\"onSearchResultReset($event)\"\n [mode]=\"'select'\"\n [container]=\"container\"\n [groupsOnly]=\"config.groupsOnly\"\n [ngClass]=\"{\n 'm-l-auto': !config.singleColumn && config.label.length,\n 'fit-w': config.singleColumn || !config.label.length\n }\"\n ></c8y-search-input>\n }\n @if (config.showSelected) {\n <div\n class=\"bg-inherit d-flex gap-4 fit-w\"\n [ngClass]=\"{ 'm-t-4': config.search }\"\n >\n <span class=\"text-label-small m-r-4 a-s-center l-h-1\">{{ 'Selected' | translate }}</span>\n <div class=\"flex-grow inner-scroll d-flex gap-4 a-i-center\">\n @if (!selected.length) {\n <em class=\"text-12 text-muted d-flex a-i-center fit-h-20\">{{ 'None' | translate }}</em>\n }\n @for (selectedItem of selected; track selectedItem) {\n <span class=\"tag tag--info chip flex-no-shrink\">\n <button\n class=\"btn btn-xs btn-clean text-10\"\n title=\"{{ selectedItem.name }}\"\n type=\"button\"\n [disabled]=\"disabled\"\n (click)=\"config.multi ? deselect(selectedItem) : deselectAll()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n {{ selectedItem.name || (ASSET_CONST | translate: { assetId: selectedItem.id }) }}\n </span>\n }\n </div>\n </div>\n }\n </div>\n}\n\n@if (selectedDevice) {\n <div class=\"p-r-16\">\n <div class=\"d-flex p-b-4\">\n @if (selectedDevice) {\n <p class=\"text-medium p-t-8 m-r-8\">\n {{ 'Selected asset' | translate }}\n </p>\n } @else {\n <p class=\"text-medium m-r-8\">{{ 'Selected assets' | translate }}</p>\n }\n <button\n class=\"btn btn-default btn-xs a-s-center m-t-4 m-l-auto\"\n title=\"{{ 'Change' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); clearSelectedDevices()\"\n >\n {{ 'Change' | translate }}\n </button>\n </div>\n <div class=\"d-flex\">\n <i\n class=\"text-success p-l-0 p-r-8\"\n [c8yIcon]=\"'check-circle'\"\n ></i>\n <i\n class=\"m-r-4 icon-20\"\n [c8yIcon]=\"selectedDevice | getGroupIcon | async\"\n ></i>\n <span>{{ selectedDevice.name }}</span>\n </div>\n </div>\n}\n\n<!-- miller columns header -->\n@if (\n config.view === 'miller' &&\n ((config.showFilter && !rootNode.root) || config.columnHeaders) &&\n !selectedDevice\n) {\n <div\n class=\"miller-column__header sticky-top bg-inherit separator-bottom\"\n [attr.inert]=\"isScrolledOutOfView ? '' : null\"\n [ngClass]=\"{ 'p-t-8': config.search }\"\n >\n @if (config.singleColumn && index !== 0) {\n <div class=\"d-flex\">\n <i\n class=\"m-r-4\"\n c8yIcon=\"home\"\n ></i>\n <p\n class=\"text-12 text-muted text-truncate text-rtl m-b-4\"\n title=\"{{ rootNode.breadcrumb || rootNode.label | translate }}\"\n >\n {{ rootNode.breadcrumb || rootNode.label | translate }}\n </p>\n </div>\n }\n @if (config.columnHeaders || config.singleColumn) {\n <div class=\"d-flex a-i-center\">\n @if (config.singleColumn && !rootNode.root && index !== 0) {\n <button\n class=\"btn btn-default btn-xs m-r-8 p-t-0 p-b-0 p-l-4 p-r-4 l-h-1\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n (click)=\"$event.stopPropagation(); back()\"\n >\n <i c8yIcon=\"angle-left\"></i>\n </button>\n }\n @if (!rootNode.root && index === 0 && (config.groupsSelectable || !rootNode.isGroup())) {\n <label class=\"c8y-radio checkbox-inline m-r-8\">\n <input\n title=\"{{ 'Select group' | translate }}\"\n type=\"radio\"\n (change)=\"select(rootNode.mo)\"\n [checked]=\"isGroupSelected()\"\n />\n <span></span>\n </label>\n }\n\n @if (config.columnHeaders && (config.singleColumn || (!rootNode.root && index === 0))) {\n <i\n class=\"icon-20 c8y-icon-duocolor m-r-4\"\n [c8yIcon]=\"this.rootNode.mo | getGroupIcon: true : this.rootNode.icon | async\"\n ></i>\n }\n @if (config.columnHeaders) {\n <p\n class=\"text-truncate\"\n title=\"{{ rootNode.label | translate }}\"\n [ngClass]=\"{\n 'text-label-small': !config.singleColumn,\n 'text-medium': config.singleColumn\n }\"\n >\n {{ rootNode.label | translate }}\n </p>\n }\n </div>\n }\n\n @if (!rootNode.root && config.showFilter) {\n <div [ngClass]=\"{ 'p-t-4': config.columnHeaders }\">\n <div class=\"input-group input-group-sm input-group-search\">\n <input\n class=\"form-control text-truncate\"\n placeholder=\"{{ 'Filter this column\u2026' | translate }}\"\n [(ngModel)]=\"filterText\"\n (keyup.enter)=\"applyFilter('*' + filterText + '*')\"\n />\n <span class=\"input-group-btn\">\n <button\n class=\"btn btn-dot p-l-4\"\n title=\"{{ 'Apply filter' | translate }}\"\n type=\"button\"\n (click)=\"applyFilter('*' + filterText + '*')\"\n >\n <i c8yIcon=\"filter\"></i>\n </button>\n @if (filterText.length) {\n <button\n class=\"btn btn-dot p-l-4\"\n title=\" {{ 'Clear filters' | translate }}\"\n type=\"button\"\n (click)=\"clearFilters()\"\n >\n <i c8yIcon=\"times\"></i>\n </button>\n }\n </span>\n </div>\n </div>\n }\n </div>\n}\n\n@if (rootNode && !selectedDevice) {\n <c8y-asset-selector-node\n class=\"d-block bg-inherit p-relative\"\n style=\"z-index: 9\"\n [attr.inert]=\"isScrolledOutOfView ? '' : null\"\n [node]=\"rootNode\"\n [rootNode]=\"rootNode\"\n [preselected]=\"selected\"\n [multi]=\"config.multi\"\n [view]=\"config.view\"\n [index]=\"index\"\n [active]=\"active\"\n [disabled]=\"disabled\"\n [handleNextMillerViewColumn]=\"handleNextMillerViewColumn.bind(this)\"\n (isLoadingState)=\"onLoading($event)\"\n (onSelect)=\"onSelect($event)\"\n (onDeselect)=\"onDeselect($event)\"\n [ngClass]=\"{ 'collapse show': !rootNode.root && !rootNode.hidden && config.view !== 'miller' }\"\n ></c8y-asset-selector-node>\n}\n" }]
1743
1750
  }], ctorParameters: () => [{ type: GroupNodeService }, { type: i2.InventoryService }, { type: AssetSelectorService }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
1744
1751
  type: Input
1745
1752
  }], active: [{
@@ -1776,12 +1783,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1776
1783
  }] } });
1777
1784
 
1778
1785
  class MillerViewComponent extends AssetSelectorBase {
1779
- constructor(groupNodeService, inventory, assetSelectorService, cd) {
1786
+ constructor(groupNodeService, inventory, assetSelectorService, cd, interactivityChecker) {
1780
1787
  super(groupNodeService, inventory, assetSelectorService);
1781
1788
  this.groupNodeService = groupNodeService;
1782
1789
  this.inventory = inventory;
1783
1790
  this.assetSelectorService = assetSelectorService;
1784
1791
  this.cd = cd;
1792
+ this.interactivityChecker = interactivityChecker;
1785
1793
  /**
1786
1794
  * Config object containing all options for the asset selector.
1787
1795
  */
@@ -1820,6 +1828,14 @@ class MillerViewComponent extends AssetSelectorBase {
1820
1828
  * Cached padding top value to avoid recalculating on every change detection cycle.
1821
1829
  */
1822
1830
  this._cachedPaddingTop = null;
1831
+ /**
1832
+ * Set while the view waits for the column that just became visible to be focusable.
1833
+ */
1834
+ this.shouldFocusVisibleColumn = false;
1835
+ /**
1836
+ * Guards the deferred focus callbacks, which outlive the component when it is closed mid-animation.
1837
+ */
1838
+ this.destroyed = false;
1823
1839
  }
1824
1840
  /**
1825
1841
  * @ignore
@@ -1843,6 +1859,12 @@ class MillerViewComponent extends AssetSelectorBase {
1843
1859
  }
1844
1860
  this.columns.push(this.rootNode);
1845
1861
  }
1862
+ /**
1863
+ * @ignore
1864
+ */
1865
+ ngOnDestroy() {
1866
+ this.destroyed = true;
1867
+ }
1846
1868
  /**
1847
1869
  * @ignore
1848
1870
  */
@@ -1872,6 +1894,9 @@ class MillerViewComponent extends AssetSelectorBase {
1872
1894
  * Create a new column with the selected node as root.
1873
1895
  */
1874
1896
  addNewColumn(node) {
1897
+ /* read before the columns change: applying `inert` to the column left behind blurs whatever was
1898
+ focused in it, so afterwards the active element is always the body */
1899
+ const focusWasInView = this.millerViewWrapper.nativeElement.contains(document.activeElement);
1875
1900
  const level = node.index;
1876
1901
  this.selectedDevice = node.selectedDevices || undefined;
1877
1902
  if (node.root) {
@@ -1898,6 +1923,12 @@ class MillerViewComponent extends AssetSelectorBase {
1898
1923
  window.requestAnimationFrame(() => (col.millerViewWrapper.nativeElement.scrollLeft = 55000));
1899
1924
  }, 700);
1900
1925
  }
1926
+ /* assigned rather than only set: a request left over from an earlier column change can no longer
1927
+ be satisfied, and would otherwise move focus on the next unrelated load */
1928
+ this.shouldFocusVisibleColumn = focusWasInView;
1929
+ if (this.shouldFocusVisibleColumn) {
1930
+ window.requestAnimationFrame(() => this.focusVisibleColumn());
1931
+ }
1901
1932
  }
1902
1933
  /**
1903
1934
  * Change the loading state of the asset selector.
@@ -1908,6 +1939,10 @@ class MillerViewComponent extends AssetSelectorBase {
1908
1939
  this.columnIndex = event.index;
1909
1940
  this.selectedDevice = event.selectedDevice;
1910
1941
  this.cd.detectChanges();
1942
+ if (this.shouldFocusVisibleColumn && !event.loading) {
1943
+ // a column added for a group starts out empty, so its rows only exist once they are loaded
1944
+ window.requestAnimationFrame(() => this.focusVisibleColumn());
1945
+ }
1911
1946
  }
1912
1947
  /**
1913
1948
  * Add the selected node to the selected array.
@@ -1923,6 +1958,35 @@ class MillerViewComponent extends AssetSelectorBase {
1923
1958
  }
1924
1959
  this.deselect(event.change.item);
1925
1960
  }
1961
+ /**
1962
+ * Focuses the column that just opened, so that a keyboard user moves forward with it instead of
1963
+ * tabbing through the rest of the column they came from. Lands on the back button when a single
1964
+ * column renders one, otherwise on the first tab stop of the column, which is its filter or first
1965
+ * row.
1966
+ */
1967
+ focusVisibleColumn() {
1968
+ if (!this.shouldFocusVisibleColumn || this.destroyed) {
1969
+ return;
1970
+ }
1971
+ const columns = Array.from(this.millerViewWrapper.nativeElement.querySelectorAll('.miller-column'));
1972
+ const candidates = Array.from(columns[columns.length - 1]?.querySelectorAll('a[href], button, input, select, textarea, [tabindex]') || []);
1973
+ const target = candidates.find(
1974
+ // the selection header stays visible for all columns, so skip it and land in the column itself
1975
+ candidate => !candidate.closest('.miller-column__selection') &&
1976
+ /* both checks are needed: isTabbable() only reads tabIndex, and a disabled radio reports
1977
+ tabIndex 0 in Chrome, so on its own it would hand focus to an element that cannot take it */
1978
+ this.interactivityChecker.isFocusable(candidate) &&
1979
+ this.interactivityChecker.isTabbable(candidate));
1980
+ if (!target) {
1981
+ // nothing to focus yet, the column is still loading its rows; onLoad tries again
1982
+ return;
1983
+ }
1984
+ this.shouldFocusVisibleColumn = false;
1985
+ /* the wrapper is mid smooth-scroll towards the new column, and focusing an element scrolls it
1986
+ into view, which cancels that animation and leaves the column stranded until the Safari
1987
+ workaround in addNewColumn re-issues the scroll 700ms later */
1988
+ target.focus({ preventScroll: true });
1989
+ }
1926
1990
  /**
1927
1991
  * Calculates and caches the padding top value based on configuration options.
1928
1992
  *
@@ -1969,14 +2033,14 @@ class MillerViewComponent extends AssetSelectorBase {
1969
2033
  this._cachedPaddingTop = PADDING.NONE;
1970
2034
  }
1971
2035
  }
1972
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: MillerViewComponent, deps: [{ token: GroupNodeService }, { token: i2.InventoryService }, { token: AssetSelectorService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1973
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: MillerViewComponent, isStandalone: true, selector: "c8y-asset-selector-miller", inputs: { config: "config", asset: "asset", selectedDevice: "selectedDevice", rootNode: "rootNode", container: "container" }, outputs: { onSelected: "onSelected", onClearSelected: "onClearSelected" }, providers: [
2036
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: MillerViewComponent, deps: [{ token: GroupNodeService }, { token: i2.InventoryService }, { token: AssetSelectorService }, { token: i0.ChangeDetectorRef }, { token: i4$1.InteractivityChecker }], target: i0.ɵɵFactoryTarget.Component }); }
2037
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: MillerViewComponent, isStandalone: true, selector: "c8y-asset-selector-miller", inputs: { config: "config", asset: "asset", selectedDevice: "selectedDevice", rootNode: "rootNode", container: "container" }, outputs: { onSelected: "onSelected", onClearSelected: "onClearSelected" }, providers: [
1974
2038
  {
1975
2039
  provide: NG_VALUE_ACCESSOR,
1976
2040
  useExisting: forwardRef(() => MillerViewComponent),
1977
2041
  multi: true
1978
2042
  }
1979
- ], viewQueries: [{ propertyName: "millerViewWrapper", first: true, predicate: ["millerViewWrapper"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"miller-view-wrapper {{ config.label }}\"\n [ngStyle]=\"{\n 'padding-top': 'calc('+ getPaddingTop() +' * var(--c8y-unit-base))',\n }\"\n #millerViewWrapper\n [ngClass]=\"{\n 'single-column': config.singleColumn,\n }\"\n>\n <div\n class=\"miller-column bg-inherit\"\n *ngFor=\"let column of columns; index as i\"\n >\n <c8y-asset-selector\n class=\"bg-inherit\"\n #assetSelector\n [config]=\"config\"\n [index]=\"i\"\n [active]=\"columns[i + 1]\"\n [rootNode]=\"column\"\n [selected]=\"selected || []\"\n [selectedDevice]=\"selectedDevice\"\n (onSelected)=\"onSelectionChange($event)\"\n (onClearSelected)=\"onClearSelected.emit()\"\n (onRowSelected)=\"addNewColumn($event)\"\n (onLoad)=\"onLoad($event)\"\n [container]=\"container\"\n ></c8y-asset-selector>\n <div\n class=\"p-relative p-b-64\"\n *ngIf=\"isLoading && columnIndex === i && !selectedDevice\"\n >\n <c8y-loading></c8y-loading>\n </div>\n\n <div\n class=\"p-l-8 p-r-8\"\n *ngIf=\"!column.children.length && !isLoading\"\n >\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'The selected asset has no children.' | translate\"\n *ngIf=\"!filterText; else noSearchResults\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <ng-template #noSearchResults>\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display for the current filter.' | translate\"\n [subtitle]=\"'There are no assets matching the filter.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: AssetSelectorComponent, selector: "c8y-asset-selector", inputs: ["config", "active", "index", "asset", "selectedDevice", "selected", "rootNode", "selectedItems", "container", "isNodeSelectable", "disabled"], outputs: ["onSelected", "onClearSelected", "onRowSelected", "onLoad"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "progressLabel", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
2043
+ ], viewQueries: [{ propertyName: "millerViewWrapper", first: true, predicate: ["millerViewWrapper"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"miller-view-wrapper {{ config.label }}\"\n [ngStyle]=\"{\n 'padding-top': 'calc(' + getPaddingTop() + ' * var(--c8y-unit-base))'\n }\"\n #millerViewWrapper\n [ngClass]=\"{\n 'single-column': config.singleColumn\n }\"\n>\n <!-- track the node itself: a column replaced in place must get a fresh c8y-asset-selector, because\n the selector loads its tree in ngOnInit and its ngOnChanges does not react to rootNode -->\n @for (column of columns; track column; let i = $index) {\n <div class=\"miller-column bg-inherit\">\n <c8y-asset-selector\n class=\"bg-inherit\"\n #assetSelector\n [config]=\"config\"\n [index]=\"i\"\n [active]=\"columns[i + 1]\"\n [rootNode]=\"column\"\n [selected]=\"selected || []\"\n [selectedDevice]=\"selectedDevice\"\n (onSelected)=\"onSelectionChange($event)\"\n (onClearSelected)=\"onClearSelected.emit()\"\n (onRowSelected)=\"addNewColumn($event)\"\n (onLoad)=\"onLoad($event)\"\n [container]=\"container\"\n ></c8y-asset-selector>\n @if (isLoading && columnIndex === i && !selectedDevice) {\n <div class=\"p-relative p-b-64\">\n <c8y-loading></c8y-loading>\n </div>\n }\n\n @if (!column.children.length && !isLoading) {\n <div class=\"p-l-8 p-r-8\">\n @if (!filterText) {\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'The selected asset has no children.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display for the current filter.' | translate\"\n [subtitle]=\"'There are no assets matching the filter.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n </div>\n }\n </div>\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AssetSelectorComponent, selector: "c8y-asset-selector", inputs: ["config", "active", "index", "asset", "selectedDevice", "selected", "rootNode", "selectedItems", "container", "isNodeSelectable", "disabled"], outputs: ["onSelected", "onClearSelected", "onRowSelected", "onLoad"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "progressLabel", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1980
2044
  }
1981
2045
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: MillerViewComponent, decorators: [{
1982
2046
  type: Component,
@@ -1989,14 +2053,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1989
2053
  ], imports: [
1990
2054
  NgStyle,
1991
2055
  NgClass,
1992
- NgFor,
1993
2056
  AssetSelectorComponent,
1994
- NgIf,
1995
2057
  LoadingComponent,
1996
2058
  EmptyStateComponent,
1997
2059
  C8yTranslatePipe
1998
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div\n class=\"miller-view-wrapper {{ config.label }}\"\n [ngStyle]=\"{\n 'padding-top': 'calc('+ getPaddingTop() +' * var(--c8y-unit-base))',\n }\"\n #millerViewWrapper\n [ngClass]=\"{\n 'single-column': config.singleColumn,\n }\"\n>\n <div\n class=\"miller-column bg-inherit\"\n *ngFor=\"let column of columns; index as i\"\n >\n <c8y-asset-selector\n class=\"bg-inherit\"\n #assetSelector\n [config]=\"config\"\n [index]=\"i\"\n [active]=\"columns[i + 1]\"\n [rootNode]=\"column\"\n [selected]=\"selected || []\"\n [selectedDevice]=\"selectedDevice\"\n (onSelected)=\"onSelectionChange($event)\"\n (onClearSelected)=\"onClearSelected.emit()\"\n (onRowSelected)=\"addNewColumn($event)\"\n (onLoad)=\"onLoad($event)\"\n [container]=\"container\"\n ></c8y-asset-selector>\n <div\n class=\"p-relative p-b-64\"\n *ngIf=\"isLoading && columnIndex === i && !selectedDevice\"\n >\n <c8y-loading></c8y-loading>\n </div>\n\n <div\n class=\"p-l-8 p-r-8\"\n *ngIf=\"!column.children.length && !isLoading\"\n >\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'The selected asset has no children.' | translate\"\n *ngIf=\"!filterText; else noSearchResults\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <ng-template #noSearchResults>\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display for the current filter.' | translate\"\n [subtitle]=\"'There are no assets matching the filter.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n </div>\n </div>\n</div>\n" }]
1999
- }], ctorParameters: () => [{ type: GroupNodeService }, { type: i2.InventoryService }, { type: AssetSelectorService }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
2060
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div\n class=\"miller-view-wrapper {{ config.label }}\"\n [ngStyle]=\"{\n 'padding-top': 'calc(' + getPaddingTop() + ' * var(--c8y-unit-base))'\n }\"\n #millerViewWrapper\n [ngClass]=\"{\n 'single-column': config.singleColumn\n }\"\n>\n <!-- track the node itself: a column replaced in place must get a fresh c8y-asset-selector, because\n the selector loads its tree in ngOnInit and its ngOnChanges does not react to rootNode -->\n @for (column of columns; track column; let i = $index) {\n <div class=\"miller-column bg-inherit\">\n <c8y-asset-selector\n class=\"bg-inherit\"\n #assetSelector\n [config]=\"config\"\n [index]=\"i\"\n [active]=\"columns[i + 1]\"\n [rootNode]=\"column\"\n [selected]=\"selected || []\"\n [selectedDevice]=\"selectedDevice\"\n (onSelected)=\"onSelectionChange($event)\"\n (onClearSelected)=\"onClearSelected.emit()\"\n (onRowSelected)=\"addNewColumn($event)\"\n (onLoad)=\"onLoad($event)\"\n [container]=\"container\"\n ></c8y-asset-selector>\n @if (isLoading && columnIndex === i && !selectedDevice) {\n <div class=\"p-relative p-b-64\">\n <c8y-loading></c8y-loading>\n </div>\n }\n\n @if (!column.children.length && !isLoading) {\n <div class=\"p-l-8 p-r-8\">\n @if (!filterText) {\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'The selected asset has no children.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n } @else {\n <c8y-ui-empty-state\n [icon]=\"'folder-open'\"\n [title]=\"'No results to display for the current filter.' | translate\"\n [subtitle]=\"'There are no assets matching the filter.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n }\n </div>\n }\n </div>\n }\n</div>\n" }]
2061
+ }], ctorParameters: () => [{ type: GroupNodeService }, { type: i2.InventoryService }, { type: AssetSelectorService }, { type: i0.ChangeDetectorRef }, { type: i4$1.InteractivityChecker }], propDecorators: { config: [{
2000
2062
  type: Input
2001
2063
  }], asset: [{
2002
2064
  type: Input