@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
163 lines • 76.6 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 { ActivatedRoute } from '@angular/router';
import { GeneralDeviceRegistrationService } from './general/general-device-registration.service';
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 "@angular/router";
import * as i5 from "./general/general-device-registration.service";
import * as i6 from "ngx-bootstrap/popover";
import * as i7 from "@angular/common";
import * as i8 from "@angular/forms";
import * as i9 from "./dropdown/register-device-dropdown.component";
export class DeviceRegistrationViewComponent {
constructor(registerDeviceService, bootstrapRealtimeService, tenantUiService, modalService, translateService, optionsService, activatedRoute, generalRegistration) {
this.registerDeviceService = registerDeviceService;
this.bootstrapRealtimeService = bootstrapRealtimeService;
this.tenantUiService = tenantUiService;
this.modalService = modalService;
this.translateService = translateService;
this.optionsService = optionsService;
this.activatedRoute = activatedRoute;
this.generalRegistration = generalRegistration;
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);
});
this.handleQueryParams();
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
updateList(data) {
this.registerDeviceService.internalListUpdate(data);
}
async handleQueryParams() {
const { externalId, 'one-time-password': oneTimePassword } = this.activatedRoute.snapshot.queryParams;
if (!externalId) {
return;
}
try {
await this.generalRegistration.open({
useEST$: new BehaviorSubject(!!oneTimePassword),
model: {
devicesToCreate: [
{
id: externalId,
oneTimePassword
}
]
}
});
this.loadAll();
}
catch (e) {
// modal closed
}
}
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 }, { token: i4.ActivatedRoute }, { token: i5.GeneralDeviceRegistrationService }], 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: i6.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: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.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: i8.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: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i8.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: i9.RegisterDeviceDropdownComponent, selector: "c8y-register-device-dropdown" }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i7.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 }, { type: i4.ActivatedRoute }, { type: i5.GeneralDeviceRegistrationService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlLXJlZ2lzdHJhdGlvbi12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3JlZ2lzdGVyLWRldmljZS9kZXZpY2UtcmVnaXN0cmF0aW9uLXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vcmVnaXN0ZXItZGV2aWNlL2RldmljZS1yZWdpc3RyYXRpb24tdmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUM3RCxPQUFPLEVBQ0wsOEJBQThCLEVBQzlCLHdCQUF3QixFQUl6QixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsZUFBZSxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM1RCxPQUFPLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkUsT0FBTyxFQUNMLDhCQUE4QixFQUU5QixlQUFlLEVBQ2YsWUFBWSxFQUNaLE1BQU0sRUFDTixPQUFPLEVBQ1AsY0FBYyxFQUNmLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNuQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLGdDQUFnQyxFQUFFLE1BQU0sK0NBQStDLENBQUM7Ozs7Ozs7Ozs7O0FBTWpHLE1BQU0sT0FBTywrQkFBK0I7SUF3QzFDLFlBQ1UscUJBQTRDLEVBQzVDLHdCQUF3RCxFQUN4RCxlQUFnQyxFQUNoQyxZQUEwQixFQUMxQixnQkFBa0MsRUFDbEMsY0FBOEIsRUFDOUIs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cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIERldmljZVJlZ2lzdHJhdGlvblNlY3VyaXR5TW9kZSxcbiAgRGV2aWNlUmVnaXN0cmF0aW9uU3RhdHVzLFxuICBJRGV2aWNlUmVnaXN0cmF0aW9uLFxuICBJRGV2aWNlUmVnaXN0cmF0aW9uTGltaXQsXG4gIFBhZ2luZ1xufSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIERldmljZUJvb3RzdHJhcFJlYWx0aW1lU2VydmljZSxcbiAgSVJlYWx0aW1lRGV2aWNlQm9vdHN0cmFwLFxuICBUZW5hbnRVaVNlcnZpY2UsXG4gIE1vZGFsU2VydmljZSxcbiAgU3RhdHVzLFxuICBnZXR0ZXh0LFxuICBPcHRpb25zU2VydmljZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IFJlZ2lzdGVyRGV2aWNlU2VydmljZSB9IGZyb20gJy4vcmVnaXN0ZXItZGV2aWNlLnNlcnZpY2UnO1xuaW1wb3J0IHsgc29ydEJ5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IFRyYW5zbGF0ZVNlcnZpY2UgfSBmcm9tICdAbmd4LXRyYW5zbGF0ZS9jb3JlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEdlbmVyYWxEZXZpY2VSZWdpc3RyYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9nZW5lcmFsL2dlbmVyYWwtZGV2aWNlLXJlZ2lzdHJhdGlvbi5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWRldmljZS1yZWdpc3RyYXRpb24tdmlldycsXG4gIHRlbXBsYXRlVXJsOiAnZGV2aWNlLXJlZ2lzdHJhdGlvbi12aWV3LmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBEZXZpY2VSZWdpc3RyYXRpb25WaWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBkZXZpY2VSZXF1ZXN0cyQ6IE9ic2VydmFibGU8e1xuICAgIGRhdGE6IElEZXZpY2VSZWdpc3RyYXRpb25bXTtcbiAgICBwYWdpbmc/OiBQYWdpbmc8SURldmljZVJlZ2lzdHJhdGlvbj47XG4gIH0+O1xuICBsaW1pdCQ6IE9ic2VydmFibGU8SURldmljZVJlZ2lzdHJhdGlvbkxpbWl0PjtcbiAgbGltaXRSZWFjaGVkSW5mbyQ6IE9ic2VydmFibGU8c3RyaW5nPjtcbiAgcmVxdWlyZVNlY3VyaXR5VG9rZW4gPSBmYWxzZTtcbiAgaXNNYW5hZ2VtZW50VGVuYW50ID0gZmFsc2U7XG4gIGlzTG9hZGluZyA9IGZhbHNlO1xuICBncmlkT3JMaXN0OiAnaW50ZXJhY3QtbGlzdCcgfCAnaW50ZXJhY3QtZ3JpZCcgPSAnaW50ZXJhY3QtZ3JpZCc7XG4gIHN0YXR1cyA9IERldmljZVJlZ2lzdHJhdGlvblN0YXR1cztcblxuICByZWFkb25seSBzdGF0dXNQcm9wcyA9IHtcbiAgICBbRGV2aWNlUmVnaXN0cmF0aW9uU3RhdHVzLldBSVRJTkdfRk9SX0NPTk5FQ1RJT05dOiB7XG4gICAgICBsYWJlbDogZ2V0dGV4dCgnV2FpdGluZyBmb3IgY29ubmVjdGlvbicpLFxuI