From 241f2a943da8546b5251ed621653b43a106a2b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Thu, 12 Jan 2023 01:35:23 +0100 Subject: [PATCH] Moving observables to promises when possible --- .../components/service/service.component.ts | 20 +++--- src/app/gui/modal/modal.component.html | 7 +- src/app/gui/modal/modal.component.ts | 69 ++++--------------- src/app/gui/uds-gui.service.ts | 12 ++-- src/app/helpers/plugin.ts | 34 ++++----- src/app/pages/services/services.component.ts | 2 +- src/app/uds-api.service-type.ts | 12 ++-- src/app/uds-api.service.ts | 60 +++++++++------- src/styles.scss | 39 ++++++----- 9 files changed, 110 insertions(+), 145 deletions(-) diff --git a/src/app/gui/components/service/service.component.ts b/src/app/gui/components/service/service.component.ts index 26bdbfa..d8507cb 100644 --- a/src/app/gui/components/service/service.component.ts +++ b/src/app/gui/components/service/service.component.ts @@ -141,16 +141,14 @@ export class ServiceComponent implements OnInit { type === 'release' ? django.gettext('Service released') : django.gettext('Service reseted'); - this.api.gui - .yesno(title, django.gettext('Are you sure?')) - .subscribe((val) => { - if (val) { - this.api.action(type, this.service.id).subscribe((service) => { - if (service) { - this.api.gui.alert(title, action); - } - }); - } - }); + this.api.gui.yesno(title, django.gettext('Are you sure?')).then((val) => { + if (val) { + this.api.action(type, this.service.id).then((service) => { + if (service) { + this.api.gui.alert(title, action); + } + }); + } + }); } } diff --git a/src/app/gui/modal/modal.component.html b/src/app/gui/modal/modal.component.html index 7d921c0..ab49619 100644 --- a/src/app/gui/modal/modal.component.html +++ b/src/app/gui/modal/modal.component.html @@ -1,8 +1,7 @@

