This is an automated email from the ASF dual-hosted git repository. dgnatyshyn pushed a commit to branch DLAB-1715 in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
commit 42209c5f711462d3aff2febffcaded90c2038879 Author: Dmytro_Gnatyshyn <[email protected]> AuthorDate: Wed Jul 29 16:17:22 2020 +0300 [DLAB-1715]: User should be notify if project quota is exceeded --- .../core/services/applicationSecurity.service.ts | 1 + .../services/applicationServiceFacade.service.ts | 9 ++ .../src/app/core/services/healthStatus.service.ts | 8 ++ .../notification-dialog.component.ts | 5 +- .../src/app/shared/navbar/navbar.component.ts | 110 +++++++++++++++------ 5 files changed, 103 insertions(+), 30 deletions(-) diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationSecurity.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationSecurity.service.ts index 1bcd4f8..fae09ef 100644 --- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationSecurity.service.ts +++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationSecurity.service.ts @@ -87,6 +87,7 @@ export class ApplicationSecurityService { map(response => { this.storage.destroyTokens(); this.storage.setBillingQuoteUsed(''); + this.storage.setIsBillingQuoteUsed(''); this._loggedInStatus.next(false); return response; }, this)); diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts index 2c0e661..39e92af 100644 --- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts +++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts @@ -78,6 +78,7 @@ export class ApplicationServiceFacade { private static readonly ENDPOINT = 'endpoint'; private static readonly ENDPOINT_CONNECTION = 'endpoint_connection'; private static readonly AUDIT = 'audit'; + private static readonly QUOTA = 'quota'; private requestRegistry: Dictionary<string>; @@ -307,6 +308,13 @@ export class ApplicationServiceFacade { data); } + public buildGetQuotaStatus(): Observable<any> { + return this.buildRequest(HTTPMethod.GET, + this.requestRegistry.Item(ApplicationServiceFacade.QUOTA), + null + ); + } + public buildRunEdgeNodeRequest(): Observable<any> { return this.buildRequest(HTTPMethod.POST, this.requestRegistry.Item(ApplicationServiceFacade.EDGE_NODE_START), @@ -723,6 +731,7 @@ export class ApplicationServiceFacade { // billing report this.requestRegistry.Add(ApplicationServiceFacade.BILLING, '/api/billing/report'); this.requestRegistry.Add(ApplicationServiceFacade.DOWNLOAD_REPORT, '/api/billing/report/download'); + this.requestRegistry.Add(ApplicationServiceFacade.QUOTA, '/api/billing/quota'); // project this.requestRegistry.Add(ApplicationServiceFacade.PROJECT, '/api/project'); diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts index 02004f3..09f902e 100644 --- a/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts +++ b/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts @@ -84,6 +84,14 @@ export class HealthStatusService { catchError(ErrorUtils.handleServiceError)); } + public getQuotaStatus(): Observable<{}> { + return this.applicationServiceFacade + .buildGetQuotaStatus() + .pipe( + map(response => response), + catchError(ErrorUtils.handleServiceError)); + } + public runEdgeNode(): Observable<{}> { return this.applicationServiceFacade .buildRunEdgeNodeRequest() diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts index e185675..551e3e2 100644 --- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts @@ -56,7 +56,9 @@ import {Endpoint} from '../../../administration/project/project.component'; </div> <span class="strong blue">by a schedule in less than 15 minutes.</span> </div> - <div *ngIf="data.type === 'message'"><span [innerHTML]="data.template"></span></div> + <div class="alert" *ngIf="data.type === 'message'"> + <span [innerHTML]="data.template"></span> + </div> <div *ngIf="data.type === 'confirmation'" class="confirm-dialog"> <p *ngIf="data.template; else label"> <span [innerHTML]="data.template"></span> @@ -169,6 +171,7 @@ import {Endpoint} from '../../../administration/project/project.component'; label{cursor: pointer} .bottom-message{padding-top: 15px;} .table-header{padding-bottom: 10px;} + .alert{text-align: left; line-height: 22px; padding-bottom: 25px;padding-top: 15px;} `] diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts index e30f8db..7be914f 100644 --- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts @@ -38,9 +38,14 @@ import { animateChild, state } from '@angular/animations'; -import {skip} from 'rxjs/operators'; +import {skip, take} from 'rxjs/operators'; import {ProgressBarService} from '../../core/services/progress-bar.service'; + +interface Quota { + projectQuotas: {}; + totalQuotaUsed: number; +} @Component({ selector: 'dlab-navbar', templateUrl: 'navbar.component.html', @@ -110,7 +115,7 @@ export class NavbarComponent implements OnInit, OnDestroy { if (this.isLoggedIn) { this.subscriptions.add(this.healthStatusService.statusData.pipe(skip(1)).subscribe(result => { this.healthStatus = result; - result.status && this.checkQuoteUsed(this.healthStatus); + result.status && this.checkQuoteUsed(); result.status && !result.projectAssigned && !result.admin && this.checkAssignment(this.healthStatus); })); this.subscriptions.add(timer(0, this.CHECK_ACTIVE_SCHEDULE_TIMEOUT).subscribe(() => this.refreshSchedulerData())); @@ -148,9 +153,9 @@ export class NavbarComponent implements OnInit, OnDestroy { this.isExpanded = !this.isExpanded; } - public emitQuotes(alert, user_quota?, total_quota?): void { + public emitQuotes(alert, total_quota?, exideedProjects?, informProjects?): void { const dialogRef: MatDialogRef<NotificationDialogComponent> = this.dialog.open(NotificationDialogComponent, { - data: { template: this.selectAlert(alert, user_quota, total_quota), type: 'message' }, + data: { template: this.selectAlert(alert, total_quota, exideedProjects, informProjects), type: 'message' }, width: '550px' }); dialogRef.afterClosed().subscribe(() => { @@ -158,17 +163,43 @@ export class NavbarComponent implements OnInit, OnDestroy { }); } - private checkQuoteUsed(params): void { - if (!this.storage.getBillingQuoteUsed() && params) { - let checkQuotaAlert = ''; + private checkQuoteUsed(): void { + if (!this.storage.getBillingQuoteUsed( ) && !this.storage.getIsBillingQuoteUsed()) { + this.healthStatusService.getQuotaStatus().pipe(take(1)).subscribe((params: Quota) => { + let checkQuotaAlert = ''; + params = { + projectQuotas: {Proj1: 99, Proj2: 99, Proj3: 99, Proj4: 99}, + totalQuotaUsed: 50 + }; + + const exceedProjects = [], informProjects = []; + Object.keys(params.projectQuotas).forEach(key => { + if (params.projectQuotas[key] > this.quotesLimit && params.projectQuotas[key] < 100) { + informProjects.push(key); + } else if (params.projectQuotas[key] >= 100) { + exceedProjects.push(key); + } + }); + + if (informProjects.length > 0 && exceedProjects.length === 0) checkQuotaAlert = 'project_quota'; + if (params.totalQuotaUsed >= this.quotesLimit && params.totalQuotaUsed < 100) checkQuotaAlert = 'total_quota'; + if (exceedProjects.length > 0 && informProjects.length === 0) checkQuotaAlert = 'project_exceed'; + if (informProjects.length > 0 && exceedProjects.length > 0) checkQuotaAlert = 'project_inform_and_exceed'; + if (params.totalQuotaUsed >= this.quotesLimit && params.totalQuotaUsed < 100 && exceedProjects.length > 0) checkQuotaAlert = 'total_quota_and_project_exceed'; + if (params.totalQuotaUsed >= this.quotesLimit && params.totalQuotaUsed < 100 && informProjects.length > 0 && exceedProjects.length > 0) checkQuotaAlert = 'total_quota_and_project_inform_and_exceed'; - if (params.billingUserQuoteUsed >= this.quotesLimit && params.billingUserQuoteUsed < 100) checkQuotaAlert = 'user_quota'; - if (params.billingQuoteUsed >= this.quotesLimit && params.billingQuoteUsed < 100) checkQuotaAlert = 'total_quota'; - if (Number(params.billingUserQuoteUsed) >= 100) checkQuotaAlert = 'user_exceed'; - if (Number(params.billingQuoteUsed) >= 100) checkQuotaAlert = 'total_exceed'; - if (this.dialog.openDialogs.length > 0 || this.dialog.openDialogs.length > 0) return; - checkQuotaAlert && this.emitQuotes(checkQuotaAlert, params.billingUserQuoteUsed, params.billingQuoteUsed); + if (Number(params.totalQuotaUsed) >= 100) checkQuotaAlert = 'total_exceed'; + + if (checkQuotaAlert === '') { + this.storage.setIsBillingQuoteUsed(true); + } else { + this.storage.setIsBillingQuoteUsed(''); + } + + if (this.dialog.openDialogs.length > 0 || this.dialog.openDialogs.length > 0) return; + checkQuotaAlert && this.emitQuotes(checkQuotaAlert, params.totalQuotaUsed, exceedProjects, informProjects); + }); } } @@ -206,25 +237,46 @@ export class NavbarComponent implements OnInit, OnDestroy { }); } - private selectAlert(type: string, user_quota?: number, total_quota?: number): string { + private selectAlert(type: string, total_quota?: number, exideedProjects?: string[], informProjects?: string[]): string { const alerts = { - user_exceed: `Dear <b>${this.currentUserName}</b>,<br /> - DLab cloud infrastructure usage quota associated with your user has been exceeded. - All your analytical environment will be stopped. To proceed working with environment, - request increase of user quota from DLab administrator.`, - total_exceed: `Dear <b>${this.currentUserName}</b>,<br /> + total_quota_and_project_inform_and_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>. + Once quota is depleted all your analytical environment will be stopped.<br /><br /> + Quota associated with project(s) <span class="strong">${exideedProjects}</span> has been exceeded. All your analytical environment will be stopped.<br /><br /> + Quota associated with project(s) <span class="strong">${informProjects}</span> has been used over <span class="strong">${this.quotesLimit}%</span>. + If quota is depleted all your analytical environment will be stopped.<br /><br /> + To proceed working with environment you'll have to request increase of quota from DLab administrator. `, + + total_quota_and_project_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>. + Once quota is depleted all your analytical environment will be stopped.<br /><br /> + Quota associated with project(s) <span class="strong">${exideedProjects}</span> has been exceeded. All your analytical environment will be stopped.<br /><br /> + To proceed working with environment you'll have to request increase of quota from DLab administrator. `, + + project_inform_and_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + DLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects}</span> has been exceeded. All your analytical environment will be stopped.<br /><br /> + Quota associated with project(s) <span class="strong">${informProjects}</span> has been used over <span class="strong">${this.quotesLimit}%</span>. + If quota is depleted all your analytical environment will be stopped.<br /><br /> + To proceed working with environment, request increase of project quota from DLab administrator.`, + project_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + DLab cloud infrastructure usage quota associated with project(s) <span class="strong">${exideedProjects}</span> has been exceeded. + All your analytical environment will be stopped.<br /><br /> + To proceed working with environment, + request increase of project(s) quota from DLab administrator.`, + total_exceed: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> DLab cloud infrastructure usage quota has been exceeded. - All your analytical environment will be stopped. To proceed working with environment, + All your analytical environment will be stopped.<br /><br /> + To proceed working with environment, request increase application quota from DLab administrator.`, - user_quota: `Dear <b>${this.currentUserName}</b>,<br /> - Cloud infrastructure usage quota associated with your user has been used for <b>${user_quota}%</b>. - Once quota is depleted all your analytical environment will be stopped. - To proceed working with environment you'll have to request increase of user quota from DLab administrator.`, - total_quota: `Dear <b>${this.currentUserName}</b>,<br /> - DLab cloud infrastructure usage quota has been used for <b>${total_quota}%</b>. - Once quota is depleted all your analytical environment will be stopped. - To proceed working with environment you'll have to request increase of user quota from DLab administrator. `, - permissions: `Dear <b>${this.currentUserName}</b>,<br /> + project_quota: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + Cloud infrastructure usage quota associated with project(s) <span class="strong">${informProjects}</span> has been used over <span class="strong">${this.quotesLimit}%</span>. + Once quota is depleted all your analytical environment will be stopped.<br /><br /> + To proceed working with environment you'll have to request increase of project(s) quota from DLab administrator.`, + total_quota: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> + DLab cloud infrastructure usage quota has been used for <span class="strong">${total_quota}%</span>. + Once quota is depleted all your analytical environment will be stopped.<br /><br /> + To proceed working with environment you'll have to request increase of total quota from DLab administrator. `, + permissions: `Dear <span class="strong">${this.currentUserName}</span>,<br /><br /> Currently, you are not assigned to any project. To start working with the environment request permission from DLab administrator.` }; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
