@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
146 lines • 66 kB
JavaScript
import { Component, EventEmitter, Inject, Input, Output } from '@angular/core';
import { InventoryService, SmartGroupsService } from '@c8y/client';
import { AlertService, AssetTypesRealtimeService, CustomColumn, ModalService, Status, gettext } from '@c8y/ngx-components';
import { AssetNodeService } from '@c8y/ngx-components/assets-navigator';
import { DeviceListExtensionService } from '@c8y/ngx-components/device-list';
import { pick } from 'lodash-es';
import { Subject, firstValueFrom } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED } from './shared/sub-assets.model';
import { SUB_ASSETS_CONFIG } from './sub-assets.model';
import { SubAssetsService } from './sub-assets.service';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/client";
import * as i2 from "./sub-assets.service";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@c8y/ngx-components/assets-navigator";
import * as i5 from "@c8y/ngx-components/device-list";
import * as i6 from "@angular/common";
import * as i7 from "@angular/forms";
import * as i8 from "ngx-bootstrap/popover";
import * as i9 from "ngx-bootstrap/dropdown";
export class GroupInfoComponent {
constructor(inventory, subAssetsService, smartGroupsService, alertService, modalService, assetNodeService, assetType, deviceListExtensionService, moduleConfig) {
this.inventory = inventory;
this.subAssetsService = subAssetsService;
this.smartGroupsService = smartGroupsService;
this.alertService = alertService;
this.modalService = modalService;
this.assetNodeService = assetNodeService;
this.assetType = assetType;
this.deviceListExtensionService = deviceListExtensionService;
this.moduleConfig = moduleConfig;
this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_SUB_ASSETS_SHARED;
this.groupChange = new EventEmitter();
this.groupInfoModel = {
name: '',
c8y_Notes: ''
};
this.filterMsg = gettext('Smart groups are groups dynamically constructed based on filtering criteria.');
this.GROUP_UPDATED_MSG = gettext('Group updated.');
this.destroyed$ = new Subject();
this.deviceListExtensionService.items$.pipe(takeUntil(this.destroyed$)).subscribe(columns => {
this.allDevicesGridColumns = columns;
});
}
async ngOnChanges(changes) {
if (changes.group) {
const { name, c8y_Notes } = this.group;
this.groupInfoModel = { name, c8y_Notes };
this.canEdit = await this.subAssetsService.canEditGroup(this.group);
this.groupIcon = await this.assetNodeService.icon(this.group);
this.smartGroupFilter = this.group.c8y_DeviceQueryString;
this.columnsWithFilter = this.group.c8y_DeviceColumnsConfig?.columns
?.filter(col => !!col.filter)
.map(col => ({
...col,
externalFilterQuery: col.filter.externalFilterQuery,
...this.withPropsFromGridColumn(col)
}));
this.label = this.assetNodeService.isAsset(this.group)
? (await firstValueFrom(this.assetType.getAssetTypeByName$(this.group.type))).label
: gettext('Group');
}
}
isSmartGroup() {
return this.subAssetsService.isSmartGroup(this.group);
}
async update(partialGroup) {
try {
const isSmartGroup = this.subAssetsService.isSmartGroup(this.group);
const updatedGroup = isSmartGroup
? await this.updateSmartGroup(partialGroup)
: await this.updateGroup(partialGroup);
this.group = updatedGroup;
this.groupChange.emit(this.group);
this.alertService.success(this.GROUP_UPDATED_MSG);
}
catch (error) {
this.alertService.addServerFailure(error);
}
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
}
withPropsFromGridColumn(column) {
if (column.custom) {
const col = new CustomColumn();
return {
filteringConfig: col.filteringConfig
};
}
else {
return pick(this.allDevicesGridColumns.find(col => col.name === column.name), 'filteringConfig', 'header');
}
}
async updateGroup(partialGroup) {
const { id } = this.group;
const group = { id, ...partialGroup };
return (await this.inventory.update(group)).data;
}
async updateSmartGroup(partialGroup) {
const { id } = this.group;
const { c8y_DeviceQueryString } = partialGroup;
const group = { id, ...partialGroup };
if (!c8y_DeviceQueryString) {
return (await this.smartGroupsService.update(group)).data;
}
try {
const modalBody = gettext('You are about to change the smart group filter. Do you want to proceed?');
const title = gettext('Smart group filter');
await this.modalService.confirm(title, modalBody, Status.WARNING, {
ok: gettext('Save'),
cancel: gettext('Cancel')
});
await this.isQueryExecutable(c8y_DeviceQueryString);
}
catch (error) {
throw Error(error);
}
return (await this.smartGroupsService.update(group)).data;
}
async isQueryExecutable(query) {
try {
const filter = { q: query };
await this.inventory.list(filter);
}
catch (error) {
throw Error(error);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GroupInfoComponent, deps: [{ token: i1.InventoryService }, { token: i2.SubAssetsService }, { token: i1.SmartGroupsService }, { token: i3.AlertService }, { token: i3.ModalService }, { token: i4.AssetNodeService }, { token: i3.AssetTypesRealtimeService }, { token: i5.DeviceListExtensionService }, { token: SUB_ASSETS_CONFIG }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: GroupInfoComponent, selector: "c8y-group-info", inputs: { group: "group" }, outputs: { groupChange: "groupChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"bg-level-1 separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <div class=\"content-flex-70\">\n <div class=\"text-center col-1\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n [c8yIcon]=\"groupIcon\"\n ></i>\n <p>\n <small\n class=\"label label-info\"\n *ngIf=\"group.c8y_IsDynamicGroup\"\n >\n {{ 'Smart group' | translate }}\n </small>\n <small\n class=\"label label-info text-truncate d-inline-block\"\n title=\"{{ label | translate }}\"\n *ngIf=\"!group.c8y_IsDynamicGroup && !group.com_cumulocity_model_Agent\"\n >\n {{ label | translate }}\n </small>\n <small\n class=\"label label-info\"\n *ngIf=\"group.com_cumulocity_model_Agent\"\n >\n {{ 'Remote group' | translate }}\n </small>\n </p>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-9\">\n <form #groupNameForm=\"ngForm\">\n <c8y-form-group class=\"form-group-lg m-b-0\">\n <label\n class=\"sr-only\"\n for=\"groupName\"\n translate\n >\n Name\n </label>\n <p\n class=\"form-control-static\"\n *ngIf=\"!canEdit\"\n >\n {{ groupInfoModel.name }}\n </p>\n <div\n class=\"input-group input-group-lg input-group-editable\"\n *ngIf=\"canEdit\"\n >\n <input\n class=\"form-control\"\n title=\"{{ groupInfoModel.name }}\"\n id=\"groupName\"\n placeholder=\"{{ 'e.g. My group' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [(ngModel)]=\"groupInfoModel.name\"\n size=\"{{ groupInfoModel.name.length + 2 }}\"\n maxlength=\"254\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n action: PRODUCT_EXPERIENCE.GROUP_INFO.ACTIONS.EDIT,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.NAME\n }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"groupNameForm.form.invalid\"\n (click)=\"\n update({ name: groupInfoModel.name }); groupNameForm.form.markAsPristine()\n \"\n [actionName]=\"'groupInfo:EditedNameSaved'\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n result: PRODUCT_EXPERIENCE.GROUP_INFO.RESULTS.EDIT_SAVED,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.NAME\n }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </form>\n <form #groupDescriptionForm=\"ngForm\">\n <label\n class=\"sr-only\"\n for=\"description\"\n translate\n >\n Description\n </label>\n <p\n class=\"form-control-static\"\n *ngIf=\"!canEdit\"\n >\n {{ groupInfoModel.c8y_Notes }}\n </p>\n <div\n class=\"input-group input-group-editable\"\n *ngIf=\"canEdit\"\n >\n <textarea\n class=\"form-control no-resize\"\n title=\"{{\n groupInfoModel.c8y_Notes\n ? groupInfoModel.c8y_Notes\n : ('e.g. My description' | translate)\n }}\"\n id=\"description\"\n placeholder=\"{{ 'e.g. My description' | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n [(ngModel)]=\"groupInfoModel.c8y_Notes\"\n cols=\"{{ groupInfoModel.c8y_Notes ? groupInfoModel.c8y_Notes.length : 25 }}\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n action: PRODUCT_EXPERIENCE.GROUP_INFO.ACTIONS.EDIT,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.DESCRIPTION\n }\"\n ></textarea>\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"groupDescriptionForm.form.invalid\"\n (click)=\"\n update({ c8y_Notes: groupInfoModel.c8y_Notes });\n groupDescriptionForm.form.markAsPristine()\n \"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n result: PRODUCT_EXPERIENCE.GROUP_INFO.RESULTS.EDIT_SAVED,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.DESCRIPTION\n }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"dropdown m-t-8\"\n placement=\"bottom left\"\n container=\"body\"\n type=\"button\"\n dropdown\n *ngIf=\"isSmartGroup()\"\n #ddFilters=\"bs-dropdown\"\n [insideClick]=\"true\"\n >\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Smart group filters' | translate }}\"\n aria-haspopup=\"true\"\n dropdownToggle\n data-cy=\"c8y-data-grid--filters\"\n [disabled]=\"columnsWithFilter?.length === 0\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"filter\"\n ></i>\n <span>{{ 'Smart group filters' | translate }}</span>\n <span\n class=\"p-relative p-l-4 p-r-16\"\n *ngIf=\"columnsWithFilter?.length > 0\"\n >\n <span class=\"badge badge-system p-absolute\" data-cy=\"group-info--filter-number\">\n {{ columnsWithFilter?.length }}\n </span>\n </span>\n </button>\n <button\n class=\"btn-help btn-help--sm m-r-4\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ filterMsg | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n data-cy=\"group-info--help-button\"\n container=\"body\"\n type=\"button\"\n ></button>\n <div\n class=\"dropdown-menu\"\n *dropdownMenu\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"data-grid__dropdown bg-level-0\">\n <ul class=\"list-unstyled m-0\">\n <li\n *ngFor=\"let column of columnsWithFilter; let last = last\"\n [ngClass]=\"{ 'separator-bottom': !last }\"\n >\n <ng-container>\n <div\n class=\"dropdown-header sticky-top text-truncate no-border-top p-b-0\"\n title=\"{{ (column.header | translate) || column.name }}\"\n >\n <label>\n {{ (column.header | translate) || column.name }}\n </label>\n </div>\n <div\n class=\"list-group-item borderless d-flex d-col\"\n *ngFor=\"\n let groupedFilterChips of column\n | mapToFilterChips\n | async\n | groupedFilterChips;\n let first = first\n \"\n [ngClass]=\"{ 'p-t-0': first }\"\n >\n <p\n class=\"small p-b-4\"\n *ngIf=\"groupedFilterChips.label\"\n >\n {{ groupedFilterChips.label | translate }}\n </p>\n <div class=\"d-flex a-i-center gap-4 flex-wrap\">\n <span\n class=\"tag tag--info chip\"\n data-cy=\"group-info--grouped-filter-chip\"\n *ngFor=\"let chip of groupedFilterChips.chips\"\n >\n {{ chip.displayValue | translate }}\n </span>\n </div>\n </div>\n </ng-container>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n <div class=\"flex-grow\">\n <ul class=\"list-unstyled small\">\n <li class=\"p-t-4 p-b-4 d-flex separator-top-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-8\">{{ 'Created' | translate }}</label>\n <span class=\"m-l-auto\">{{ group.creationTime | c8yDate }}</span>\n </li>\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-8\">{{ 'Last updated' | translate }}</label>\n <span class=\"m-l-auto\">{{ group.lastUpdated | c8yDate }}</span>\n </li>\n <li\n class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\"\n *ngIf=\"group.com_cumulocity_model_Agent\"\n >\n <label class=\"small m-b-0 m-r-8\">{{ 'Status' | translate }}</label>\n <span\n class=\"m-l-auto\"\n *ngIf=\"group.c8y_BrokerSource\"\n >\n {{ group.c8y_BrokerSource.status }}\n </span>\n <span\n class=\"m-l-auto\"\n *ngIf=\"!group.c8y_BrokerSource\"\n >\n {{ 'Offline' | translate }}\n </span>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.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: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i7.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i3.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i3.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "directive", type: i8.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: i9.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i9.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i9.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.DatePipe, name: "c8yDate" }, { kind: "pipe", type: i3.FilterMapperPipe, name: "mapToFilterChips" }, { kind: "pipe", type: i3.GroupedFilterChips, name: "groupedFilterChips" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GroupInfoComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-group-info', template: "<div class=\"bg-level-1 separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <div class=\"content-flex-70\">\n <div class=\"text-center col-1\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n [c8yIcon]=\"groupIcon\"\n ></i>\n <p>\n <small\n class=\"label label-info\"\n *ngIf=\"group.c8y_IsDynamicGroup\"\n >\n {{ 'Smart group' | translate }}\n </small>\n <small\n class=\"label label-info text-truncate d-inline-block\"\n title=\"{{ label | translate }}\"\n *ngIf=\"!group.c8y_IsDynamicGroup && !group.com_cumulocity_model_Agent\"\n >\n {{ label | translate }}\n </small>\n <small\n class=\"label label-info\"\n *ngIf=\"group.com_cumulocity_model_Agent\"\n >\n {{ 'Remote group' | translate }}\n </small>\n </p>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-9\">\n <form #groupNameForm=\"ngForm\">\n <c8y-form-group class=\"form-group-lg m-b-0\">\n <label\n class=\"sr-only\"\n for=\"groupName\"\n translate\n >\n Name\n </label>\n <p\n class=\"form-control-static\"\n *ngIf=\"!canEdit\"\n >\n {{ groupInfoModel.name }}\n </p>\n <div\n class=\"input-group input-group-lg input-group-editable\"\n *ngIf=\"canEdit\"\n >\n <input\n class=\"form-control\"\n title=\"{{ groupInfoModel.name }}\"\n id=\"groupName\"\n placeholder=\"{{ 'e.g. My group' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [(ngModel)]=\"groupInfoModel.name\"\n size=\"{{ groupInfoModel.name.length + 2 }}\"\n maxlength=\"254\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n action: PRODUCT_EXPERIENCE.GROUP_INFO.ACTIONS.EDIT,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.NAME\n }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"groupNameForm.form.invalid\"\n (click)=\"\n update({ name: groupInfoModel.name }); groupNameForm.form.markAsPristine()\n \"\n [actionName]=\"'groupInfo:EditedNameSaved'\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n result: PRODUCT_EXPERIENCE.GROUP_INFO.RESULTS.EDIT_SAVED,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.NAME\n }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </form>\n <form #groupDescriptionForm=\"ngForm\">\n <label\n class=\"sr-only\"\n for=\"description\"\n translate\n >\n Description\n </label>\n <p\n class=\"form-control-static\"\n *ngIf=\"!canEdit\"\n >\n {{ groupInfoModel.c8y_Notes }}\n </p>\n <div\n class=\"input-group input-group-editable\"\n *ngIf=\"canEdit\"\n >\n <textarea\n class=\"form-control no-resize\"\n title=\"{{\n groupInfoModel.c8y_Notes\n ? groupInfoModel.c8y_Notes\n : ('e.g. My description' | translate)\n }}\"\n id=\"description\"\n placeholder=\"{{ 'e.g. My description' | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n [(ngModel)]=\"groupInfoModel.c8y_Notes\"\n cols=\"{{ groupInfoModel.c8y_Notes ? groupInfoModel.c8y_Notes.length : 25 }}\"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n action: PRODUCT_EXPERIENCE.GROUP_INFO.ACTIONS.EDIT,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.DESCRIPTION\n }\"\n ></textarea>\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"groupDescriptionForm.form.invalid\"\n (click)=\"\n update({ c8y_Notes: groupInfoModel.c8y_Notes });\n groupDescriptionForm.form.markAsPristine()\n \"\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.EVENT\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.GROUP_INFO.COMPONENTS.GROUP_INFO,\n result: PRODUCT_EXPERIENCE.GROUP_INFO.RESULTS.EDIT_SAVED,\n property: PRODUCT_EXPERIENCE.GROUP_INFO.PROPERTIES.DESCRIPTION\n }\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"dropdown m-t-8\"\n placement=\"bottom left\"\n container=\"body\"\n type=\"button\"\n dropdown\n *ngIf=\"isSmartGroup()\"\n #ddFilters=\"bs-dropdown\"\n [insideClick]=\"true\"\n >\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Smart group filters' | translate }}\"\n aria-haspopup=\"true\"\n dropdownToggle\n data-cy=\"c8y-data-grid--filters\"\n [disabled]=\"columnsWithFilter?.length === 0\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"filter\"\n ></i>\n <span>{{ 'Smart group filters' | translate }}</span>\n <span\n class=\"p-relative p-l-4 p-r-16\"\n *ngIf=\"columnsWithFilter?.length > 0\"\n >\n <span class=\"badge badge-system p-absolute\" data-cy=\"group-info--filter-number\">\n {{ columnsWithFilter?.length }}\n </span>\n </span>\n </button>\n <button\n class=\"btn-help btn-help--sm m-r-4\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ filterMsg | translate }}\"\n placement=\"right\"\n triggers=\"focus\"\n data-cy=\"group-info--help-button\"\n container=\"body\"\n type=\"button\"\n ></button>\n <div\n class=\"dropdown-menu\"\n *dropdownMenu\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"data-grid__dropdown bg-level-0\">\n <ul class=\"list-unstyled m-0\">\n <li\n *ngFor=\"let column of columnsWithFilter; let last = last\"\n [ngClass]=\"{ 'separator-bottom': !last }\"\n >\n <ng-container>\n <div\n class=\"dropdown-header sticky-top text-truncate no-border-top p-b-0\"\n title=\"{{ (column.header | translate) || column.name }}\"\n >\n <label>\n {{ (column.header | translate) || column.name }}\n </label>\n </div>\n <div\n class=\"list-group-item borderless d-flex d-col\"\n *ngFor=\"\n let groupedFilterChips of column\n | mapToFilterChips\n | async\n | groupedFilterChips;\n let first = first\n \"\n [ngClass]=\"{ 'p-t-0': first }\"\n >\n <p\n class=\"small p-b-4\"\n *ngIf=\"groupedFilterChips.label\"\n >\n {{ groupedFilterChips.label | translate }}\n </p>\n <div class=\"d-flex a-i-center gap-4 flex-wrap\">\n <span\n class=\"tag tag--info chip\"\n data-cy=\"group-info--grouped-filter-chip\"\n *ngFor=\"let chip of groupedFilterChips.chips\"\n >\n {{ chip.displayValue | translate }}\n </span>\n </div>\n </div>\n </ng-container>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n <div class=\"flex-grow\">\n <ul class=\"list-unstyled small\">\n <li class=\"p-t-4 p-b-4 d-flex separator-top-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-8\">{{ 'Created' | translate }}</label>\n <span class=\"m-l-auto\">{{ group.creationTime | c8yDate }}</span>\n </li>\n <li class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\">\n <label class=\"small m-b-0 m-r-8\">{{ 'Last updated' | translate }}</label>\n <span class=\"m-l-auto\">{{ group.lastUpdated | c8yDate }}</span>\n </li>\n <li\n class=\"p-t-4 p-b-4 d-flex separator-bottom text-nowrap\"\n *ngIf=\"group.com_cumulocity_model_Agent\"\n >\n <label class=\"small m-b-0 m-r-8\">{{ 'Status' | translate }}</label>\n <span\n class=\"m-l-auto\"\n *ngIf=\"group.c8y_BrokerSource\"\n >\n {{ group.c8y_BrokerSource.status }}\n </span>\n <span\n class=\"m-l-auto\"\n *ngIf=\"!group.c8y_BrokerSource\"\n >\n {{ 'Offline' | translate }}\n </span>\n </li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.InventoryService }, { type: i2.SubAssetsService }, { type: i1.SmartGroupsService }, { type: i3.AlertService }, { type: i3.ModalService }, { type: i4.AssetNodeService }, { type: i3.AssetTypesRealtimeService }, { type: i5.DeviceListExtensionService }, { type: undefined, decorators: [{
type: Inject,
args: [SUB_ASSETS_CONFIG]
}] }], propDecorators: { group: [{
type: Input
}], groupChange: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JvdXAtaW5mby5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zdWItYXNzZXRzL2dyb3VwLWluZm8uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vc3ViLWFzc2V0cy9ncm91cC1pbmZvLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBR0wsTUFBTSxFQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBa0IsZ0JBQWdCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbkYsT0FBTyxFQUNMLFlBQVksRUFDWix5QkFBeUIsRUFFekIsWUFBWSxFQUNaLFlBQVksRUFDWixNQUFNLEVBQ04sT0FBTyxFQUNSLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDeEUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDN0UsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNqQyxPQUFPLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUFFLG9DQUFvQyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakYsT0FBTyxFQUFFLGlCQUFpQixFQUFtQixNQUFNLG9CQUFvQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDOzs7Ozs7Ozs7OztBQU94RCxNQUFNLE9BQU8sa0JBQWtCO0lBeUI3QixZQUNVLFNBQTJCLEVBQzNCLGdCQUFrQyxFQUNsQyxrQkFBc0MsRUFDdEMsWUFBMEIsRUFDMUIsWUFBMEIsRUFDMUIsZ0JBQWtDLEVB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QyxDQUFDO1lBRUgsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN0RCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JCLENBQUM7UUFDRCxPQUFPLENBQUMsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQzVELENBQUM7SUFFTyxLQUFLLENBQUMsaUJBQWlCLENBQUMsS0FBYTtRQUMzQyxJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckIsQ0FBQztJQUNILENBQUM7K0dBNUlVLGtCQUFrQiwrUkFrQ25CLGlCQUFpQjttR0FsQ2hCLGtCQUFrQixnSkNsQy9CLHMyWEFvU0E7OzRGRGxRYSxrQkFBa0I7a0JBSjlCLFNBQVM7K0JBQ0UsZ0JBQWdCOzswQkFxQ3ZCLE1BQU07MkJBQUMsaUJBQWlCO3lDQWhDbEIsS0FBSztzQkFBYixLQUFLO2dCQUNJLFdBQVc7c0JBQXBCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlc1xufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0LCBJbnZlbnRvcnlTZXJ2aWNlLCBTbWFydEdyb3Vwc1NlcnZpY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQge1xuICBBbGVydFNlcnZpY2UsXG4gIEFzc2V0VHlwZXNSZWFsdGltZVNlcnZpY2UsXG4gIENvbHVtbixcbiAgQ3VzdG9tQ29sdW1uLFxuICBNb2RhbFNlcnZpY2UsXG4gIFN0YXR1cyxcbiAgZ2V0dGV4dFxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEFzc2V0Tm9kZVNlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2Fzc2V0cy1uYXZpZ2F0b3InO1xuaW1wb3J0IHsgRGV2aWNlTGlzdEV4dGVuc2lvblNlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2RldmljZS1saXN0JztcbmltcG9ydCB7IHBpY2sgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgU3ViamVjdCwgZmlyc3RWYWx1ZUZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFBST0RVQ1RfRVhQRVJJRU5DRV9TVUJfQVNTRVRTX1NIQVJFRCB9IGZyb20gJy4vc2hhcmVkL3N1Yi1hc3NldHMubW9kZWwnO1xuaW1wb3J0IHsgU1VCX0FTU0VUU19DT05GSUcsIFN1YkFzc2V0c0NvbmZpZyB9IGZyb20gJy4vc3ViLWFzc2V0cy5tb2RlbCc7XG5pbXBvcnQgeyBTdWJBc3NldHNTZXJ2aWNlIH0gZnJvbSAnLi9zdWItYXNzZXRzLnNlcnZpY2UnO1xuaW1wb3J0IHsgU3VwcG9ydGVkSWNvbnNTdWdnZXN0aW9ucyB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvaWNvbi1zZWxlY3Rvci9pY29ucyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1ncm91cC1pbmZvJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2dyb3VwLWluZm8uY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEdyb3VwSW5mb0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uRGVzdHJveSwgT25DaGFuZ2VzIHtcbiAgUFJPRFVDVF9FWFBFUklFTkNFID0gUFJPRFVDVF9FWFBFUklFTkNFX1NVQl9BU1NFVFNfU0hBUkVEO1xuICBASW5wdXQoKSBncm91cDogSU1hbmFnZWRPYmplY3Q7XG4gIEBPdXRwdXQoKSBncm91cENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8SU1hbmFnZWRPYmplY3Q+KCk7XG4gIGNhbkVkaXQ6IGJvb2xlYW47XG4gIGdyb3VwSWNvbjogU3VwcG9ydGVkSWNvbnNTdWdnZXN0aW9ucztcbiAgc21hcnRHcm91cEZpbHRlcjogc3RyaW5nO1xuICBsYWJlbDogc3RyaW5nO1xuICBjb2x1bW5zV2l0aEZpbHRlcjogQ29sdW1uW107XG5cbiAgZ3JvdXBJbmZvTW9kZWw6IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgYzh5X05vdGVzOiBzdHJpbmc7XG4gIH0gPSB7XG4gICAgbmFtZTogJycsXG4gICAgYzh5X05vdGVzOiAnJ1xuICB9O1xuXG4gIGZpbHRlck1zZyA9IGdldHRleHQoXG4gICAgJ1NtYXJ0IGdyb3VwcyBhcmUgZ3JvdXBzIGR5bmFtaWNhbGx5IGNvbnN0cnVjdGVkIGJhc2VkIG9uIGZpbHRlcmluZyBjcml0ZXJpYS4nXG4gICk7XG4gIHByaXZhdGUgcmVhZG9ubHkgR1JPVVBfVVBEQVRFRF9NU0cgPSBnZXR0ZXh0KCdHcm91cCB1cGRhdGVkLicpO1xuICBwcml2YXRlIGFsbERldmljZXNHcmlkQ29sdW1uczogQ29sdW1uW107XG4gIHByaXZhdGUgZGVzdHJveWVkJCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBpbnZlbnRvcnk6IEludmVudG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBzdWJBc3NldHNTZXJ2aWNlOiBTdWJBc3NldHNTZXJ2aWNlLFxuICAgIHByaXZhdGUgc21hcnRHcm91cHNTZXJ2aWNlOiBTbWFydEdyb3Vwc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwcml2YXRlIG1vZGFsU2VydmljZTogTW9kYWxTZXJ2aWNlLFxuICAgIHByaXZhdGUgYXNzZXROb2RlU2VydmljZTogQXNzZXROb2RlU2VydmljZSxcbiAgICBwcml2YXRlIGFzc2V0VHlwZTogQXNzZXRUeXBlc1JlYWx0aW1lU2VydmljZSxcbiAgICBwcml2YXRlIGRldmljZUxpc3RFeHRlbnNpb25TZXJ2aWNlOiBEZXZpY2VMaXN0RXh0ZW5zaW9uU2VydmljZSxcbiAgICBASW5qZWN0KFNVQl9BU1NFVFNfQ09ORklHKSBwdWJsaWMgbW9kdWxlQ29uZmlnOiBTdWJBc3NldHNDb25maWdcbiAgKSB7XG4gICAgdGhpcy5kZXZpY2VMaXN0RXh0ZW5zaW9uU2VydmljZS5pdGVtcyQucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95ZWQkKSkuc3Vic2NyaWJlKGNvbHVtbnMgPT4ge1xuICAgICAgdGhpcy5hbGxEZXZpY2VzR3JpZENvbHVtbnMgPSBjb2x1bW5zO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcykge1xuICAgIGlmIChjaGFuZ2VzLmdyb3VwKSB7XG4gICAgICBjb25zdCB7IG5hbWUsIGM4eV9Ob3RlcyB9ID0gdGhpcy5ncm91cDtcbiAgICAgIHRoaXMuZ3JvdXBJbmZvTW9kZWwgPSB7IG5hbWUsIGM4eV9Ob3RlcyB9O1xuICAgICAgdGhpcy5jYW5FZGl0ID0gYXdhaXQgdGhpcy5zdWJBc3NldHNTZXJ2aWNlLmNhbkVkaXRHcm91cCh0aGlzLmdyb3VwKTtcbiAgICAgIHRoaXMuZ3JvdXBJY29uID0gYXdhaXQgdGhpcy5hc3NldE5vZGVTZXJ2aWNlLmljb24odGhpcy5ncm91cCk7XG4gICAgICB0aGlzLnNtYXJ0R3JvdXBGaWx0ZXIgPSB0aGlzLmdyb3VwLmM4eV9EZXZpY2VRdWVyeVN0cmluZztcbiAgICAgIHRoaXMuY29sdW1uc1dpdGhGaWx0ZXIgPSB0aGlzLmdyb3VwLmM4eV9EZXZpY2VDb2x1bW5zQ29uZmlnPy5jb2x1bW5zXG4gICAgICAgID8uZmlsdGVyKGNvbCA9PiAhIWNvbC5maWx0ZXIpXG4gICAgICAgIC5tYXAoY29sID0+ICh7XG4gICAgICAgICAgLi4uY29sLFxuICAgICAgICAgIGV4dGVybmFsRmlsdGVyUXVlcnk6IGNvbC5maWx0ZXIuZXh0ZXJuYWxGaWx0ZXJRdWVyeSxcbiAgICAgICAgICAuLi50aGlzLndpdGhQcm9wc0Zyb21HcmlkQ29sdW1uKGNvbClcbiAgICAgICAgfSkpO1xuICAgICAgdGhpcy5sYWJlbCA9IHRoaXMuYXNzZXROb2RlU2VydmljZS5pc0Fzc2V0KHRoaXMuZ3JvdXApXG4gICAgICAgID8gKGF3YWl0IGZpcnN0VmFsdWVGcm9tKHRoaXMuYXNzZXRUeXBlLmdldEFzc2V0VHlwZUJ5TmFtZSQodGhpcy5ncm91cC50eXBlKSkpLmxhYmVsXG4gICAgICAgIDogZ2V0dGV4dCgnR3JvdXAnKTtcbiAgICB9XG4gIH1cblxuICBpc1NtYXJ0R3JvdXAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3ViQXNzZXRzU2VydmljZS5pc1NtYXJ0R3JvdXAodGhpcy5ncm91cCk7XG4gIH1cblxuICBhc3luYyB1cGRhdGUocGFydGlhbEdyb3VwOiBQYXJ0aWFsPElNYW5hZ2VkT2JqZWN0Pikge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBpc1NtYXJ0R3JvdXA6IGJvb2xlYW4gPSB0aGlzLnN1YkFzc2V0c1NlcnZpY2UuaXNTbWFydEdyb3VwKHRoaXMuZ3JvdXApO1xuICAgICAgY29uc3QgdXBkYXRlZEdyb3VwID0gaXNTbWFydEdyb3VwXG4gICAgICAgID8gYXdhaXQgdGhpcy51cGRhdGVTbWFydEdyb3VwKHBhcnRpYWxHcm91cClcbiAgICAgICAgOiBhd2FpdCB0aGlzLnVwZGF0ZUdyb3VwKHBhcnRpYWxHcm91cCk7XG5cbiAgICAgIHRoaXMuZ3JvdXAgPSB1cGRhdGVkR3JvdXA7XG4gICAgICB0aGlzLmdyb3VwQ2hhbmdlLmVtaXQodGhpcy5ncm91cCk7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5zdWNjZXNzKHRoaXMuR1JPVVBfVVBEQVRFRF9NU0cpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5hZGRTZXJ2ZXJGYWlsdXJlKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3llZCQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveWVkJC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSB3aXRoUHJvcHNGcm9tR3JpZENvbHVtbihjb2x1bW46IENvbHVtbik6IFBhcnRpYWw8Q29sdW1uPiB7XG4gICAgaWYgKGNvbHVtbi5jdXN0b20pIHtcbiAgICAgIGNvbnN0IGNvbCA9IG5ldyBDdXN0b21Db2x1bW4oKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGZpbHRlcmluZ0NvbmZpZzogY29sLmZpbHRlcmluZ0NvbmZpZ1xuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHBpY2soXG4gICAgICAgIHRoaXMuYWxsRGV2aWNlc0dyaWRDb2x1bW5zLmZpbmQoY29sID0+IGNvbC5uYW1lID09PSBjb2x1bW4ubmFtZSksXG4gICAgICAgICdmaWx0ZXJpbmdDb25maWcnLFxuICAgICAgICAnaGVhZGVyJ1xuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHVwZGF0ZUdyb3VwKHBhcnRpYWxHcm91cDogUGFydGlhbDxJTWFuYWdlZE9iamVjdD4pIHtcbiAgICBjb25zdCB7IGlkIH0gPSB0aGlzLmdyb3VwO1xuICAgIGNvbnN0IGdyb3VwOiBQYXJ0aWFsPElNYW5hZ2VkT2JqZWN0PiA9IHsgaWQsIC4uLnBhcnRpYWxHcm91cCB9O1xuXG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmludmVudG9yeS51cGRhdGUoZ3JvdXApKS5kYXRhO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1cGRhdGVTbWFydEdyb3VwKHBhcnRpYWxHcm91cDogUGFydGlhbDxJTWFuYWdlZE9iamVjdD4pIHtcbiAgICBjb25zdCB7IGlkIH0gPSB0aGlzLmdyb3VwO1xuICAgIGNvbnN0IHsgYzh5X0RldmljZVF1ZXJ5U3RyaW5nIH0gPSBwYXJ0aWFsR3JvdXA7XG4gICAgY29uc3QgZ3JvdXA6IFBhcnRpYWw8SU1hbmFnZWRPYmplY3Q+ID0geyBpZCwgLi4ucGFydGlhbEdyb3VwIH07XG5cbiAgICBpZiAoIWM4eV9EZXZpY2VRdWVyeVN0cmluZykge1xuICAgICAgcmV0dXJuIChhd2FpdCB0aGlzLnNtYXJ0R3JvdXBzU2VydmljZS51cGRhdGUoZ3JvdXApKS5kYXRhO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBtb2RhbEJvZHkgPSBnZXR0ZXh0KFxuICAgICAgICAnWW91IGFyZSBhYm91dCB0byBjaGFuZ2UgdGhlIHNtYXJ0IGdyb3VwIGZpbHRlci4gRG8geW91IHdhbnQgdG8gcHJvY2VlZD8nXG4gICAgICApO1xuICAgICAgY29uc3QgdGl0bGUgPSBnZXR0ZXh0KCdTbWFydCBncm91cCBmaWx0ZXInKTtcbiAgICAgIGF3YWl0IHRoaXMubW9kYWxTZXJ2aWNlLmNvbmZpcm0odGl0bGUsIG1vZGFsQm9keSwgU3RhdHVzLldBUk5JTkcsIHtcbiAgICAgICAgb2s6IGdldHRleHQoJ1NhdmUnKSxcbiAgICAgICAgY2FuY2VsOiBnZXR0ZXh0KCdDYW5jZWwnKVxuICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IHRoaXMuaXNRdWVyeUV4ZWN1dGFibGUoYzh5X0RldmljZVF1ZXJ5U3RyaW5nKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgRXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuc21hcnRHcm91cHNTZXJ2aWNlLnVwZGF0ZShncm91cCkpLmRhdGE7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGlzUXVlcnlFeGVjdXRhYmxlKHF1ZXJ5OiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZmlsdGVyID0geyBxOiBxdWVyeSB9O1xuICAgICAgYXdhaXQgdGhpcy5pbnZlbnRvcnkubGlzdChmaWx0ZXIpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBFcnJvcihlcnJvcik7XG4gICAgfVxuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiYmctbGV2ZWwtMSBzZXBhcmF0b3ItYm90dG9tXCI+XG4gIDxkaXYgY2xhc3M9XCJjYXJkLWJsb2NrIHAtdC0yNCBwLWItMjQgbGFyZ2UtcGFkZGluZ1wiPlxuICAgIDxkaXYgY2xhc3M9XCJjb250ZW50LWZsZXgtNzBcIj5cbiAgICAgIDxkaXYgY2x