- - - - + + + diff --git a/src/app/gui/modal/modal.component.ts b/src/app/gui/modal/modal.component.ts index 4552370..1ec55ad 100644 --- a/src/app/gui/modal/modal.component.ts +++ b/src/app/gui/modal/modal.component.ts @@ -15,7 +15,7 @@ export interface ModalData { title: string; body: string; autoclose?: number; - checkClose?: Observable; + checkClose?: Promise; type: DialogType; username?: string; domain?: string; @@ -30,50 +30,17 @@ export interface ModalData { export class ModalComponent implements OnInit { extra: string; subscription: Subscription; - yesno: Observable; - yes: () => void; - no: () => void; - close: () => void; + yesno: Promise; + resolver: (value: boolean) => void; constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: ModalData) { - this.subscription = null; - this.resetCallbacks(); // Notifies on case of yes or not to subscriber - this.yesno = new Observable((observer) => { - this.yes = () => { - observer.next(true); - observer.complete(); - }; - this.no = () => { - observer.next(false); - observer.complete(); - }; - this.close = () => { - this.doClose(); - observer.next(false); - observer.complete(); - }; - const self = this; - return {unsubscribe: () => self.resetCallbacks()}; + this.yesno = new Promise((resolve) => { + this.resolver = resolve; }); } - resetCallbacks() { - this.yes = this.no = () => this.close(); - this.close = () => this.doClose(); - } - - /** - * Invoked on closed modal component - * This ensures that we stop subscription to interval - */ - closed(): void { - if (this.subscription !== null) { - this.subscription.unsubscribe(); - } - } - - doClose(): void { + close() { this.dialogRef.close(); } @@ -86,13 +53,13 @@ export class ModalComponent implements OnInit { this.extra = ' (' + Math.floor(miliseconds / 1000) + ' ' + django.gettext('seconds') + ') '; } - initAlert() { + async initAlert(): Promise { if (this.data.autoclose > 0) { this.dialogRef.afterClosed().subscribe(res => { - this.closed(); + this.close(); }); this.setExtra(this.data.autoclose); - this.subscription = interval(1000).subscribe(n => { + interval(1000).subscribe(n => { const rem = this.data.autoclose - (n + 1) * 1000; this.setExtra(rem); if (rem <= 0) { @@ -103,26 +70,14 @@ export class ModalComponent implements OnInit { this.dialogRef.close(); }, this.data.autoclose);*/ } else if (this.data.checkClose) { - this.dialogRef.afterClosed().subscribe(res => { - this.closed(); - }); - this.subscription = this.data.checkClose.subscribe(res => { - // Invoke the close after, result in fact is not important - window.setTimeout(() => { - this.doClose(); - }); - }); - + await this.data.checkClose; + this.close(); } } - initYesNo() { - // data.autoclose is not used - } - ngOnInit() { if ( this.data.type === DialogType.yesno ) { - this.initYesNo(); + ; } else { this.initAlert(); } diff --git a/src/app/gui/uds-gui.service.ts b/src/app/gui/uds-gui.service.ts index 58ca1cc..68dde34 100644 --- a/src/app/gui/uds-gui.service.ts +++ b/src/app/gui/uds-gui.service.ts @@ -3,7 +3,9 @@ import { Injectable } from '@angular/core'; import { ModalComponent, DialogType } from './modal/modal.component'; import { CredentialsModalComponent } from './credentials-modal/credentials-modal.component'; import { MatDialog } from '@angular/material/dialog'; -import { Observable } from 'rxjs'; +import { Observable, firstValueFrom } from 'rxjs'; + +const toPromise = (observable: Observable): Promise => firstValueFrom(observable); @Injectable() export class UDSGuiService { @@ -13,7 +15,7 @@ export class UDSGuiService { title: string, message: string, autoclose = 0, - checkClose: Observable = null + checkClose: Promise = null ) { const width = window.innerWidth < 800 ? '80%' : '40%'; const dialogRef = this.dialog.open(ModalComponent, { @@ -30,7 +32,7 @@ export class UDSGuiService { return dialogRef; } - yesno(title: string, message: string) { + yesno(title: string, message: string): Promise { const width = window.innerWidth < 800 ? '80%' : '40%'; const dialogRef = this.dialog.open(ModalComponent, { width, @@ -41,13 +43,13 @@ export class UDSGuiService { return dialogRef.componentInstance.yesno; } - askCredentials(username: string, domain: string): Observable<{username: string; password: string; domain: string}> { + askCredentials(username: string, domain: string): Promise<{username: string; password: string; domain: string}> { const dialogRef = this.dialog.open(CredentialsModalComponent, { data: { username, domain, }, }); - return dialogRef.afterClosed(); + return toPromise(dialogRef.afterClosed()); } } diff --git a/src/app/helpers/plugin.ts b/src/app/helpers/plugin.ts index bad9eef..8d88600 100644 --- a/src/app/helpers/plugin.ts +++ b/src/app/helpers/plugin.ts @@ -48,12 +48,12 @@ export class Plugin { ), 0, // Now UDS tries to check status - new Observable((observer) => { + new Promise((resolve) => { let readyTime = 0; const checker = () => { if (alert.componentInstance) { // Not closed dialog... - this.api.status(params[0], params[1]).subscribe( + this.api.status(params[0], params[1]).then( (data) => { if (data.status === 'ready') { if (!readyTime) { @@ -89,19 +89,16 @@ export class Plugin { alert.componentInstance.data.body = django.gettext( 'Machine ready, waiting for UDS Client' ); - observer.next(true); - observer.complete(); + resolve(true); } else if (data.status === 'running') { window.setTimeout(checker, this.delay); // Recheck after delay seconds } else { - observer.next(true); - observer.complete(); + resolve(true); notifyError(); } }, (error) => { - observer.next(true); - observer.complete(); + resolve(true); notifyError(error); } ); @@ -120,7 +117,7 @@ export class Plugin { }) ); - this.api.enabler(params[0], params[1]).subscribe( + this.api.enabler(params[0], params[1]).then( (data) => { if (data.error) { state = 'error'; @@ -162,15 +159,14 @@ export class Plugin { ), 0, // Now UDS tries to check status before closing dialog... - new Observable((observer) => { + new Promise((resolve) => { const checker = () => { if (alert.componentInstance) { // Not closed dialog... - this.api.transportUrl(url).subscribe( + this.api.transportUrl(url).then( (data) => { if (data.url) { - observer.next(true); - observer.complete(); // Notify window to close... + resolve(true); // Extract if credentials modal is requested let username = ''; let domain = ''; @@ -237,9 +233,9 @@ export class Plugin { if (askCredentials) { this.api.gui .askCredentials(username, domain) - .subscribe((result) => { + .then((result) => { // Update transport credentials - this.api.updateTransportTicket(ticket, scrambler,result.username, result.password, result.domain).subscribe( + this.api.updateTransportTicket(ticket, scrambler,result.username, result.password, result.domain).then( () => { openWindow(); } @@ -249,16 +245,14 @@ export class Plugin { openWindow(); // Open window } } else if (!data.running) { - observer.next(true); - observer.complete(); + resolve(true); notifyError(data.error); } else { window.setTimeout(checker, this.delay); // Recheck after 5 seconds } }, (error) => { - observer.next(true); - observer.complete(); + resolve(true); notifyError(error); } ); @@ -273,7 +267,7 @@ export class Plugin { text: string, info: string, waitTime: number, - checker: Observable = null + checker: Promise = null ) { return this.api.gui.alert( django.gettext('Launching service'), diff --git a/src/app/pages/services/services.component.ts b/src/app/pages/services/services.component.ts index 058292c..25503a8 100644 --- a/src/app/pages/services/services.component.ts +++ b/src/app/pages/services/services.component.ts @@ -84,7 +84,7 @@ export class ServicesComponent implements OnInit { // Obtain services list this.api .getServicesInformation() - .subscribe((result: JSONServicesInformation) => { + .then((result: JSONServicesInformation) => { this.servicesInformation = result; this.autorun(); diff --git a/src/app/uds-api.service-type.ts b/src/app/uds-api.service-type.ts index b74a644..6ed1248 100644 --- a/src/app/uds-api.service-type.ts +++ b/src/app/uds-api.service-type.ts @@ -19,22 +19,22 @@ export interface UDSApiServiceType { enabler( serviceId: string, transportId: string - ): Observable; + ): Promise; /* Service status */ status( serviceId: string, transportId: string - ): Observable; + ): Promise; /* Services resetter */ - action(action: string, serviceId: string): Observable; + action(action: string, serviceId: string): Promise; /* transport url */ - transportUrl(url: string): Observable; + transportUrl(url: string): Promise; /* Transport ticket credentials updater */ - updateTransportTicket(ticketId: string, scrambler: string, username: string, password: string, domain: string): Observable; + updateTransportTicket(ticketId: string, scrambler: string, username: string, password: string, domain: string): Promise; /* Go to admin dashboard */ gotoAdmin(): void; @@ -45,7 +45,7 @@ export interface UDSApiServiceType { /** * Gets services information */ - getServicesInformation(): Observable; + getServicesInformation(): Promise; /** * Executes custom javascript for service launch if it is available diff --git a/src/app/uds-api.service.ts b/src/app/uds-api.service.ts index fc23ee1..55cd805 100644 --- a/src/app/uds-api.service.ts +++ b/src/app/uds-api.service.ts @@ -2,7 +2,8 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Router } from '@angular/router'; import { User, UDSConfig, Downloadable, Info } from './types/config'; -import { Observable } from 'rxjs'; +import { firstValueFrom, Observable } from 'rxjs'; +import { timeout } from 'rxjs/operators'; import { JSONServicesInformation, JSONEnabledService, @@ -23,7 +24,12 @@ declare const csrf: any; const DARK_THEME = 'dark-theme'; const LIGHT_THEME = 'light-theme'; +const TIMEOUT = 10000; +const toPromise = (observable: Observable, wait?: number): Promise => { + wait = wait || TIMEOUT; + return firstValueFrom(observable.pipe(timeout(wait))); +}; @Injectable() export class UDSApiService implements UDSApiServiceType { @@ -88,45 +94,50 @@ export class UDSApiService implements UDSApiServiceType { } /* Client enabler */ - enabler(serviceId: string, transportId: string) { + enabler(serviceId: string, transportId: string): Promise { const enabler = this.config.urls.enabler .replace('param1', serviceId) .replace('param2', transportId); - return this.http.get(enabler); + return toPromise(this.http.get(enabler)); } /* Check userService status */ - status( - serviceId: string, - transportId: string - ): Observable { + status(serviceId: string, transportId: string): Promise { const status = this.config.urls.status .replace('param1', serviceId) .replace('param2', transportId); - return this.http.get(status); + return toPromise(this.http.get(status)); } /* Services resetter */ - action(action: string, serviceId: string) { + action(action: string, serviceId: string): Promise { const actionURL = this.config.urls.action .replace('param1', serviceId) .replace('param2', action); - return this.http.get(actionURL); + return toPromise(this.http.get(actionURL)); } - transportUrl(url: string): Observable { - return this.http.get(url); + transportUrl(url: string): Promise { + return toPromise(this.http.get(url)); } - updateTransportTicket(ticketId: string, scrambler: string, username: string, password: string, domain: string): Observable { + updateTransportTicket( + ticketId: string, + scrambler: string, + username: string, + password: string, + domain: string + ): Promise { const url = this.config.urls.updateTransportTicket - .replace('param1', ticketId) - .replace('param2', scrambler); - return this.http.post(url, { - username, - password, - domain, - }); + .replace('param1', ticketId) + .replace('param2', scrambler); + return toPromise( + this.http.post(url, { + username, + password, + domain, + }) + ); } /* Images & static related */ @@ -149,15 +160,17 @@ export class UDSApiService implements UDSApiServiceType { /** * Gets services information */ - getServicesInformation(): Observable { - return this.http.get(this.config.urls.services); + getServicesInformation(): Promise { + return toPromise(this.http.get(this.config.urls.services)); } /** * Gets error string from a code */ getErrorInformation(errorCode: string): Observable { - return this.http.get(this.config.urls.error.replace('9999', errorCode)); + return this.http.get( + this.config.urls.error.replace('9999', errorCode) + ); } /** @@ -206,5 +219,4 @@ export class UDSApiService implements UDSApiServiceType { }); body.classList.add(dark ? DARK_THEME : LIGHT_THEME); } - } diff --git a/src/styles.scss b/src/styles.scss index d498764..2cba0e0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -4,48 +4,53 @@ @include angular-material-theme($angular-default-theme); /* Cookie consent */ -@import "~cookieconsent/build/cookieconsent.min.css"; +@import '~cookieconsent/build/cookieconsent.min.css'; -html, body { - margin: 0; - font-family: 'Roboto', sans-serif; - height: 100%; +html, +body { + margin: 0; + font-family: 'Roboto', sans-serif; + height: 100%; } /* App loading logo */ .app-loading .logo { - width: 113px; - height: 120px; - background: url(data:image/png;base64,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); + width: 113px; + height: 120px; + background: url(data:image/png;base64,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); } /* Fix for vertical align on material icons */ i.material-icons { - vertical-align: middle !important; + vertical-align: middle !important; } /* colors for remmarks */ .highlight { - color: red; + color: red; } .mat-mdc-menu-content { - .mat-mdc-menu-item:hover { - background-color: #E8E8E8; - } + .mat-mdc-menu-item:hover { + background-color: #e8e8e8; } +} .mat-mdc-option:hover:not(.mat-mdc-option-disabled) { - background: #648cb0 !important; - color: white !important; + background: #648cb0 !important; + color: white !important; } - + .dark-theme { @include angular-material-color($angular-dark-theme); html, body { - background-color: $bg-dark; + background-color: $bg-dark; } } +/* Variables */ +:root { + --mdc-dialog-supporting-text-font: 'Roboto', 'Helvetica', 'Arial', sans-serif; +}