@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
133 lines • 73.2 kB
JavaScript
import { Component } from '@angular/core';
import { DeviceRegistrationSecurityMode, DeviceRegistrationStatus } from '@c8y/client';
import { BehaviorSubject, Subject } from 'rxjs';
import { filter, map, switchMap, takeUntil } from 'rxjs/operators';
import { DeviceBootstrapRealtimeService, TenantUiService, ModalService, Status, gettext, OptionsService } from '@c8y/ngx-components';
import { RegisterDeviceService } from './register-device.service';
import { sortBy } from 'lodash-es';
import { TranslateService } from '@ngx-translate/core';
import * as i0 from "@angular/core";
import * as i1 from "./register-device.service";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "@ngx-translate/core";
import * as i4 from "ngx-bootstrap/popover";
import * as i5 from "@angular/common";
import * as i6 from "@angular/forms";
import * as i7 from "./dropdown/register-device-dropdown.component";
export class DeviceRegistrationViewComponent {
constructor(registerDeviceService, bootstrapRealtimeService, tenantUiService, modalService, translateService, optionsService) {
this.registerDeviceService = registerDeviceService;
this.bootstrapRealtimeService = bootstrapRealtimeService;
this.tenantUiService = tenantUiService;
this.modalService = modalService;
this.translateService = translateService;
this.optionsService = optionsService;
this.requireSecurityToken = false;
this.isManagementTenant = false;
this.isLoading = false;
this.gridOrList = 'interact-grid';
this.status = DeviceRegistrationStatus;
this.statusProps = {
[DeviceRegistrationStatus.WAITING_FOR_CONNECTION]: {
label: gettext('Waiting for connection'),
icon: 'unlink',
cls: 'text-danger'
},
[DeviceRegistrationStatus.PENDING_ACCEPTANCE]: {
label: gettext('Pending acceptance'),
icon: 'circle',
cls: 'text-info'
},
[DeviceRegistrationStatus.ACCEPTED]: {
label: gettext('Accepted'),
icon: 'check-circle',
cls: 'text-success'
},
[DeviceRegistrationStatus.BLOCKED]: {
label: gettext('Blocked'),
icon: 'ban',
cls: 'text-danger'
}
};
this.unsubscribe$ = new Subject();
this._securityTokenPolicy = new BehaviorSubject(DeviceRegistrationSecurityMode.OPTIONAL);
}
ngOnInit() {
this.loadAll();
this.setIsManagementTenant();
this.setRequireSecurityToken();
this.deviceRequests$ = this.registerDeviceService.deviceRegistrationRequests$.pipe(map(req => ({
data: sortBy(req.data, [
({ status }) => (status === DeviceRegistrationStatus.PENDING_ACCEPTANCE ? 0 : 1),
'-creationTime'
]),
paging: req.paging
})));
this.limit$ = this.registerDeviceService.limit$;
this.limitReachedInfo$ = this.limit$.pipe(filter(deviceRegistrationLimit => deviceRegistrationLimit.isReached), switchMap(({ limit }) => this.translateService.stream(gettext('You reached the limit of {{ maxDevices }} devices. No more devices can be registered.'), { maxDevices: limit })));
this.registerDeviceService.loading$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(value => (this.isLoading = value));
this.bootstrapRealtimeService
.onUpdate$()
.pipe(takeUntil(this.unsubscribe$))
.subscribe((bootstrap) => {
this.registerDeviceService.onDeviceBootstrap(bootstrap);
});
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
updateList(data) {
this.registerDeviceService.internalListUpdate(data);
}
async delete(id) {
const confirmed = await this.modalService.confirm(gettext('Cancel device registration'), this.translateService.instant(gettext('You are about to cancel device registration for ID "{{id}}". Do you want to proceed?'), { id }), Status.DANGER, {
ok: gettext('Cancel registration'),
cancel: gettext('Close')
});
if (confirmed) {
this.registerDeviceService.remove(id);
}
}
accept(request) {
this.registerDeviceService.accept(request);
}
acceptAll() {
this.registerDeviceService.acceptAll();
}
canAcceptAll() {
const pendingRequests = this.registerDeviceService.getRequestByStatus(DeviceRegistrationStatus.PENDING_ACCEPTANCE);
return !(pendingRequests.length > 0 && !this.requireSecurityToken);
}
loadAll() {
this.registerDeviceService.list();
}
displayMode(listClass) {
this.gridOrList = listClass;
}
async setRequireSecurityToken() {
const mode = (await this.optionsService.getTenantOption('device-registration', 'security-token.policy', DeviceRegistrationSecurityMode.OPTIONAL));
this._securityTokenPolicy.next(mode);
this.requireSecurityToken = mode === DeviceRegistrationSecurityMode.REQUIRED;
}
async setIsManagementTenant() {
this.isManagementTenant = await this.tenantUiService.isManagementTenant();
}
shouldShowSecurityTokenInput(data) {
return (data &&
data.status === DeviceRegistrationStatus.PENDING_ACCEPTANCE &&
this.showTokenInputBasedOnSecurityMode());
}
showTokenInputBasedOnSecurityMode() {
return this._securityTokenPolicy.getValue() !== DeviceRegistrationSecurityMode.IGNORED;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceRegistrationViewComponent, deps: [{ token: i1.RegisterDeviceService }, { token: i2.DeviceBootstrapRealtimeService }, { token: i2.TenantUiService }, { token: i2.ModalService }, { token: i3.TranslateService }, { token: i2.OptionsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DeviceRegistrationViewComponent, selector: "c8y-device-registration-view", ngImport: i0, template: "<ng-container *ngIf=\"deviceRequests$ | async as deviceRequestList\">\n <c8y-title>\n {{ 'Device registration' | translate }}\n <small *ngIf=\"deviceRequestList.data.length === 1\">1 {{ 'new device' | translate }}</small>\n <small *ngIf=\"deviceRequestList.data.length > 1\">\n {{ deviceRequestList.data.length }} {{ 'new devices' | translate }}\n </small>\n </c8y-title>\n\n <c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'exchange'\"\n [label]=\"'Devices' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-connect'\"\n [label]=\"'Device registration' | translate\"\n ></c8y-breadcrumb-item>\n </c8y-breadcrumb>\n\n <c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n >\n <c8y-list-display-switch (onListClassChange)=\"displayMode($event)\"></c8y-list-display-switch>\n </c8y-action-bar-item>\n\n <ng-container *ngIf=\"limit$ | async as limitStatus\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"10\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Accept all' | translate }}\"\n type=\"button\"\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n (click)=\"acceptAll()\"\n [disabled]=\"canAcceptAll() || limitStatus?.isReached\"\n >\n <i [c8yIcon]=\"'check'\"></i>\n {{ 'Accept all' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"9\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadAll()\"\n [disabled]=\"isLoading\"\n >\n <i\n [c8yIcon]=\"'refresh'\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n >\n <c8y-register-device-dropdown></c8y-register-device-dropdown>\n </c8y-action-bar-item>\n\n <c8y-help\n src=\"/docs/device-management-application/registering-devices/#registering-devices\"\n ></c8y-help>\n\n <ng-container *ngIf=\"deviceRequestList.data.length > 0; else noData\">\n <div\n class=\"card-group\"\n [ngClass]=\"gridOrList\"\n >\n <!-- START interact-list sticky header START -->\n <div\n class=\"page-sticky-header hidden-xs\"\n *ngIf=\"gridOrList === 'interact-list'\"\n >\n <div class=\"d-flex\">\n <div class=\"card-header p-l-40\">\n <p translate>Device</p>\n </div>\n <div class=\"card-block card-column-30 p-l-0 m-l-8\">\n <p translate>Status</p>\n </div>\n <div\n class=\"card-block card-column-30 p-0\"\n *ngIf=\"showTokenInputBasedOnSecurityMode()\"\n >\n <p translate>Security token</p>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Security token is required if the connected device uses it.' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </div>\n <div class=\"card-footer card-column-50\">\n <div\n class=\"d-contents\"\n *ngIf=\"isManagementTenant; else noManagement\"\n >\n <div class=\"card-column-50\">\n {{ 'Created' | translate }}\n </div>\n <div class=\"card-column-30\">\n {{ 'By`user`' | translate }}\n </div>\n <div class=\"card-column-20\">\n {{ 'Tenant ID' | translate }}\n </div>\n </div>\n <ng-template #noManagement>\n <div class=\"d-contents\">\n <div class=\"card-column-50\">\n {{ 'Created' | translate }}\n </div>\n <div class=\"card-column-50\">\n {{ 'By`user`' | translate }}\n </div>\n </div>\n </ng-template>\n </div>\n <div\n class=\"card-actions-group\"\n style=\"min-width: 176px\"\n >\n <div class=\"btn btn-xs invisible\">\n <!--EMPTY by design-->\n </div>\n </div>\n </div>\n </div>\n <!-- END interact-list sticky header END -->\n\n <div\n class=\"col-xs-12 col-sm-6 col-md-4 col-lg-3\"\n *ngIf=\"limitStatus?.isReached\"\n >\n <p\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n >\n <strong>\n {{ limitReachedInfo$ | async }}\n </strong>\n <br />\n <span translate>Please contact your platform administrator.</span>\n </p>\n </div>\n\n <ng-container *ngFor=\"let singleRequest of deviceRequestList.data\">\n <div class=\"col-xs-12 col-sm-6 col-md-4 col-lg-3\">\n <div class=\"card\">\n <div class=\"card-header separator\">\n <div class=\"card-icon\">\n <i\n [class]=\"statusProps[singleRequest.status].cls\"\n [c8yIcon]=\"statusProps[singleRequest.status].icon\"\n ></i>\n </div>\n <p\n class=\"card-title text-truncate\"\n title=\"{{ singleRequest.id }}\"\n >\n {{ singleRequest.id }}\n </p>\n </div>\n\n <div class=\"card-block text-center card-column-30\">\n <span\n class=\"text-label-small\"\n translate\n >\n Status\n </span>\n <p>\n <i\n class=\"icon-spin text-primary\"\n c8yIcon=\"refresh\"\n *ngIf=\"singleRequest.status === status.WAITING_FOR_CONNECTION\"\n ></i>\n {{ statusProps[singleRequest.status].label | translate }}\n </p>\n </div>\n\n <ng-container *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\">\n <div\n class=\"card-block text-center card-column-30 p-t-0\"\n [ngClass]=\"{ 'p-b-0': !shouldShowSecurityTokenInput(singleRequest) }\"\n *ngIf=\"showTokenInputBasedOnSecurityMode()\"\n >\n <ng-container *ngIf=\"shouldShowSecurityTokenInput(singleRequest)\">\n <span\n class=\"text-label-small\"\n *ngIf=\"gridOrList !== 'interact-list'\"\n translate\n >\n Security token\n </span>\n <input\n class=\"form-control\"\n type=\"text\"\n [(ngModel)]=\"singleRequest.securityToken\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'A1e3gh5ds' }\"\n [required]=\"requireSecurityToken\"\n />\n </ng-container>\n </div>\n\n <div\n class=\"card-actions-group d-flex a-i-center j-c-center\"\n style=\"min-width: 176px\"\n >\n <button\n class=\"btn btn-sm\"\n title=\"{{\n singleRequest.status === status.PENDING_ACCEPTANCE\n ? ('Remove' | translate)\n : ('Cancel' | translate)\n }}\"\n type=\"button\"\n [ngClass]=\"{\n 'btn-danger': singleRequest.status === status.PENDING_ACCEPTANCE,\n 'btn-default': singleRequest.status !== status.PENDING_ACCEPTANCE\n }\"\n (click)=\"delete(singleRequest.id)\"\n [disabled]=\"isLoading\"\n >\n <span *ngIf=\"singleRequest.status === status.PENDING_ACCEPTANCE\">\n {{ 'Remove' | translate }}\n </span>\n <span *ngIf=\"singleRequest.status !== status.PENDING_ACCEPTANCE\">\n {{ 'Cancel' | translate }}\n </span>\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Accept' | translate }}\"\n type=\"button\"\n (click)=\"accept(singleRequest)\"\n *ngIf=\"singleRequest.status === status.PENDING_ACCEPTANCE\"\n [disabled]=\"\n isLoading ||\n limitStatus?.isReached ||\n (!singleRequest.securityToken && requireSecurityToken)\n \"\n >\n {{ 'Accept' | translate }}\n </button>\n </div>\n </ng-container>\n\n <div class=\"card-footer separator text-center card-column-50\">\n <small\n class=\"d-contents\"\n *ngIf=\"isManagementTenant; else noManagement\"\n >\n <div\n class=\"d-contents\"\n *ngIf=\"singleRequest.creationTime && singleRequest.owner\"\n >\n <span class=\"card-column-50\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n Created on`date`\n </span>\n <span data-cy=\"device-registration--creation-date\">\n {{ singleRequest.creationTime | c8yDate }}\n </span>\n </span>\n <span class=\"card-column-30 text-truncate\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n by`user`\n </span>\n <span\n title=\"{{ singleRequest.owner }}\"\n data-cy=\"device-registration--created-by\"\n >\n {{ singleRequest.owner }}\n </span>\n </span>\n <span class=\"card-column-20\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n in`tenant`\n </span>\n <span>{{ singleRequest.tenantId }}</span>\n </span>\n </div>\n <div\n class=\"d-contents\"\n *ngIf=\"!singleRequest.creationTime || !singleRequest.owner\"\n >\n <div class=\"card-column-50\"></div>\n <div class=\"card-column-30\"></div>\n <span\n class=\"text-label-small\"\n translate\n >\n Created in`tenant`\n </span>\n <div class=\"card-column-20\">\n <span>\n {{ singleRequest.tenantId }}\n </span>\n </div>\n </div>\n </small>\n <ng-template #noManagement>\n <small class=\"d-contents\">\n <span class=\"card-column-50\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n Created on`date`\n </span>\n <span data-cy=\"device-registration--creation-date\">\n {{ singleRequest.creationTime | c8yDate }}\n </span>\n </span>\n <span class=\"card-column-50 text-truncate\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n by`user`\n </span>\n <span\n title=\"{{ singleRequest.owner }}\"\n data-cy=\"device-registration--created-by\"\n >\n {{ singleRequest.owner }}\n </span>\n </span>\n </small>\n </ng-template>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n <c8y-load-more\n [paging]=\"deviceRequestList.paging\"\n [hidden]=\"true\"\n (onLoad)=\"updateList($event)\"\n ></c8y-load-more>\n </ng-container>\n\n <ng-template #noData>\n <div class=\"c8y-empty-state m-t-40 text-center\">\n <h1 class=\"c8y-icon c8y-icon-device-connect c8y-icon-duocolor\"></h1>\n <ng-container *ngIf=\"limitStatus?.isReached; else limitNotReached\">\n <h3>\n {{ limitReachedInfo$ | async }}\n </h3>\n <p translate>Please contact your platform administrator.</p>\n </ng-container>\n <ng-template #limitNotReached>\n <h3 translate>No pending registrations to display.</h3>\n <p\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n translate\n >\n Use the \"Register device\" dropdown in the top right corner.\n </p>\n </ng-template>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n", dependencies: [{ kind: "directive", type: i4.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: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "component", type: i2.LoadMoreComponent, selector: "c8y-load-more", inputs: ["paging", "useIntersection", "hidden", "container", "class", "maxIterations", "noMoreDataHint", "loadingTemplate", "hideNoMoreDataHint", "loadNextLabel", "loadingLabel"], outputs: ["onLoad"] }, { kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i6.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: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i2.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "component", type: i2.ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: i7.RegisterDeviceDropdownComponent, selector: "c8y-register-device-dropdown" }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceRegistrationViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-device-registration-view', template: "<ng-container *ngIf=\"deviceRequests$ | async as deviceRequestList\">\n <c8y-title>\n {{ 'Device registration' | translate }}\n <small *ngIf=\"deviceRequestList.data.length === 1\">1 {{ 'new device' | translate }}</small>\n <small *ngIf=\"deviceRequestList.data.length > 1\">\n {{ deviceRequestList.data.length }} {{ 'new devices' | translate }}\n </small>\n </c8y-title>\n\n <c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'exchange'\"\n [label]=\"'Devices' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-connect'\"\n [label]=\"'Device registration' | translate\"\n ></c8y-breadcrumb-item>\n </c8y-breadcrumb>\n\n <c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n >\n <c8y-list-display-switch (onListClassChange)=\"displayMode($event)\"></c8y-list-display-switch>\n </c8y-action-bar-item>\n\n <ng-container *ngIf=\"limit$ | async as limitStatus\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"10\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Accept all' | translate }}\"\n type=\"button\"\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n (click)=\"acceptAll()\"\n [disabled]=\"canAcceptAll() || limitStatus?.isReached\"\n >\n <i [c8yIcon]=\"'check'\"></i>\n {{ 'Accept all' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"9\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadAll()\"\n [disabled]=\"isLoading\"\n >\n <i\n [c8yIcon]=\"'refresh'\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item\n [placement]=\"'right'\"\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n >\n <c8y-register-device-dropdown></c8y-register-device-dropdown>\n </c8y-action-bar-item>\n\n <c8y-help\n src=\"/docs/device-management-application/registering-devices/#registering-devices\"\n ></c8y-help>\n\n <ng-container *ngIf=\"deviceRequestList.data.length > 0; else noData\">\n <div\n class=\"card-group\"\n [ngClass]=\"gridOrList\"\n >\n <!-- START interact-list sticky header START -->\n <div\n class=\"page-sticky-header hidden-xs\"\n *ngIf=\"gridOrList === 'interact-list'\"\n >\n <div class=\"d-flex\">\n <div class=\"card-header p-l-40\">\n <p translate>Device</p>\n </div>\n <div class=\"card-block card-column-30 p-l-0 m-l-8\">\n <p translate>Status</p>\n </div>\n <div\n class=\"card-block card-column-30 p-0\"\n *ngIf=\"showTokenInputBasedOnSecurityMode()\"\n >\n <p translate>Security token</p>\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'Security token is required if the connected device uses it.' | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n ></button>\n </div>\n <div class=\"card-footer card-column-50\">\n <div\n class=\"d-contents\"\n *ngIf=\"isManagementTenant; else noManagement\"\n >\n <div class=\"card-column-50\">\n {{ 'Created' | translate }}\n </div>\n <div class=\"card-column-30\">\n {{ 'By`user`' | translate }}\n </div>\n <div class=\"card-column-20\">\n {{ 'Tenant ID' | translate }}\n </div>\n </div>\n <ng-template #noManagement>\n <div class=\"d-contents\">\n <div class=\"card-column-50\">\n {{ 'Created' | translate }}\n </div>\n <div class=\"card-column-50\">\n {{ 'By`user`' | translate }}\n </div>\n </div>\n </ng-template>\n </div>\n <div\n class=\"card-actions-group\"\n style=\"min-width: 176px\"\n >\n <div class=\"btn btn-xs invisible\">\n <!--EMPTY by design-->\n </div>\n </div>\n </div>\n </div>\n <!-- END interact-list sticky header END -->\n\n <div\n class=\"col-xs-12 col-sm-6 col-md-4 col-lg-3\"\n *ngIf=\"limitStatus?.isReached\"\n >\n <p\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n >\n <strong>\n {{ limitReachedInfo$ | async }}\n </strong>\n <br />\n <span translate>Please contact your platform administrator.</span>\n </p>\n </div>\n\n <ng-container *ngFor=\"let singleRequest of deviceRequestList.data\">\n <div class=\"col-xs-12 col-sm-6 col-md-4 col-lg-3\">\n <div class=\"card\">\n <div class=\"card-header separator\">\n <div class=\"card-icon\">\n <i\n [class]=\"statusProps[singleRequest.status].cls\"\n [c8yIcon]=\"statusProps[singleRequest.status].icon\"\n ></i>\n </div>\n <p\n class=\"card-title text-truncate\"\n title=\"{{ singleRequest.id }}\"\n >\n {{ singleRequest.id }}\n </p>\n </div>\n\n <div class=\"card-block text-center card-column-30\">\n <span\n class=\"text-label-small\"\n translate\n >\n Status\n </span>\n <p>\n <i\n class=\"icon-spin text-primary\"\n c8yIcon=\"refresh\"\n *ngIf=\"singleRequest.status === status.WAITING_FOR_CONNECTION\"\n ></i>\n {{ statusProps[singleRequest.status].label | translate }}\n </p>\n </div>\n\n <ng-container *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\">\n <div\n class=\"card-block text-center card-column-30 p-t-0\"\n [ngClass]=\"{ 'p-b-0': !shouldShowSecurityTokenInput(singleRequest) }\"\n *ngIf=\"showTokenInputBasedOnSecurityMode()\"\n >\n <ng-container *ngIf=\"shouldShowSecurityTokenInput(singleRequest)\">\n <span\n class=\"text-label-small\"\n *ngIf=\"gridOrList !== 'interact-list'\"\n translate\n >\n Security token\n </span>\n <input\n class=\"form-control\"\n type=\"text\"\n [(ngModel)]=\"singleRequest.securityToken\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'A1e3gh5ds' }\"\n [required]=\"requireSecurityToken\"\n />\n </ng-container>\n </div>\n\n <div\n class=\"card-actions-group d-flex a-i-center j-c-center\"\n style=\"min-width: 176px\"\n >\n <button\n class=\"btn btn-sm\"\n title=\"{{\n singleRequest.status === status.PENDING_ACCEPTANCE\n ? ('Remove' | translate)\n : ('Cancel' | translate)\n }}\"\n type=\"button\"\n [ngClass]=\"{\n 'btn-danger': singleRequest.status === status.PENDING_ACCEPTANCE,\n 'btn-default': singleRequest.status !== status.PENDING_ACCEPTANCE\n }\"\n (click)=\"delete(singleRequest.id)\"\n [disabled]=\"isLoading\"\n >\n <span *ngIf=\"singleRequest.status === status.PENDING_ACCEPTANCE\">\n {{ 'Remove' | translate }}\n </span>\n <span *ngIf=\"singleRequest.status !== status.PENDING_ACCEPTANCE\">\n {{ 'Cancel' | translate }}\n </span>\n </button>\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Accept' | translate }}\"\n type=\"button\"\n (click)=\"accept(singleRequest)\"\n *ngIf=\"singleRequest.status === status.PENDING_ACCEPTANCE\"\n [disabled]=\"\n isLoading ||\n limitStatus?.isReached ||\n (!singleRequest.securityToken && requireSecurityToken)\n \"\n >\n {{ 'Accept' | translate }}\n </button>\n </div>\n </ng-container>\n\n <div class=\"card-footer separator text-center card-column-50\">\n <small\n class=\"d-contents\"\n *ngIf=\"isManagementTenant; else noManagement\"\n >\n <div\n class=\"d-contents\"\n *ngIf=\"singleRequest.creationTime && singleRequest.owner\"\n >\n <span class=\"card-column-50\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n Created on`date`\n </span>\n <span data-cy=\"device-registration--creation-date\">\n {{ singleRequest.creationTime | c8yDate }}\n </span>\n </span>\n <span class=\"card-column-30 text-truncate\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n by`user`\n </span>\n <span\n title=\"{{ singleRequest.owner }}\"\n data-cy=\"device-registration--created-by\"\n >\n {{ singleRequest.owner }}\n </span>\n </span>\n <span class=\"card-column-20\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n in`tenant`\n </span>\n <span>{{ singleRequest.tenantId }}</span>\n </span>\n </div>\n <div\n class=\"d-contents\"\n *ngIf=\"!singleRequest.creationTime || !singleRequest.owner\"\n >\n <div class=\"card-column-50\"></div>\n <div class=\"card-column-30\"></div>\n <span\n class=\"text-label-small\"\n translate\n >\n Created in`tenant`\n </span>\n <div class=\"card-column-20\">\n <span>\n {{ singleRequest.tenantId }}\n </span>\n </div>\n </div>\n </small>\n <ng-template #noManagement>\n <small class=\"d-contents\">\n <span class=\"card-column-50\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n Created on`date`\n </span>\n <span data-cy=\"device-registration--creation-date\">\n {{ singleRequest.creationTime | c8yDate }}\n </span>\n </span>\n <span class=\"card-column-50 text-truncate\">\n <span\n class=\"text-label-small m-l-4 m-r-4\"\n translate\n >\n by`user`\n </span>\n <span\n title=\"{{ singleRequest.owner }}\"\n data-cy=\"device-registration--created-by\"\n >\n {{ singleRequest.owner }}\n </span>\n </span>\n </small>\n </ng-template>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n <c8y-load-more\n [paging]=\"deviceRequestList.paging\"\n [hidden]=\"true\"\n (onLoad)=\"updateList($event)\"\n ></c8y-load-more>\n </ng-container>\n\n <ng-template #noData>\n <div class=\"c8y-empty-state m-t-40 text-center\">\n <h1 class=\"c8y-icon c8y-icon-device-connect c8y-icon-duocolor\"></h1>\n <ng-container *ngIf=\"limitStatus?.isReached; else limitNotReached\">\n <h3>\n {{ limitReachedInfo$ | async }}\n </h3>\n <p translate>Please contact your platform administrator.</p>\n </ng-container>\n <ng-template #limitNotReached>\n <h3 translate>No pending registrations to display.</h3>\n <p\n *c8yIfAllowed=\"['ROLE_DEVICE_CONTROL_ADMIN']\"\n translate\n >\n Use the \"Register device\" dropdown in the top right corner.\n </p>\n </ng-template>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n" }]
}], ctorParameters: () => [{ type: i1.RegisterDeviceService }, { type: i2.DeviceBootstrapRealtimeService }, { type: i2.TenantUiService }, { type: i2.ModalService }, { type: i3.TranslateService }, { type: i2.OptionsService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlLXJlZ2lzdHJhdGlvbi12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3JlZ2lzdGVyLWRldmljZS9kZXZpY2UtcmVnaXN0cmF0aW9uLXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vcmVnaXN0ZXItZGV2aWNlL2RldmljZS1yZWdpc3RyYXRpb24tdmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUM3RCxPQUFPLEVBQ0wsOEJBQThCLEVBQzlCLHdCQUF3QixFQUl6QixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsZUFBZSxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RCxPQUFPLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkUsT0FBTyxFQUNMLDhCQUE4QixFQUU5QixlQUFlLEVBQ2YsWUFBWSxFQUNaLE1BQU0sRUFDTixPQUFPLEVBQ1AsY0FBYyxFQUNmLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNuQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7Ozs7Ozs7O0FBTXZELE1BQU0sT0FBTywrQkFBK0I7SUF3QzFDLFlBQ1UscUJBQTRDLEVBQzVDLHdCQUF3RCxFQUN4RCxlQUFnQyxFQUNoQyxZQUEwQixFQUMxQixnQkFBa0MsRUFDbEMsY0FBOEI7UUFMOUIsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUF1QjtRQUM1Qyw2QkFBd0IsR0FBeEIsd0JBQXdCLENBQWdDO1FBQ3hELG9CQUFlLEdBQWYsZUFBZSxDQUFpQjtRQUNo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QztRQUMvQixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLEVBQUUsS0FBSyw4QkFBOEIsQ0FBQyxPQUFPLENBQUM7SUFDekYsQ0FBQzsrR0FyS1UsK0JBQStCO21HQUEvQiwrQkFBK0Isb0VDM0I1Qyx3MGNBdVlBOzs0RkQ1V2EsK0JBQStCO2tCQUozQyxTQUFTOytCQUNFLDhCQUE4QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIERldmljZVJlZ2lzdHJhdGlvblNlY3VyaXR5TW9kZSxcbiAgRGV2aWNlUmVnaXN0cmF0aW9uU3RhdHVzLFxuICBJRGV2aWNlUmVnaXN0cmF0aW9uLFxuICBJRGV2aWNlUmVnaXN0cmF0aW9uTGltaXQsXG4gIFBhZ2luZ1xufSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIERldmljZUJvb3RzdHJhcFJlYWx0aW1lU2VydmljZSxcbiAgSVJlYWx0aW1lRGV2aWNlQm9vdHN0cmFwLFxuICBUZW5hbnRVaVNlcnZpY2UsXG4gIE1vZGFsU2VydmljZSxcbiAgU3RhdHVzLFxuICBnZXR0ZXh0LFxuICBPcHRpb25zU2VydmljZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IFJlZ2lzdGVyRGV2aWNlU2VydmljZSB9IGZyb20gJy4vcmVnaXN0ZXItZGV2aWNlLnNlcnZpY2UnO1xuaW1wb3J0IHsgc29ydEJ5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWRldmljZS1yZWdpc3RyYXRpb24tdmlldycsXG4gIHRlbXBsYXRlVXJsOiAnZGV2aWNlLXJlZ2lzdHJhdGlvbi12aWV3LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBEZXZpY2VSZWdpc3RyYXRpb25WaWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBkZXZpY2VSZXF1ZXN0cyQ6IE9ic2VydmFibGU8e1xuICAgIGRhdGE6IElEZXZpY2VSZWdpc3RyYXRpb25bXTtcbiAgICBwYWdpbmc/OiBQYWdpbmc8SURldmljZVJlZ2lzdHJhdGlvbj47XG4gIH0+O1xuICBsaW1pdCQ6IE9ic2VydmFibGU8SURldmljZVJlZ2lzdHJhdGlvbkxpbWl0PjtcbiAgbGltaXRSZWFjaGVkSW5mbyQ6IE9ic2VydmFibGU8c3RyaW5nPjtcbiAgcmVxdWlyZVNlY3VyaXR5VG9rZW4gPSBmYWxzZTtcbiAgaXNNYW5hZ2VtZW50VGVuYW50ID0gZmFsc2U7XG4gIGlzTG9hZGluZyA9IGZhbHNlO1xuICBncmlkT3JMaXN0OiAnaW50ZXJhY3QtbGlzdCcgfCAnaW50ZXJhY3QtZ3JpZCcgPSAnaW50ZXJhY3QtZ3JpZCc7XG4gIHN0YXR1cyA9IERldmljZVJlZ2lzdHJhdGlvblN0YXR1cztcblxuICByZWFkb25seSBzdGF0dXNQcm9wcyA9IHtcbiAgICBbRGV2aWNlUmVnaXN0cmF0aW9uU3RhdHVzLldBSVRJTkdfRk9SX0NPTk5FQ1RJT05dOiB7XG4gICAgICBsYWJlbDogZ2V0dGV4dCgnV2FpdGluZyBmb3IgY29ubmVjdGlvbicpLFxuICAgICAgaWNvbjogJ3VubGluaycsXG4gICAgICBjbHM6ICd0ZXh0LWRhbmdlcidcbiAgICB9LFxuICAgIFtEZXZpY2VSZWdpc3RyYXRpb25TdGF0dXMuUEVORElOR19BQ0NFUFRBTkNFXToge1xuICAgICAgbGFiZWw6IGdldHRleHQoJ1BlbmRpbmcgYWNjZXB0YW5jZScpLFxuICAgICAgaWNvbjogJ2NpcmNsZScsXG4gICAgICBjbHM6ICd0ZXh0LWluZm8nXG4gICAgfSxcbiAgICBbRGV2aWNlUmVnaXN0cmF0aW9uU3RhdHVzLkFDQ0VQVEVEXToge1xuICAgICAgbGFiZWw6IGdldHRleHQoJ0FjY2VwdGVkJyksXG4gICAgICBpY29uOiAnY2hlY2stY2lyY2xlJyxcbiAgICAgIGNsczogJ3RleHQtc3VjY2VzcydcbiAgICB9LFxuICAgIFtEZXZpY2VSZWdpc3RyYXRpb25TdGF0dXMuQkxPQ0tFRF06IHtcbiAgICAgIGxhYmVsOiBnZXR0ZXh0KCdCbG9ja2VkJyksXG4gICAgICBpY29uOiAnYmFuJyxcbiAgICAgIGNsczogJ3RleHQtZGFuZ2VyJ1xuICAgIH1cbiAgfTtcblxuICBwcml2YXRlIHVuc3Vic2NyaWJlJDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3NlY3VyaXR5VG9rZW5Qb2xpY3k6IEJlaGF2aW9yU3ViamVjdDxEZXZpY2VSZWdpc3RyYXRpb25TZWN1cml0eU1vZGU+ID1cbiAgICBuZXcgQmVoYXZpb3JTdWJqZWN0KERldmljZVJlZ2lzdHJhdGlvblNlY3VyaXR5TW9kZS5PUFRJT05BTCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWdpc3RlckRldmljZVNlcnZpY2U6IFJlZ2lzdGVyRGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIGJvb3RzdHJhcFJlYWx0aW1lU2VydmljZTogRGV2aWNlQm9vdHN0cmFwUmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgdGVuYW50VWlTZXJ2aWNlOiBUZW5hbnRVaVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtb2RhbFNlcnZpY2U6IE1vZGFsU2VydmljZSxcbiAgICBwcml2YXRlIHRyYW5zbGF0ZVNlcnZpY2U6IFRyYW5zbGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBvcHRpb25zU2VydmljZTogT3B0aW9uc1NlcnZpY2VcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMubG9hZEFsbCgpO1xuICAgIHRoaXMuc2V0SXNNYW5hZ2VtZW50VGVuYW50KCk7XG4gICAgdGhpcy5zZXRSZXF1aXJlU2VjdXJpdHlUb2tlbigpO1xuXG4gICAgdGhpcy5kZXZpY2VSZXF1ZXN0cyQgPSB0aGlzLnJlZ2lzdGVyRGV2aWNlU2VydmljZS5kZXZpY2VSZWdpc3RyYXRpb25SZXF1ZXN0cyQucGlwZShcbiAgICAgIG1hcChyZXEgPT4gKHtcbiAgICAgICAgZGF0YTogc29ydEJ5KHJlcS5kYXRhLCBbXG4gICAgICAgICAgKHsgc3RhdHVzIH0pID0+IChzdGF0dXMgPT09IERldmljZVJlZ2lzdHJhdGlvblN0YXR1cy5QRU5ESU5HX0FDQ0VQVEFOQ0UgPyAwIDogMSksXG4gICAgICAgICAgJy1jcmVhdGlvblRpbWUnXG4gICAgICAgIF0pLFxuICAgICAgICBwYWdpbmc6IHJlcS5wYWdpbmdcbiAgICAgIH0pKVxuICAgICk7XG4gICAgdGhpcy5saW1pdCQgPSB0aGlzLnJlZ2lzdGVyRGV2aWNlU2VydmljZS5saW1pdCQ7XG4gICAgdGhpcy5saW1pdFJlYWNoZWRJbmZvJCA9IHRoaXMubGltaXQkLnBpcGUoXG4gICAgICBmaWx0ZXIoZGV2aWNlUmVnaXN0cmF0aW9uTGltaXQgPT4gZGV2aWNlUmVnaXN0cmF0aW9uTGltaXQuaXNSZWFjaGVkKSxcbiAgICAgIHN3aXRjaE1hcCgoeyBsaW1pdCB9KSA9PlxuICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2Uuc3RyZWFtKFxuICAgICAgICAgIGdldHRleHQoXG4gICAgICAgICAgICAnWW91IHJlYWNoZWQgdGhlIGxpbWl0IG9mIHt7IG1