From 7fce27e0f224463f05211a0274eb282590466b5c Mon Sep 17 00:00:00 2001 From: dweinholz Date: Mon, 8 Jul 2024 14:51:48 +0200 Subject: [PATCH 01/10] fix(Application): reload application when resetting pi or some changes for the application --- .../application-card.component.html | 85 +- .../application-card.component.ts | 292 +----- .../application-facility-actions.component.ts | 436 ++++----- .../application-list.component.ts | 1 + .../application-vo-actions.component.ts | 831 +++++++++--------- 5 files changed, 687 insertions(+), 958 deletions(-) diff --git a/src/app/applications/application-card/application-card.component.html b/src/app/applications/application-card/application-card.component.html index 05d0a2ab73..77761eec7b 100644 --- a/src/app/applications/application-card/application-card.component.html +++ b/src/app/applications/application-card/application-card.component.html @@ -1,46 +1,49 @@ - - - - {{ application?.project_application_name }} - {{ application?.project_application_shortname }} - {{ application?.project_application_date_submitted }} - - @if (application?.project_application_user?.username) { - {{ application?.project_application_user?.username }} - } @else { - - } - - {{ application?.project_application_institute }} + + + + {{ application?.project_application_name }} + {{ application?.project_application_shortname }} + {{ application?.project_application_date_submitted }} + + @if (application?.project_application_user?.username) { + {{ application?.project_application_user?.username }} + } @else { + + } + + {{ application?.project_application_institute }} - @if (voView) { - - } @else if (facilityView) { - - } + @if (voView) { + + } @else if (facilityView) { + + } - @if (!isCollapsed) { - - } + @if (!isCollapsed) { + + } diff --git a/src/app/applications/application-card/application-card.component.ts b/src/app/applications/application-card/application-card.component.ts index e6c0a61873..41d61deec8 100644 --- a/src/app/applications/application-card/application-card.component.ts +++ b/src/app/applications/application-card/application-card.component.ts @@ -1,19 +1,16 @@ import { - Component, EventEmitter, Input, OnInit, Output, + Component, EventEmitter, Input, OnInit, Output, ViewChild, } from '@angular/core'; -import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; -import { Subscription } from 'rxjs'; -import { HttpStatusCode } from '@angular/common/http'; +import { BsModalRef } from 'ngx-bootstrap/modal'; import { AbstractBaseClass, Application_States } from '../../shared/shared_modules/baseClass/abstract-base-class'; import { ConfirmationActions } from '../../shared/modal/confirmation_actions'; import { Application } from '../application.model/application.model'; import { ApplicationTabStates } from '../../shared/enums/application-tab-states'; import { ApplicationsService } from '../../api-connector/applications.service'; -import { NotificationModalComponent } from '../../shared/modal/notification-modal'; import { is_vo } from '../../shared/globalvar'; import { ComputecenterComponent } from '../../projectmanagement/computecenter.component'; -import { GroupService } from '../../api-connector/group.service'; import { User } from '../application.model/user.model'; +import { ApplicationDetailComponent } from '../application-detail/application-detail.component'; @Component({ selector: 'app-application-card', @@ -21,7 +18,6 @@ import { User } from '../application.model/user.model'; styleUrl: './application-card.component.scss', }) export class ApplicationCardComponent extends AbstractBaseClass implements OnInit { - private subscription: Subscription = new Subscription(); @Input() application: Application; @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; @@ -30,10 +26,10 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); @Input() facilityView: boolean = false; @Input() voView: boolean = false; + @ViewChild('applicationdetail') applicationDetailComponent: ApplicationDetailComponent; bsModalRef: BsModalRef; is_vo_admin: boolean = false; - selectedComputeCenter: ComputecenterComponent; ngOnInit() { this.is_vo_admin = is_vo; @@ -63,8 +59,7 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni constructor( private applicationsService: ApplicationsService, - private modalService: BsModalService, - private groupService: GroupService, + ) { super(); } @@ -88,288 +83,11 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni ); } - resetApplicationPI(): void { - this.applicationsService.resetPIValidation(this.application).subscribe(() => { - this.getApplication(); - }); - } - switchCollaps() { this.isCollapsed = !this.isCollapsed; } - showNotificationModal( - notificationModalTitle: string, - notificationModalMessage: string, - notificationModalType: string, - ) { - const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; - if (this.bsModalRef) { - this.bsModalRef.hide(); - } - - this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); - this.bsModalRef.setClass('modal-lg'); - } - - createSimpleVmProjectGroup(): void { - this.showNotificationModal('Info', 'Creating Project...', 'info'); - - if (this.selectedComputeCenter && this.selectedComputeCenter.FacilityId) { - this.groupService - .createGroupByApplication(this.application.project_application_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (res: any): void => { - if (!res['client_available'] && !res['created']) { - this.showNotificationModal( - 'Failed', - `The client ${res['client_name']} has not the necessary resources left!`, - 'danger', - ); - } else { - this.showNotificationModal('Success', 'The project was created!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - } - }, - (error: any): void => { - console.log(error); - const errorMessage = error && error.error === 'locked' - ? 'Project is locked and could not be created!' - : 'Project could not be created!'; - - this.showNotificationModal('Failed', errorMessage, 'danger'); - console.log(error); - }, - ); - } - } - - approveModificationRequest(): void { - this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The resource modification request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - - // this.all_applications.splice(this.all_applications.indexOf(application), 1); - } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of resource modification failed!', 'danger'); - }, - ); - } - - declineModificationRequest(): void { - this.applicationsService.deleteModificationRequest(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The resource modification request was declined!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - - this.getApplication(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of resource modification failed!', 'danger'); - }, - ); - } - - deleteApplication(): void { - // const idx: number = this.all_applications.indexOf(application); - - this.subscription.add( - this.applicationsService.deleteApplication(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.updateNotificationModal('Failed', 'Application could not be removed!', true, 'danger'); - }, - ), - ); - } - - declineLifetimeExtension(): void { - this.applicationsService.deleteAdditionalLifetimeRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The project extension was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of project extension failed!', 'danger'); - }, - ); - } - - declineCreditExtension(): void { - this.applicationsService.deleteAdditionalCreditsRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The credit extension request was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of credit extension failed!', 'danger'); - }, - ); - } - - declineApplication(): void { - // const idx: number = this.all_applications.indexOf(app); - this.applicationsService.declineApplication(this.application.project_application_id).subscribe( - (): void => { - const message: string = 'The Application was declined.'; - - this.showNotificationModal('Success', message, 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); - }, - ); - } - - approveLifetimeExtension(): void { - this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( - (res: Response): void => { - if (this.application.project_application_openstack_project) { - this.getApplication(); - this.showNotificationModal('Success', 'The request has been sent to the facility manager.', 'success'); - } else { - this.showNotificationModal('Success', 'The project has been extended!', 'success'); - } - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - } - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Project lifetime could not be extendend!', 'danger'); - }, - ); - } - - approveCreditExtension(): void { - this.applicationsService.approveAdditionalCreditsRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The credit extension request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of credit extension failed!', 'danger'); - }, - ); - } - - createOpenStackProjectGroup(): void { - this.groupService - .createGroupOpenStack(this.application.project_application_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (result: { [key: string]: string }): void => { - if (result['Error']) { - this.showNotificationModal('Failed', result['Error'], 'danger'); - } else { - this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); - this.getApplication(); - // this.switchApproveLocked(false); - } - }, - (error: any): void => { - const errorMessage = error && error.error === 'locked' - ? 'Project is locked and could not be created!' - : 'Project could not be created!'; - - this.showNotificationModal('Failed', errorMessage, 'danger'); - console.log(error); - }, - ); - } - - /** - * Function to listen to modal results. - */ - subscribeToBsModalRef(): void { - this.subscription.add( - this.bsModalRef.content.event.subscribe((result: any) => { - let action = null; - if ('action' in result) { - action = result['action']; - } - if ('createSimpleVM' in result) { - this.createSimpleVmProjectGroup(); - } - if (action === ConfirmationActions.APPROVE_MODIFICATION) { - this.approveModificationRequest(); - } - if ('closed' in result) { - // this.switchApproveLocked(false); - } - if (action === ConfirmationActions.DECLINE_MODIFICATION) { - this.declineModificationRequest(); - } - if (action === ConfirmationActions.DELETE_APPLICATION) { - this.deleteApplication(); - } - if (action === ConfirmationActions.DECLINE_EXTENSION) { - this.declineLifetimeExtension(); - } - if (action === ConfirmationActions.DECLINE_CREDITS) { - this.declineCreditExtension(); - } - if (action === ConfirmationActions.DECLINE_APPLICATION) { - this.declineApplication(); - } - - if (action === ConfirmationActions.APPROVE_EXTENSION) { - this.approveLifetimeExtension(); - } - if (action === ConfirmationActions.RESET_PI) { - this.resetApplicationPI(); - } - if (action === ConfirmationActions.APPROVE_CREDITS) { - this.approveCreditExtension(); - } - if (action === ConfirmationActions.APPROVE_APPLICATION) { - if (this.application.project_application_openstack_project) { - this.createOpenStackProjectGroup(); - } - } - if (action === 'adjustedModificationRequest') { - // this.isLoaded = false; - // this.changeTabState(ApplicationTabStates.MODIFICATION_EXTENSION); - } - }), - ); - } - isCollapsed: boolean = true; protected readonly Application_States = Application_States; protected readonly ConfirmationActions = ConfirmationActions; - protected readonly ApplicationTabStates = ApplicationTabStates; } diff --git a/src/app/applications/application-facility-actions/application-facility-actions.component.ts b/src/app/applications/application-facility-actions/application-facility-actions.component.ts index f0435db1b8..562c3a7b0e 100644 --- a/src/app/applications/application-facility-actions/application-facility-actions.component.ts +++ b/src/app/applications/application-facility-actions/application-facility-actions.component.ts @@ -33,250 +33,256 @@ export class ApplicationFacilityActionsComponent extends AbstractBaseClass { isCollapsed: boolean = true; bsModalRef: BsModalRef; @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); + @Output() reloadApplicationTrigger: EventEmitter = new EventEmitter(); - constructor( + constructor( private facilityService: FacilityService, private modalService: BsModalService, private applicationsService: ApplicationsService, - ) { - super(); - } + ) { + super(); + } - switchCollaps() { - this.switchCollapseEvent.emit(); - } + switchCollaps() { + this.switchCollapseEvent.emit(); + } - triggerRemoveApplication() { - this.removeApplicationTrigger.emit(this.application.project_application_id); - } + triggerRemoveApplication() { + this.removeApplicationTrigger.emit(this.application.project_application_id); + } - triggerReloadNumbers() { - this.reloadNumbersTrigger.emit(); - } + triggerReloadNumbers() { + this.reloadNumbersTrigger.emit(); + } - declineApplication(): void { - this.showNotificationModal('Decline Application', 'Waiting..', 'info'); + triggerReloadApplication():void { + this.reloadApplicationTrigger.emit(); - this.facilityService - .declineFacilityApplication( - this.application.project_application_compute_center.FacilityId, - this.application.project_application_id, - ) - .subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully declined the application.', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); + } - // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); - }, - (): void => { - this.showNotificationModal('Failed', 'Failed to decline the application.', 'danger'); - }, - ); - } + declineApplication(): void { + this.showNotificationModal('Decline Application', 'Waiting..', 'info'); - public approveExtension(): void { - this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully approved extension!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - }, - (): void => { - this.showNotificationModal('Failed', 'The approval of the extension request has failed.', 'danger'); - }, - ); - } + this.facilityService + .declineFacilityApplication( + this.application.project_application_compute_center.FacilityId, + this.application.project_application_id, + ) + .subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully declined the application.', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); - /** + // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); + }, + (): void => { + this.showNotificationModal('Failed', 'Failed to decline the application.', 'danger'); + }, + ); + } + + public approveExtension(): void { + this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully approved extension!', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + }, + (): void => { + this.showNotificationModal('Failed', 'The approval of the extension request has failed.', 'danger'); + }, + ); + } + + /** * Decline an extension request. * * @param application_id */ - public declineExtension(): void { - this.applicationsService.declineAdditionalLifetime(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully declined extension!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - }, - (): void => { - this.showNotificationModal('Failed', 'The decline of the extension request has failed.', 'danger'); - }, - ); - } + public declineExtension(): void { + this.applicationsService.declineAdditionalLifetime(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully declined extension!', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + }, + (): void => { + this.showNotificationModal('Failed', 'The decline of the extension request has failed.', 'danger'); + }, + ); + } - showNotificationModal( - notificationModalTitle: string, - notificationModalMessage: string, - notificationModalType: string, - ) { - const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; - if (this.bsModalRef) { - this.bsModalRef.hide(); - } + showNotificationModal( + notificationModalTitle: string, + notificationModalMessage: string, + notificationModalType: string, + ) { + const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; + if (this.bsModalRef) { + this.bsModalRef.hide(); + } - this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); - this.bsModalRef.setClass('modal-lg'); - } + this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); + this.bsModalRef.setClass('modal-lg'); + } - approveApplication(): void { - this.showNotificationModal('Approving Application', 'Waiting..', 'info'); - this.facilityService - .approveFacilityApplication( - this.application.project_application_compute_center.FacilityId, - this.application.project_application_id, - ) - .subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully approved the application.', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); + approveApplication(): void { + this.showNotificationModal('Approving Application', 'Waiting..', 'info'); + this.facilityService + .approveFacilityApplication( + this.application.project_application_compute_center.FacilityId, + this.application.project_application_id, + ) + .subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully approved the application.', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); - // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); - }, - (): void => { - this.showNotificationModal('Failed', 'Failed to approve the application.', 'danger'); - }, - ); - } + // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); + }, + (): void => { + this.showNotificationModal('Failed', 'Failed to approve the application.', 'danger'); + }, + ); + } - showConfirmationModal(action: ConfirmationActions): void { - const initialState = { - application: this.application, - action, - }; + showConfirmationModal(action: ConfirmationActions): void { + const initialState = { + application: this.application, + action, + }; - this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); - this.subscribeToBsModalRef(); - } + this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); + this.subscribeToBsModalRef(); + } - approveModification(): void { - this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully approved modification!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - }, - (): void => { - this.showNotificationModal('Failed', 'The approval of the modification request has failed.', 'danger'); - }, - ); - } + approveModification(): void { + this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully approved modification!', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + }, + (): void => { + this.showNotificationModal('Failed', 'The approval of the modification request has failed.', 'danger'); + }, + ); + } - declineModification(): void { - this.applicationsService.declineModificationRequest(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'Successfully declined modification!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - }, - (): void => { - this.showNotificationModal('Failed', 'The decline of the modification request has failed.', 'danger'); - }, - ); - } + declineModification(): void { + this.applicationsService.declineModificationRequest(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Success', 'Successfully declined modification!', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + }, + (): void => { + this.showNotificationModal('Failed', 'The decline of the modification request has failed.', 'danger'); + }, + ); + } - approveTermination(): void { - this.facilityService - .approveTerminationByFM( - this.application.project_application_perun_id, - this.application.project_application_compute_center.FacilityId, - ) - .subscribe( - (): void => { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - this.showNotificationModal('Success', 'The project was terminated.', 'success'); - }, - (error: any): void => { - if (error['status'] === 409) { - this.showNotificationModal( - 'Failed', - `The project could not be terminated. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, + approveTermination(): void { + this.facilityService + .approveTerminationByFM( + this.application.project_application_perun_id, + this.application.project_application_compute_center.FacilityId, + ) + .subscribe( + (): void => { + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + this.showNotificationModal('Success', 'The project was terminated.', 'success'); + }, + (error: any): void => { + if (error['status'] === 409) { + this.showNotificationModal( + 'Failed', + `The project could not be terminated. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, - 'danger', - ); - } else { - this.showNotificationModal('Failed', 'The project could not be terminated.', 'danger'); - } - }, - ); - } + 'danger', + ); + } else { + this.showNotificationModal('Failed', 'The project could not be terminated.', 'danger'); + } + }, + ); + } - declineTermination(): void { - this.facilityService - .declineTerminationByFM( - this.application.project_application_perun_id, - this.application.project_application_compute_center.FacilityId, - ) - .subscribe( - (): void => { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - this.showNotificationModal('Success', 'The termination of the project was declined.', 'success'); - }, - (error: any): void => { - if (error['status'] === 409) { - this.showNotificationModal( - 'Failed', - `The decline of the project was not successful. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, + declineTermination(): void { + this.facilityService + .declineTerminationByFM( + this.application.project_application_perun_id, + this.application.project_application_compute_center.FacilityId, + ) + .subscribe( + (): void => { + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + this.showNotificationModal('Success', 'The termination of the project was declined.', 'success'); + }, + (error: any): void => { + if (error['status'] === 409) { + this.showNotificationModal( + 'Failed', + `The decline of the project was not successful. Reason: ${error['error']['reason']} for ${error['error']['openstackid']}`, - 'danger', - ); - } else { - this.showNotificationModal('Failed', 'The decline of the project failed.', 'danger'); - } - }, - ); - } + 'danger', + ); + } else { + this.showNotificationModal('Failed', 'The decline of the project failed.', 'danger'); + } + }, + ); + } - subscribeToBsModalRef(): void { - this.subscription.add( - this.bsModalRef.content.event.subscribe((event: any) => { - const action: ConfirmationActions = event.action; - switch (action) { - case ConfirmationActions.APPROVE_APPLICATION: { - this.approveApplication(); - break; - } - case ConfirmationActions.DECLINE_APPLICATION: { - this.declineApplication(); - break; - } - case ConfirmationActions.DECLINE_EXTENSION: { - this.declineExtension(); - break; - } - case ConfirmationActions.APPROVE_EXTENSION: { - this.approveExtension(); - break; - } - case ConfirmationActions.DECLINE_MODIFICATION: { - this.declineModification(); - break; - } - case ConfirmationActions.APPROVE_MODIFICATION: { - this.approveModification(); - break; - } - case ConfirmationActions.APPROVE_TERMINATION: { - this.approveTermination(); - break; - } - case ConfirmationActions.DECLINE_TERMINATION: { - this.declineTermination(); - break; - } - default: - break; - } - }), - ); - } + subscribeToBsModalRef(): void { + this.subscription.add( + this.bsModalRef.content.event.subscribe((event: any) => { + const action: ConfirmationActions = event.action; + switch (action) { + case ConfirmationActions.APPROVE_APPLICATION: { + this.approveApplication(); + break; + } + case ConfirmationActions.DECLINE_APPLICATION: { + this.declineApplication(); + break; + } + case ConfirmationActions.DECLINE_EXTENSION: { + this.declineExtension(); + break; + } + case ConfirmationActions.APPROVE_EXTENSION: { + this.approveExtension(); + break; + } + case ConfirmationActions.DECLINE_MODIFICATION: { + this.declineModification(); + break; + } + case ConfirmationActions.APPROVE_MODIFICATION: { + this.approveModification(); + break; + } + case ConfirmationActions.APPROVE_TERMINATION: { + this.approveTermination(); + break; + } + case ConfirmationActions.DECLINE_TERMINATION: { + this.declineTermination(); + break; + } + default: + break; + } + }), + ); + } - ngOnInit() {} + ngOnInit() {} - protected readonly Application_States = Application_States; + protected readonly Application_States = Application_States; } diff --git a/src/app/applications/application-list/application-list.component.ts b/src/app/applications/application-list/application-list.component.ts index f761a7873e..96816ed888 100644 --- a/src/app/applications/application-list/application-list.component.ts +++ b/src/app/applications/application-list/application-list.component.ts @@ -22,6 +22,7 @@ export class ApplicationListComponent implements OnInit, OnChanges { @Input() computeCenters: ComputecenterComponent[] = []; @Input() facilityView: boolean = false; @Input() voView: boolean = false; + dataTestId: string = ''; is_vo_admin: boolean = false; diff --git a/src/app/applications/application-vo-actions/application-vo-actions.component.ts b/src/app/applications/application-vo-actions/application-vo-actions.component.ts index 68191fff20..86ef775905 100644 --- a/src/app/applications/application-vo-actions/application-vo-actions.component.ts +++ b/src/app/applications/application-vo-actions/application-vo-actions.component.ts @@ -14,9 +14,15 @@ import { is_vo } from '../../shared/globalvar'; import { ApplicationsService } from '../../api-connector/applications.service'; import { VoService } from '../../api-connector/vo.service'; import { GroupService } from '../../api-connector/group.service'; -import { AdjustLifetimeRequestComponent } from '../../projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component'; -import { AdjustApplicationComponent } from '../../projectmanagement/modals/adjust-application/adjust-application.component'; -import { ModificationRequestComponent } from '../../projectmanagement/modals/modification-request/modification-request.component'; +import { + AdjustLifetimeRequestComponent, +} from '../../projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component'; +import { + AdjustApplicationComponent, +} from '../../projectmanagement/modals/adjust-application/adjust-application.component'; +import { + ModificationRequestComponent, +} from '../../projectmanagement/modals/modification-request/modification-request.component'; import { ConfirmationModalComponent } from '../../shared/modal/confirmation-modal.component'; import { ClientLimitsComponent } from '../../vo_manager/clients/modals/client-limits..component'; import { NotificationModalComponent } from '../../shared/modal/notification-modal'; @@ -29,224 +35,386 @@ import { NotificationModalComponent } from '../../shared/modal/notification-moda export class ApplicationVoActionsComponent extends AbstractBaseClass implements OnInit { private subscription: Subscription = new Subscription(); - @Input() application: Application; - @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; - @Input() computeCenters: ComputecenterComponent[] = []; - @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); - @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); - @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); - - bsModalRef: BsModalRef; - is_vo_admin: boolean = false; - selectedComputeCenter: ComputecenterComponent; - - ngOnInit() { - this.is_vo_admin = is_vo; - } - - constructor( - private applicationsService: ApplicationsService, - private modalService: BsModalService, - private voService: VoService, - private groupService: GroupService, - private adjustLifeTimeExtensionModal: AdjustLifetimeRequestComponent, - private adjustApplicationModal: AdjustApplicationComponent, - ) { - super(); - } - - triggerRemoveApplication() { - this.removeApplicationTrigger.emit(this.application.project_application_id); - } - - showAdjustLifetimeExtensionModal() { - this.adjustLifeTimeExtensionModal - .showAdjustLifetimeExtensionModal(this.application) - .subscribe((eventSuccess: boolean) => { - if (eventSuccess) { - this.getApplication(); - this.showNotificationModal( - 'Success', - 'The lifetime of the extension request were adjusted successfully!', - 'success', - ); + @Input() application: Application; + @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; + @Input() computeCenters: ComputecenterComponent[] = []; + @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); + @Output() reloadApplicationTrigger: EventEmitter = new EventEmitter(); + @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); + @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); + + bsModalRef: BsModalRef; + is_vo_admin: boolean = false; + selectedComputeCenter: ComputecenterComponent; + + ngOnInit() { + this.is_vo_admin = is_vo; + } + + constructor( + private applicationsService: ApplicationsService, + private modalService: BsModalService, + private voService: VoService, + private groupService: GroupService, + private adjustLifeTimeExtensionModal: AdjustLifetimeRequestComponent, + private adjustApplicationModal: AdjustApplicationComponent, + ) { + super(); + } + + triggerRemoveApplication() { + this.removeApplicationTrigger.emit(this.application.project_application_id); + } + + showAdjustLifetimeExtensionModal() { + this.adjustLifeTimeExtensionModal + .showAdjustLifetimeExtensionModal(this.application) + .subscribe((eventSuccess: boolean) => { + if (eventSuccess) { + this.triggerReloadApplication(); + this.showNotificationModal( + 'Success', + 'The lifetime of the extension request were adjusted successfully!', + 'success', + ); + } else { + this.showNotificationModal('Failed', 'The adjustment of the lifetime has failed!', 'danger'); + } + }); + } + + triggerReloadApplication(): void { + this.reloadApplicationTrigger.emit(); + + } + + showAdjustApplicationModal() { + this.adjustApplicationModal.showAdjustApplicationModal(this.application).subscribe((changed: boolean) => { + if (changed) { + this.triggerReloadApplication(); + + this.showNotificationModal('Success', 'The resources of the application were adjusted successfully!', 'success'); } else { - this.showNotificationModal('Failed', 'The adjustment of the lifetime has failed!', 'danger'); + this.showNotificationModal('Failed', 'The adjustment of the resources has failed!', 'danger'); } }); - } + } + + showModificationAdjustmentModal() { + const initialState = { + project: this.application, + adjustment: true, + }; + + this.bsModalRef = this.modalService.show(ModificationRequestComponent, { + initialState, + class: 'modal-lg', + }); + this.subscribeToBsModalRef(); + // this.subscribeForExtensionResult(this.ExtensionRequestType.MODIFICATION); + } + + triggerReloadNumbers() { + this.reloadNumbersTrigger.emit(); + } - showAdjustApplicationModal() { - this.adjustApplicationModal.showAdjustApplicationModal(this.application).subscribe((changed: boolean) => { - if (changed) { - this.getApplication(); + setCurrentUserProcessingVoManager(application: Application): void { + if (this.is_vo_admin) { + this.voService.setCurrentUserProcessingVoManager(application.project_application_id).subscribe((res: any) => { + application.processing_vo_initials = res['processing_vo_initials']; + }); + } + } - this.showNotificationModal('Success', 'The resources of the application were adjusted successfully!', 'success'); + showConfirmationModal(action: ConfirmationActions): void { + let initialState = {}; + if (action === ConfirmationActions.APPROVE_APPLICATION) { + const application_center = !this.selectedComputeCenter.FacilityId; + initialState = { application: this.application, action, application_center }; } else { - this.showNotificationModal('Failed', 'The adjustment of the resources has failed!', 'danger'); + initialState = { + application: this.application, + action, + }; } - }); - } - - showModificationAdjustmentModal() { - const initialState = { - project: this.application, - adjustment: true, - }; - - this.bsModalRef = this.modalService.show(ModificationRequestComponent, { - initialState, - class: 'modal-lg', - }); - this.subscribeToBsModalRef(); - // this.subscribeForExtensionResult(this.ExtensionRequestType.MODIFICATION); - } - - triggerReloadNumbers() { - this.reloadNumbersTrigger.emit(); - } - - setCurrentUserProcessingVoManager(application: Application): void { - if (this.is_vo_admin) { - this.voService.setCurrentUserProcessingVoManager(application.project_application_id).subscribe((res: any) => { - application.processing_vo_initials = res['processing_vo_initials']; - }); + this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); + this.subscribeToBsModalRef(); } - } - - showConfirmationModal(action: ConfirmationActions): void { - let initialState = {}; - if (action === ConfirmationActions.APPROVE_APPLICATION) { - const application_center = !this.selectedComputeCenter.FacilityId; - initialState = { application: this.application, action, application_center }; - } else { - initialState = { - application: this.application, - action, - }; + + unsetProcessingVoManager(application: Application): void { + if (this.is_vo_admin) { + this.voService.unsetProcessingVoManager(application.project_application_id).subscribe(() => { + application.processing_vo_initials = null; + }); + } + } + + showClientsLimitsModal(is_modification_request: boolean = false): void { + let initialState = {}; + if (is_modification_request) { + initialState = { + compute_center_id: this.application.project_application_compute_center.FacilityId, + application: this.application, + is_modification_request, + }; + } else { + initialState = { + compute_center_id: this.selectedComputeCenter.FacilityId, + application: this.application, + is_modification_request, + }; + } + + this.bsModalRef = this.modalService.show(ClientLimitsComponent, { initialState }); + this.subscribeToBsModalRef(); + } + + removeApplicationFromFacilityConfirmation(): void { + this.groupService.removeGroupFromResource(this.application.project_application_perun_id.toString()).subscribe( + (): void => { + this.triggerReloadApplication(); + this.showNotificationModal('Success', 'The application was removed from the compute center', 'success'); + }, + (): void => { + this.showNotificationModal('Failed', 'The application was removed from the compute center', 'danger'); + }, + ); + } + + assignGroupToFacility(): void { + if (this.selectedComputeCenter) { + this.groupService + .assignGroupToResource(this.application.project_application_perun_id, this.selectedComputeCenter.FacilityId) + .subscribe( + (): void => { + this.triggerReloadApplication(); + + this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); + }, + (error: object): void => { + console.log(error); + this.showNotificationModal('Failed', 'Project could not be created!', 'danger'); + }, + ); + } else { + this.showNotificationModal('Failed', 'You need to select an compute center!', 'danger'); + } } - this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); - this.subscribeToBsModalRef(); - } - - unsetProcessingVoManager(application: Application): void { - if (this.is_vo_admin) { - this.voService.unsetProcessingVoManager(application.project_application_id).subscribe(() => { - application.processing_vo_initials = null; + + resetApplicationPI(): void { + this.applicationsService.resetPIValidation(this.application).subscribe(() => { + this.triggerReloadApplication(); }); } - } - - showClientsLimitsModal(is_modification_request: boolean = false): void { - let initialState = {}; - if (is_modification_request) { - initialState = { - compute_center_id: this.application.project_application_compute_center.FacilityId, - application: this.application, - is_modification_request, - }; - } else { - initialState = { - compute_center_id: this.selectedComputeCenter.FacilityId, - application: this.application, - is_modification_request, - }; + + switchCollaps() { + this.switchCollapseEvent.emit(); } - this.bsModalRef = this.modalService.show(ClientLimitsComponent, { initialState }); - this.subscribeToBsModalRef(); - } - - removeApplicationFromFacilityConfirmation(): void { - this.groupService.removeGroupFromResource(this.application.project_application_perun_id.toString()).subscribe( - (): void => { - this.getApplication(); - this.showNotificationModal('Success', 'The application was removed from the compute center', 'success'); - }, - (): void => { - this.showNotificationModal('Failed', 'The application was removed from the compute center', 'danger'); - }, - ); - } - - getApplication(): void { - this.applicationsService.getApplication(this.application.project_application_id.toString()).subscribe( - (aj: Application): void => { - this.application = aj; - }, - (error: any): void => { - console.log(error); - }, - ); - } - - assignGroupToFacility(): void { - if (this.selectedComputeCenter) { - this.groupService - .assignGroupToResource(this.application.project_application_perun_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (): void => { - this.getApplication(); + showNotificationModal( + notificationModalTitle: string, + notificationModalMessage: string, + notificationModalType: string, + ) { + const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; + if (this.bsModalRef) { + this.bsModalRef.hide(); + } + + this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); + this.bsModalRef.setClass('modal-lg'); + } + + createSimpleVmProjectGroup(): void { + this.showNotificationModal('Info', 'Creating Project...', 'info'); + + if (this.selectedComputeCenter && this.selectedComputeCenter.FacilityId) { + this.groupService + .createGroupByApplication(this.application.project_application_id, this.selectedComputeCenter.FacilityId) + .subscribe( + (res: any): void => { + if (!res['client_available'] && !res['created']) { + this.showNotificationModal( + 'Failed', + `The client ${res['client_name']} has not the necessary resources left!`, + 'danger', + ); + } else { + this.showNotificationModal('Success', 'The project was created!', 'success'); + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); + } + }, + (error: any): void => { + console.log(error); + const errorMessage = error && error.error === 'locked' + ? 'Project is locked and could not be created!' + : 'Project could not be created!'; + + this.showNotificationModal('Failed', errorMessage, 'danger'); + console.log(error); + }, + ); + } + } + + approveModificationRequest(): void { + this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( + (res: Response): void => { + this.showNotificationModal('Success', 'The resource modification request was approved!', 'success'); + if (!this.application.project_application_openstack_project) { + if (res.status === HttpStatusCode.Accepted) { + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); + + // this.all_applications.splice(this.all_applications.indexOf(application), 1); + } + } else { + this.triggerReloadApplication(); + } + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Approval of resource modification failed!', 'danger'); + }, + ); + } + + declineModificationRequest(): void { + this.applicationsService.deleteModificationRequest(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Declined', 'The resource modification request was declined!', 'success'); + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + + this.triggerReloadApplication(); + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Decline of resource modification failed!', 'danger'); + }, + ); + } + + deleteApplication(): void { + // const idx: number = this.all_applications.indexOf(application); - this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); + this.subscription.add( + this.applicationsService.deleteApplication(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); }, - (error: object): void => { - console.log(error); - this.showNotificationModal('Failed', 'Project could not be created!', 'danger'); + (): void => { + this.updateNotificationModal('Failed', 'Application could not be removed!', true, 'danger'); }, - ); - } else { - this.showNotificationModal('Failed', 'You need to select an compute center!', 'danger'); + ), + ); } - } - - resetApplicationPI(): void { - this.applicationsService.resetPIValidation(this.application).subscribe(() => { - this.getApplication(); - }); - } - - switchCollaps() { - this.switchCollapseEvent.emit(); - } - - showNotificationModal( - notificationModalTitle: string, - notificationModalMessage: string, - notificationModalType: string, - ) { - const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; - if (this.bsModalRef) { - this.bsModalRef.hide(); + + declineLifetimeExtension(): void { + this.applicationsService.deleteAdditionalLifetimeRequests(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Declined', 'The project extension was declined!', 'success'); + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Decline of project extension failed!', 'danger'); + }, + ); + } + + declineCreditExtension(): void { + this.applicationsService.deleteAdditionalCreditsRequests(this.application.project_application_id).subscribe( + (): void => { + this.showNotificationModal('Declined', 'The credit extension request was declined!', 'success'); + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Decline of credit extension failed!', 'danger'); + }, + ); } - this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); - this.bsModalRef.setClass('modal-lg'); - } + declineApplication(): void { + // const idx: number = this.all_applications.indexOf(app); + this.applicationsService.declineApplication(this.application.project_application_id).subscribe( + (): void => { + const message: string = 'The Application was declined.'; + + this.showNotificationModal('Success', message, 'success'); + this.triggerRemoveApplication(); + this.triggerReloadNumbers(); + }, + (): void => { + this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); + }, + ); + } + + approveLifetimeExtension(): void { + this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( + (res: Response): void => { + if (this.application.project_application_openstack_project) { + this.triggerReloadApplication(); + this.showNotificationModal('Success', 'The request has been sent to the facility manager.', 'success'); + } else { + this.showNotificationModal('Success', 'The project has been extended!', 'success'); + } + if (!this.application.project_application_openstack_project) { + if (res.status === HttpStatusCode.Accepted) { + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + } + } + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Project lifetime could not be extendend!', 'danger'); + }, + ); + } - createSimpleVmProjectGroup(): void { - this.showNotificationModal('Info', 'Creating Project...', 'info'); + approveCreditExtension(): void { + this.applicationsService.approveAdditionalCreditsRequest(this.application.project_application_id).subscribe( + (res: Response): void => { + this.showNotificationModal('Success', 'The credit extension request was approved!', 'success'); + if (!this.application.project_application_openstack_project) { + if (res.status === HttpStatusCode.Accepted) { + this.triggerReloadNumbers(); + this.triggerRemoveApplication(); + } + } else { + this.triggerReloadApplication(); + } + }, + (err: any): void => { + console.log('error', err.status); + this.showNotificationModal('Failed', 'Approval of credit extension failed!', 'danger'); + }, + ); + } - if (this.selectedComputeCenter && this.selectedComputeCenter.FacilityId) { + createOpenStackProjectGroup(): void { this.groupService - .createGroupByApplication(this.application.project_application_id, this.selectedComputeCenter.FacilityId) + .createGroupOpenStack(this.application.project_application_id, this.selectedComputeCenter.FacilityId) .subscribe( - (res: any): void => { - if (!res['client_available'] && !res['created']) { - this.showNotificationModal( - 'Failed', - `The client ${res['client_name']} has not the necessary resources left!`, - 'danger', - ); + (result: { [key: string]: string }): void => { + if (result['Error']) { + this.showNotificationModal('Failed', result['Error'], 'danger'); } else { - this.showNotificationModal('Success', 'The project was created!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); + this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); + this.triggerReloadApplication(); + // this.switchApproveLocked(false); } }, (error: any): void => { - console.log(error); - const errorMessage = error && error.error === 'locked' + const errorMessage = error && error.error === 'locked' ? 'Project is locked and could not be created!' : 'Project could not be created!'; @@ -255,233 +423,66 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements }, ); } - } - - approveModificationRequest(): void { - this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The resource modification request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - // this.all_applications.splice(this.all_applications.indexOf(application), 1); + /** + * Function to listen to modal results. + */ + subscribeToBsModalRef(): void { + this.subscription.add( + this.bsModalRef.content.event.subscribe((result: any) => { + let action = null; + if ('action' in result) { + action = result['action']; } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of resource modification failed!', 'danger'); - }, - ); - } - - declineModificationRequest(): void { - this.applicationsService.deleteModificationRequest(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The resource modification request was declined!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - - this.getApplication(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of resource modification failed!', 'danger'); - }, - ); - } - - deleteApplication(): void { - // const idx: number = this.all_applications.indexOf(application); - - this.subscription.add( - this.applicationsService.deleteApplication(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.updateNotificationModal('Failed', 'Application could not be removed!', true, 'danger'); - }, - ), - ); - } - - declineLifetimeExtension(): void { - this.applicationsService.deleteAdditionalLifetimeRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The project extension was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of project extension failed!', 'danger'); - }, - ); - } - - declineCreditExtension(): void { - this.applicationsService.deleteAdditionalCreditsRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The credit extension request was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of credit extension failed!', 'danger'); - }, - ); - } - - declineApplication(): void { - // const idx: number = this.all_applications.indexOf(app); - this.applicationsService.declineApplication(this.application.project_application_id).subscribe( - (): void => { - const message: string = 'The Application was declined.'; - - this.showNotificationModal('Success', message, 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); - }, - ); - } - - approveLifetimeExtension(): void { - this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( - (res: Response): void => { - if (this.application.project_application_openstack_project) { - this.getApplication(); - this.showNotificationModal('Success', 'The request has been sent to the facility manager.', 'success'); - } else { - this.showNotificationModal('Success', 'The project has been extended!', 'success'); - } - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); + if ('createSimpleVM' in result) { + this.createSimpleVmProjectGroup(); } - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Project lifetime could not be extendend!', 'danger'); - }, - ); - } - - approveCreditExtension(): void { - this.applicationsService.approveAdditionalCreditsRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The credit extension request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); + if (action === ConfirmationActions.APPROVE_MODIFICATION) { + this.approveModificationRequest(); } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of credit extension failed!', 'danger'); - }, - ); - } - - createOpenStackProjectGroup(): void { - this.groupService - .createGroupOpenStack(this.application.project_application_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (result: { [key: string]: string }): void => { - if (result['Error']) { - this.showNotificationModal('Failed', result['Error'], 'danger'); - } else { - this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); - this.getApplication(); - // this.switchApproveLocked(false); + if ('closed' in result) { + // this.switchApproveLocked(false); + } + if (action === ConfirmationActions.DECLINE_MODIFICATION) { + this.declineModificationRequest(); + } + if (action === ConfirmationActions.DELETE_APPLICATION) { + this.deleteApplication(); + } + if (action === ConfirmationActions.DECLINE_EXTENSION) { + this.declineLifetimeExtension(); + } + if (action === ConfirmationActions.DECLINE_CREDITS) { + this.declineCreditExtension(); + } + if (action === ConfirmationActions.DECLINE_APPLICATION) { + this.declineApplication(); } - }, - (error: any): void => { - const errorMessage = error && error.error === 'locked' - ? 'Project is locked and could not be created!' - : 'Project could not be created!'; - this.showNotificationModal('Failed', errorMessage, 'danger'); - console.log(error); - }, + if (action === ConfirmationActions.APPROVE_EXTENSION) { + this.approveLifetimeExtension(); + } + if (action === ConfirmationActions.RESET_PI) { + this.resetApplicationPI(); + } + if (action === ConfirmationActions.APPROVE_CREDITS) { + this.approveCreditExtension(); + } + if (action === ConfirmationActions.APPROVE_APPLICATION) { + if (this.application.project_application_openstack_project) { + this.createOpenStackProjectGroup(); + } + } + if (action === 'adjustedModificationRequest') { + // this.isLoaded = false; + // this.changeTabState(ApplicationTabStates.MODIFICATION_EXTENSION); + } + }), ); - } - - /** - * Function to listen to modal results. - */ - subscribeToBsModalRef(): void { - this.subscription.add( - this.bsModalRef.content.event.subscribe((result: any) => { - let action = null; - if ('action' in result) { - action = result['action']; - } - if ('createSimpleVM' in result) { - this.createSimpleVmProjectGroup(); - } - if (action === ConfirmationActions.APPROVE_MODIFICATION) { - this.approveModificationRequest(); - } - if ('closed' in result) { - // this.switchApproveLocked(false); - } - if (action === ConfirmationActions.DECLINE_MODIFICATION) { - this.declineModificationRequest(); - } - if (action === ConfirmationActions.DELETE_APPLICATION) { - this.deleteApplication(); - } - if (action === ConfirmationActions.DECLINE_EXTENSION) { - this.declineLifetimeExtension(); - } - if (action === ConfirmationActions.DECLINE_CREDITS) { - this.declineCreditExtension(); - } - if (action === ConfirmationActions.DECLINE_APPLICATION) { - this.declineApplication(); - } + } - if (action === ConfirmationActions.APPROVE_EXTENSION) { - this.approveLifetimeExtension(); - } - if (action === ConfirmationActions.RESET_PI) { - this.resetApplicationPI(); - } - if (action === ConfirmationActions.APPROVE_CREDITS) { - this.approveCreditExtension(); - } - if (action === ConfirmationActions.APPROVE_APPLICATION) { - if (this.application.project_application_openstack_project) { - this.createOpenStackProjectGroup(); - } - } - if (action === 'adjustedModificationRequest') { - // this.isLoaded = false; - // this.changeTabState(ApplicationTabStates.MODIFICATION_EXTENSION); - } - }), - ); - } - - isCollapsed: boolean = true; - protected readonly Application_States = Application_States; - protected readonly ConfirmationActions = ConfirmationActions; - protected readonly ApplicationTabStates = ApplicationTabStates; + isCollapsed: boolean = true; + protected readonly Application_States = Application_States; + protected readonly ConfirmationActions = ConfirmationActions; + protected readonly ApplicationTabStates = ApplicationTabStates; } From bd01b4f50e4f61e2130570a29e1ccb092bf003d8 Mon Sep 17 00:00:00 2001 From: dweinholz Date: Tue, 9 Jul 2024 09:18:00 +0200 Subject: [PATCH 02/10] started refactoring tremplated mail --- .../facilityprojectsoverview.component.ts | 4 - ...t-csv-templated-email-modal.component.html | 213 ++++++++++++ ...ect-csv-templated-email-modal.component.ts | 109 ++++++ .../project-csv-templated-email.scss | 25 ++ .../project-email-modal.component.html | 312 +++++++++--------- .../shared_modules/shared-module.module.ts | 5 + src/app/vo_manager/VoOverviewComponent.ts | 33 +- src/app/vo_manager/voOverview.component.html | 3 +- 8 files changed, 518 insertions(+), 186 deletions(-) create mode 100644 src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html create mode 100644 src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts create mode 100644 src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss diff --git a/src/app/facility_manager/facilityprojectsoverview.component.ts b/src/app/facility_manager/facilityprojectsoverview.component.ts index 4bbf018218..bcade8d803 100644 --- a/src/app/facility_manager/facilityprojectsoverview.component.ts +++ b/src/app/facility_manager/facilityprojectsoverview.component.ts @@ -196,10 +196,6 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme this.sortProjectService.sortDirection = direction; } - searchForUserInFacility(searchString: string): void { - this.facilityService.getFilteredMembersOfFacility(searchString); - } - filterMembers(bare_searchString: string): void { this.filteredMembers = []; const searchString: string = bare_searchString.toLowerCase(); diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html new file mode 100644 index 0000000000..337d2c0538 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html @@ -0,0 +1,213 @@ + + + + + + \ No newline at end of file diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts new file mode 100644 index 0000000000..24c7ab91b7 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts @@ -0,0 +1,109 @@ +import { + Component, EventEmitter, Input, OnDestroy, OnInit, +} from '@angular/core'; +import { BsModalRef } from 'ngx-bootstrap/modal'; +import { Application } from '../../../../applications/application.model/application.model'; +import { IResponseTemplate } from '../../../../api-connector/response-template'; +import { EmailService } from '../../../../api-connector/email.service'; +import { STATUS_LINK } from '../../../../../links/links'; +import { CsvMailTemplateModel } from '../../../classes/csvMailTemplate.model'; + +@Component({ + selector: 'app-project-csv-templated-email-modal', + templateUrl: './project-csv-templated-email-modal.component.html', + styleUrls: ['./project-csv-templated-email.scss'], + providers: [EmailService], +}) +export class ProjectCsvTemplatedEmailModalComponent implements OnInit, OnDestroy { + selectedProjects: Application[]; + csvMailTemplate: CsvMailTemplateModel; + csvFile: File; + + emailAdminsOnly: boolean; + emailSubject: string; + emailReply: string; + emailText: string; + templates: string[]; + validCSVExample = `Project, VM, LOCATION +Proj1, VM_1, Bielefeld +Proj2, VM_2, Giessen`; + + public event: EventEmitter = new EventEmitter(); + + constructor( + public bsModalRef: BsModalRef, + private emailService: EmailService, + ) { + // eslint-disable-next-line no-empty-function + } + + ngOnInit() { + this.getMailTemplates(); + } + + onCsvFileSelected(event): void { + const inputElement = event.target as HTMLInputElement; + this.csvFile = inputElement.files[0]; + if (this.csvFile) { + this.emailService.sendCsvTemplate(this.csvFile).subscribe( + (csvTemplate: CsvMailTemplateModel) => { + this.csvMailTemplate = csvTemplate; + + }, + (error: CsvMailTemplateModel) => { + this.csvMailTemplate = error; + console.log(error['error']); + }, + ); + } + } + + getMailTemplates(): void { + this.emailService.getMailTemplates().subscribe((res: string[]) => { + this.templates = res; + }); + } + + sentProjectsTemplatedMail(): void { + const project_ids = this.selectedProjects.map((pr: Application) => pr.project_application_perun_id); + + this.emailService + .sendCsvTemplatedMail( + this.csvFile, + project_ids, + this.emailSubject, + this.emailText, + this.emailAdminsOnly, + this.emailReply, + ) + .subscribe( + (res: IResponseTemplate) => { + this.event.emit(res.value as boolean); + }, + () => { + this.event.emit(false); + }, + ); + } + + sentProjectsMail(): void { + const project_ids = this.selectedProjects.map((pr: Application) => pr.project_application_perun_id); + + this.emailService + .sendMailToProjects(project_ids, this.emailSubject, this.emailText, this.emailAdminsOnly, this.emailReply) + .subscribe( + (res: IResponseTemplate) => { + this.event.emit(res.value as boolean); + }, + () => { + this.event.emit(false); + }, + ); + } + + ngOnDestroy(): void { + this.bsModalRef.hide(); + } + + protected readonly STATUS_LINK = STATUS_LINK; +} diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss new file mode 100644 index 0000000000..a86e9ffc41 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss @@ -0,0 +1,25 @@ +.templates-container { + border: 1px solid #ccc; + padding: 10px; + background-color: #f9f9f9; +} + +.templates-list { + margin: 10px 0; + font-family: monospace; +} + +.valid-example { + border: 1px solid #ccc; + padding: 10px; + background-color: #f9f9f9; + margin-top: 10px; +} + +.valid-example-heading { + margin-bottom: 5px; +} + +.valid-example-content { + font-family: monospace; +} \ No newline at end of file diff --git a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html index 5584431736..683f4adf5a 100644 --- a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html +++ b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html @@ -1,179 +1,187 @@ + +
+

