UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

212 lines (207 loc) 18.3 kB
import * as i0 from '@angular/core'; import { Input, Component } from '@angular/core'; import * as i3 from '@c8y/ngx-components'; import { CoreModule, gettext as gettext$1, C8yTranslatePipe, TitleComponent, ActionBarItemComponent, C8yTranslateDirective, IconDirective, LoadingComponent } from '@c8y/ngx-components'; import * as i1$1 from '@c8y/ngx-components/remote-access/data'; import * as i2$1 from '@angular/router'; import * as i4 from '@angular/common'; import { NgIf, NgClass } from '@angular/common'; import { saveAs } from 'file-saver'; import * as i2 from 'ngx-bootstrap/modal'; import * as i1 from '@angular/forms'; import { Validators } from '@angular/forms'; import { gettext } from '@c8y/ngx-components/gettext'; import { BehaviorSubject, combineLatest, defer } from 'rxjs'; import { filter, map, distinctUntilChanged } from 'rxjs/operators'; class VncCredentialsPromptComponent { constructor(formBuilder, modalRef) { this.formBuilder = formBuilder; this.modalRef = modalRef; this.title = gettext('VNC credentials'); this.types = []; this.result = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); this.showUsername = false; this.form = this.initForm(); } ngOnInit() { this.showUsername = this.types.includes('username'); this.form = this.initForm(); } initForm() { return this.formBuilder.group({ username: [undefined, this.showUsername ? [Validators.required] : []], password: [undefined, [Validators.required]] }); } cancel() { this._reject(); } save() { this._resolve(this.form.value); } submit() { if (!this.form.valid) { return; } this.modalRef.hide(); this.save(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VncCredentialsPromptComponent, deps: [{ token: i1.FormBuilder }, { token: i2.BsModalRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: VncCredentialsPromptComponent, isStandalone: true, selector: "c8y-vnc-credentials-prompt", inputs: { types: "types" }, ngImport: i0, template: "<c8y-modal\n [title]=\"title\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"cancel()\"\n (onClose)=\"save()\"\n [disabled]=\"form.invalid\"\n [labels]=\"{ cancel: 'Cancel', ok: 'Save' }\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'key'\"></span>\n </ng-container>\n <form\n class=\"p-24\"\n [formGroup]=\"form\"\n (submit)=\"submit()\"\n >\n <c8y-form-group *ngIf=\"showUsername\">\n <label\n for=\"username\"\n translate\n >\n Username\n </label>\n <input\n class=\"form-control\"\n id=\"username\"\n name=\"username\"\n type=\"text\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'admin' }\"\n formControlName=\"username\"\n />\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group>\n <label\n for=\"password\"\n translate\n >\n Password\n </label>\n <input\n class=\"form-control\"\n id=\"password\"\n name=\"password\"\n type=\"password\"\n formControlName=\"password\"\n />\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n\n <button type=\"submit\" class=\"hidden\">hidden submit</button>\n </form>\n</c8y-modal>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i3.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i3.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VncCredentialsPromptComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-vnc-credentials-prompt', standalone: true, imports: [CoreModule, NgIf], template: "<c8y-modal\n [title]=\"title\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"cancel()\"\n (onClose)=\"save()\"\n [disabled]=\"form.invalid\"\n [labels]=\"{ cancel: 'Cancel', ok: 'Save' }\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'key'\"></span>\n </ng-container>\n <form\n class=\"p-24\"\n [formGroup]=\"form\"\n (submit)=\"submit()\"\n >\n <c8y-form-group *ngIf=\"showUsername\">\n <label\n for=\"username\"\n translate\n >\n Username\n </label>\n <input\n class=\"form-control\"\n id=\"username\"\n name=\"username\"\n type=\"text\"\n [placeholder]=\"'e.g. {{ example }}' | translate: { example: 'admin' }\"\n formControlName=\"username\"\n />\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group>\n <label\n for=\"password\"\n translate\n >\n Password\n </label>\n <input\n class=\"form-control\"\n id=\"password\"\n name=\"password\"\n type=\"password\"\n formControlName=\"password\"\n />\n <c8y-messages></c8y-messages>\n </c8y-form-group>\n\n <button type=\"submit\" class=\"hidden\">hidden submit</button>\n </form>\n</c8y-modal>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.BsModalRef }], propDecorators: { types: [{ type: Input }] } }); class VncViewerComponent { constructor(remoteAccess, activatedRoute, modalService) { this.remoteAccess = remoteAccess; this.activatedRoute = activatedRoute; this.modalService = modalService; this.titlePrefix = gettext$1('VNC viewer'); this.title = ''; this.container = null; this.powerCapability = false; this.status = 'connecting'; this.container$ = new BehaviorSubject(null); const container$ = this.container$.pipe(filter(Boolean)); const configurationId$ = this.activatedRoute.params.pipe(map(params => params.configurationId), filter(Boolean), distinctUntilChanged()); const deviceId$ = this.activatedRoute.parent.params.pipe(map(params => params.id), filter(Boolean), distinctUntilChanged()); this.connectionSubscription = combineLatest([ container$, deviceId$, configurationId$, defer(() => this.getNoVNCClient()) ]).subscribe(([container, deviceId, configurationId, noVNC]) => { this.disconnectFromOldSession(); this.connect(container, deviceId, configurationId, noVNC); }); } ngOnDestroy() { this.connectionSubscription?.unsubscribe(); this.disconnectFromOldSession(); } ngAfterViewInit() { this.container$.next(document.getElementById('vnc-screen')); } disconnectFromOldSession() { this.powerCapability = false; this.title = ''; if (!this.noVNCClient) { return; } this.noVNCClient.disconnect(); delete this.noVNCClient; } connect(container, deviceId, configId, noVNC) { this.container = container; this.changeStatus('connecting'); const options = { wsProtocols: ['binary'] }; const uri = this.remoteAccess.getWebSocketUri(deviceId, configId); this.noVNCClient = new noVNC(container, uri, options); this.noVNCClient.resizeSession = true; this.noVNCClient.scaleViewport = true; this.noVNCClient.showDotCursor = true; this.noVNCClient.viewOnly = false; this.noVNCClient.qualityLevel = 6; // need to set compressionLevel to something different than the default 2 as 2 seems to be causing issues.. this.noVNCClient.compressionLevel = 9; this.noVNCClient.addEventListener('connect', _e => { this.changeStatus('connected'); this.noVNCClient.focus(); }); this.noVNCClient.addEventListener('credentialsrequired', e => { this.requestCredentials(e.detail.types); }); this.noVNCClient.addEventListener('desktopname', e => { this.title = e.detail.name; }); this.noVNCClient.addEventListener('disconnect', () => { this.changeStatus('disconnected'); }); this.noVNCClient.addEventListener('capabilities', e => { this.powerCapability = e.detail.capabilities.power; }); } downloadScreenshot() { this.noVNCClient.toBlob(blob => { const date = new Date().toISOString(); saveAs(blob, `screenshot-${this.title}-${date}.png`); }, 'image/png', 1); } changeStatus(status) { this.status = status; } toggleFullscreen() { if (document.fullscreenElement) { document.exitFullscreen(); } else { this.container.requestFullscreen(); } } sendCtrlAltDel() { this.noVNCClient.sendCtrlAltDel(); } sendShutDown() { this.noVNCClient.machineShutdown(); } sendReset() { this.noVNCClient.machineReset(); } sendReboot() { this.noVNCClient.machineReboot(); } async getNoVNCClient() { const lib = await import('@novnc/novnc/lib/rfb'); if (typeof lib.default === 'function') { return lib.default; } const libDefault = lib.default; if (typeof libDefault.default === 'function') { return libDefault.default; } throw new Error('NoVNC library not found'); } async requestCredentials(types) { const modalRef = this.modalService.show(VncCredentialsPromptComponent, { ignoreBackdropClick: true, keyboard: false, initialState: { types: types } }); try { const { username, password } = await modalRef.content.result; this.noVNCClient.sendCredentials({ username, password, target: undefined }); } catch (e) { this.noVNCClient.disconnect(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VncViewerComponent, deps: [{ token: i1$1.RemoteAccessService }, { token: i2$1.ActivatedRoute }, { token: i2.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: VncViewerComponent, isStandalone: true, selector: "c8y-vnc-viewer", ngImport: i0, template: "<c8y-title>{{ titlePrefix | translate }}: {{ title | translate }}</c8y-title>\n\n<ng-container *ngIf=\"status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"downloadScreenshot()\"\n >\n <i [c8yIcon]=\"'download'\"></i>\n <span translate>Screenshot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendCtrlAltDel()\"\n >\n <i [c8yIcon]=\"'keyboard'\"></i>\n <span translate>Send Ctrl+Alt+Del</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<ng-container *ngIf=\"powerCapability && status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendShutDown()\"\n >\n <i [c8yIcon]=\"'shutdown'\"></i>\n <span translate>Shutdown</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReboot()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reboot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReset()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reset</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-loading *ngIf=\"status === 'connecting'\"></c8y-loading>\n\n<div\n class=\"content-fullpage\"\n [ngClass]=\"{ hidden: status !== 'connected' }\"\n>\n <div\n class=\"inner-scroll\"\n id=\"vnc-screen\"\n ></div>\n</div>\n", dependencies: [{ kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VncViewerComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-vnc-viewer', standalone: true, imports: [ C8yTranslatePipe, TitleComponent, ActionBarItemComponent, C8yTranslateDirective, IconDirective, NgIf, NgClass, LoadingComponent ], template: "<c8y-title>{{ titlePrefix | translate }}: {{ title | translate }}</c8y-title>\n\n<ng-container *ngIf=\"status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"toggleFullscreen()\"\n >\n <i [c8yIcon]=\"'expand'\"></i>\n <span translate>Fullscreen</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n (click)=\"downloadScreenshot()\"\n >\n <i [c8yIcon]=\"'download'\"></i>\n <span translate>Screenshot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendCtrlAltDel()\"\n >\n <i [c8yIcon]=\"'keyboard'\"></i>\n <span translate>Send Ctrl+Alt+Del</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<ng-container *ngIf=\"powerCapability && status === 'connected'\">\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendShutDown()\"\n >\n <i [c8yIcon]=\"'shutdown'\"></i>\n <span translate>Shutdown</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReboot()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reboot</span>\n </button>\n </c8y-action-bar-item>\n\n <c8y-action-bar-item [placement]=\"'more'\">\n <button\n class=\"btn btn-link\"\n (click)=\"sendReset()\"\n >\n <i [c8yIcon]=\"'reset'\"></i>\n <span translate>Reset</span>\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-loading *ngIf=\"status === 'connecting'\"></c8y-loading>\n\n<div\n class=\"content-fullpage\"\n [ngClass]=\"{ hidden: status !== 'connected' }\"\n>\n <div\n class=\"inner-scroll\"\n id=\"vnc-screen\"\n ></div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1$1.RemoteAccessService }, { type: i2$1.ActivatedRoute }, { type: i2.BsModalService }] }); /** * Generated bundle index. Do not edit. */ export { VncViewerComponent }; //# sourceMappingURL=c8y-ngx-components-remote-access-vnc-vnc-viewer.mjs.map