@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.
- package/fesm2022/c8y-ngx-components-actility-device-registration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-actility-device-registration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-asset-properties.mjs +67 -20
- package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-assets-navigator.mjs +75 -13
- package/fesm2022/c8y-ngx-components-assets-navigator.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs +2 -4
- package/fesm2022/c8y-ngx-components-branding-shared-lazy-add-branding-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs +6 -8
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs +98 -19
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-dashboard-manager.mjs +4 -4
- package/fesm2022/c8y-ngx-components-dashboard-manager.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +7 -7
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +5 -3
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart-models.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart.mjs +52 -7
- package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-file-preview.mjs +2 -2
- package/fesm2022/c8y-ngx-components-file-preview.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-icon-selector.mjs +6 -6
- package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-loriot-device-registration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-loriot-device-registration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operation-picker.mjs +2 -2
- package/fesm2022/c8y-ngx-components-operation-picker.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-register-device.mjs +4 -4
- package/fesm2022/c8y-ngx-components-register-device.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs +2 -3
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-shared.mjs +2 -2
- package/fesm2022/c8y-ngx-components-remote-access-shared.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs +2 -2
- package/fesm2022/c8y-ngx-components-remote-access-ssh-remote-access-ssh-endpoint-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs +2 -4
- package/fesm2022/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs +2 -3
- package/fesm2022/c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-sigfox-device-registration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-sigfox-device-registration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs +2 -2
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs +3 -4
- package/fesm2022/c8y-ngx-components-translation-editor-lazy.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs +10 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +4 -4
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +18 -3
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +59 -19
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/de.po +3 -2
- package/locales/es.po +3 -3
- package/locales/fr.po +3 -3
- package/locales/ja_JP.po +2 -2
- package/locales/ko.po +3 -3
- package/locales/locales.pot +1 -1
- package/locales/nl.po +3 -3
- package/locales/pl.po +2 -3
- package/locales/pt_BR.po +2 -3
- package/locales/zh_CN.po +2 -2
- package/locales/zh_TW.po +3 -3
- package/package.json +1 -1
- package/types/c8y-ngx-components-asset-properties.d.ts +9 -1
- package/types/c8y-ngx-components-asset-properties.d.ts.map +1 -1
- package/types/c8y-ngx-components-assets-navigator.d.ts +30 -3
- package/types/c8y-ngx-components-assets-navigator.d.ts.map +1 -1
- package/types/c8y-ngx-components-branding-shared-lazy-add-branding-modal.d.ts.map +1 -1
- package/types/c8y-ngx-components-context-dashboard.d.ts +44 -1
- package/types/c8y-ngx-components-context-dashboard.d.ts.map +1 -1
- package/types/c8y-ngx-components-echart-models.d.ts +9 -0
- package/types/c8y-ngx-components-echart-models.d.ts.map +1 -1
- package/types/c8y-ngx-components-echart.d.ts +32 -5
- package/types/c8y-ngx-components-echart.d.ts.map +1 -1
- package/types/c8y-ngx-components-remote-access-vnc-remote-access-vnc-endpoint-modal.d.ts.map +1 -1
- package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts +6 -0
- package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts.map +1 -1
- package/types/c8y-ngx-components.d.ts +50 -2
- 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: "
|
|
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
|
|
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
|
|
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: "
|
|
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))'
|
|
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))'
|
|
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
|