+ The following keys were provided by the CSV file: {{ csvFile.name }} +

+
+ {{ '{' + template + '}' }} +
+
-
-

You can use the following keys as variables:

-
- {{ '{' + template + '}' }} -
-
+
+

You can use the following keys as variables:

+
+ {{ '{' + template + '}' }} +
+
-
- Please consider: In case any dates are part of the sent E-Mails, they will be formatted in the german - TT.MM.YYYY-format. -
+
+ Please consider: In case any dates are part of the sent E-Mails, they will be formatted in the german + TT.MM.YYYY-format. +
+ } diff --git a/src/app/shared/shared_modules/shared-module.module.ts b/src/app/shared/shared_modules/shared-module.module.ts index eab670b22f..6c985ba778 100644 --- a/src/app/shared/shared_modules/shared-module.module.ts +++ b/src/app/shared/shared_modules/shared-module.module.ts @@ -16,6 +16,9 @@ import { SharedDirectivesModule } from './shared_directives.module'; import { MaintenanceNotificationComponent } from './components/maintenance-notification/maintenance-notification.component'; import { PipeModuleModule } from '../../pipe-module/pipe-module.module'; import { MembersListModalComponent } from '../modal/members/members-list-modal.component'; +import { + ProjectCsvTemplatedEmailModalComponent, +} from '../modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component'; /** * Shared module. @@ -30,6 +33,7 @@ import { MembersListModalComponent } from '../modal/members/members-list-modal.c MigrationInformationComponent, ApplicationBadgesComponent, ProjectEmailModalComponent, + ProjectCsvTemplatedEmailModalComponent, TestimonialFormComponent, MaintenanceNotificationComponent, ], @@ -53,6 +57,7 @@ import { MembersListModalComponent } from '../modal/members/members-list-modal.c MigrationInformationComponent, ApplicationBadgesComponent, ProjectEmailModalComponent, + ProjectCsvTemplatedEmailModalComponent, TestimonialFormComponent, MaintenanceNotificationComponent, ], diff --git a/src/app/vo_manager/VoOverviewComponent.ts b/src/app/vo_manager/VoOverviewComponent.ts index 9a207966b7..3f392670e6 100644 --- a/src/app/vo_manager/VoOverviewComponent.ts +++ b/src/app/vo_manager/VoOverviewComponent.ts @@ -26,6 +26,9 @@ import { ConfirmationActions } from '../shared/modal/confirmation_actions'; import { MembersListModalComponent } from '../shared/modal/members/members-list-modal.component'; import { EmailService } from '../api-connector/email.service'; import { CsvMailTemplateModel } from '../shared/classes/csvMailTemplate.model'; +import { + ProjectCsvTemplatedEmailModalComponent, +} from '../shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component'; /** * Vo Overview component. @@ -122,21 +125,6 @@ export class VoOverviewComponent extends AbstractBaseClass implements OnInit, On this.subscription.unsubscribe(); } - onCsvFileSelected(event): void { - const inputElement = event.target as HTMLInputElement; - if (inputElement.files && inputElement.files.length > 0) { - this.emailService.sendCsvTemplate(inputElement.files[0]).subscribe( - (csvTemplate: CsvMailTemplateModel) => { - this.openProjectMailsModal(inputElement.files[0], csvTemplate); - }, - (error: CsvMailTemplateModel) => { - console.log(error['error']); - this.openProjectMailsModal(inputElement.files[0], error['error']); - }, - ); - } - } - getTSVInformation(timeout: number = this.checkTSVTimeout): void { this.stopCheckTSVTimer(); this.subscription.add( @@ -252,20 +240,9 @@ export class VoOverviewComponent extends AbstractBaseClass implements OnInit, On } } - openProjectMailsModal(csvFile: File = null, csvTemplate: CsvMailTemplateModel = null): void { - let initialState = {}; - - if (csvFile) { - initialState = { - selectedProjects: csvTemplate.valid_projects, - csvFile, - csvMailTemplate: csvTemplate, - }; - } else { - initialState = { selectedProjects: this.selectedEmailProjects }; - } + openProjectMailsModal(): void { - this.bsModalRef = this.modalService.show(ProjectEmailModalComponent, { initialState, class: 'modal-lg' }); + this.bsModalRef = this.modalService.show(ProjectCsvTemplatedEmailModalComponent, { class: 'modal-lg' }); this.bsModalRef.content.event.subscribe((sent_successfully: boolean) => { if (sent_successfully) { this.updateNotificationModal('Success', 'Mails were successfully sent', true, 'success'); diff --git a/src/app/vo_manager/voOverview.component.html b/src/app/vo_manager/voOverview.component.html index 439ddfcc7d..d70da89c96 100644 --- a/src/app/vo_manager/voOverview.component.html +++ b/src/app/vo_manager/voOverview.component.html @@ -34,8 +34,7 @@ {{ selectedEmailProjects?.length }} - -
- -
diff --git a/src/app/facility_manager/facilityprojectsoverview.component.ts b/src/app/facility_manager/facilityprojectsoverview.component.ts index bcade8d803..03910a2a8c 100644 --- a/src/app/facility_manager/facilityprojectsoverview.component.ts +++ b/src/app/facility_manager/facilityprojectsoverview.component.ts @@ -19,10 +19,12 @@ import { import { ProjectSortService } from '../shared/shared_modules/services/project-sort.service'; import { AbstractBaseClass } from '../shared/shared_modules/baseClass/abstract-base-class'; import { ProjectEmailModalComponent } from '../shared/modal/email/project-email-modal/project-email-modal.component'; -import { NotificationModalComponent } from '../shared/modal/notification-modal'; import { MembersListModalComponent } from '../shared/modal/members/members-list-modal.component'; import { EmailService } from '../api-connector/email.service'; import { CsvMailTemplateModel } from '../shared/classes/csvMailTemplate.model'; +import { + ProjectCsvTemplatedEmailModalComponent, +} from '../shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component'; /** * Facility Project overview component. @@ -43,9 +45,7 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme public memberFilter: string = ''; filteredMembers: object[] = []; selectedMember: object[] = []; - facility_members: object[] = []; - filterChanged: Subject = new Subject(); isLoaded: boolean = false; projects: Application[] = []; projectsCopy: Application[] = []; @@ -183,7 +183,12 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme ); } } + openProjectCSVMailModal(): void { + console.log('show'); + + this.bsModalRef = this.modalService.show(ProjectCsvTemplatedEmailModalComponent, { class: 'modal-lg' }); + } onSort({ column, direction }: SortEvent) { // resetting other headers this.headers.forEach(header => { @@ -512,24 +517,6 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme initialState = { selectedProjects: this.selectedEmailProjects }; } this.bsModalRef = this.modalService.show(ProjectEmailModalComponent, { initialState, class: 'modal-lg' }); - this.bsModalRef.content.event.subscribe((sent_successfully: boolean) => { - if (sent_successfully) { - const initialStateNotification = { - notificationModalTitle: 'Success', - notificationModalType: 'success', - notificationModalMessage: 'Mails were successfully sent', - }; - - this.modalService.show(NotificationModalComponent, { initialState: initialStateNotification }); - } else { - const initialStateNotification = { - notificationModalTitle: 'Failed', - notificationModalType: 'danger', - notificationModalMessage: 'Failed to send mails!', - }; - this.modalService.show(NotificationModalComponent, { initialState: initialStateNotification }); - } - }); } setFacilitySupportMails(supportMails: string): void { diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html index 337d2c0538..50e8fc8a12 100644 --- a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html @@ -10,7 +10,7 @@