diff --git a/.gitignore b/.gitignore index 6266efc908..f45b4f0a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,7 @@ npm-debug.log testem.log /typings - +/.nx #test environment /tests/environment.json *e2e/environment.json diff --git a/.nx/cache/18.3.4-nx.linux-x64-gnu.node b/.nx/cache/18.3.5-nx.linux-x64-gnu.node similarity index 54% rename from .nx/cache/18.3.4-nx.linux-x64-gnu.node rename to .nx/cache/18.3.5-nx.linux-x64-gnu.node index 29fb952f46..6edb22b819 100644 Binary files a/.nx/cache/18.3.4-nx.linux-x64-gnu.node and b/.nx/cache/18.3.5-nx.linux-x64-gnu.node differ diff --git a/.nx/cache/nx_files.nxt b/.nx/cache/nx_files.nxt index cd7fb4a75b..44653957fc 100644 Binary files a/.nx/cache/nx_files.nxt and b/.nx/cache/nx_files.nxt differ diff --git a/angular.json b/angular.json index 6208b048bb..fbba1ac331 100644 --- a/angular.json +++ b/angular.json @@ -33,7 +33,6 @@ ] }, "scripts": [ - "src/assets/js/matomo.js" ], "vendorChunk": true, "extractLicenses": false, diff --git a/package-lock.json b/package-lock.json index 031a5548c4..468482af1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "ngx-bootstrap": "12.0.0", "ngx-clipboard": "16.0.0", "ngx-cookie-service": "17.1.0", + "ngx-matomo-client": "6.2.0", "ngx-owl-carousel-o": "17.0.0", "ngx-scrollbar": "13.0.3", "postcss-loader": "8.1.1", @@ -12937,6 +12938,18 @@ "@angular/core": "^17.0.0" } }, + "node_modules/ngx-matomo-client": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ngx-matomo-client/-/ngx-matomo-client-6.2.0.tgz", + "integrity": "sha512-fPuTuns5WEEvwc/1N2dONyjA/JLMjrK1hTXo9n6jAGuDtymLZhGsoZvRfmLF1fvNuFi0hOO1xRzwgDnUOlsqAQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0 || ^18.0.0", + "@angular/core": "^17.0.0 || ^18.0.0" + } + }, "node_modules/ngx-owl-carousel-o": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/ngx-owl-carousel-o/-/ngx-owl-carousel-o-17.0.0.tgz", diff --git a/package.json b/package.json index d18435cf6e..5afada3c1a 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "ngx-bootstrap": "12.0.0", "ngx-clipboard": "16.0.0", "ngx-cookie-service": "17.1.0", + "ngx-matomo-client": "6.2.0", "ngx-owl-carousel-o": "17.0.0", "ngx-scrollbar": "13.0.3", "postcss-loader": "8.1.1", diff --git a/src/app/api-connector/applications.service.ts b/src/app/api-connector/applications.service.ts index 4987f0d22e..027032fc5e 100644 --- a/src/app/api-connector/applications.service.ts +++ b/src/app/api-connector/applications.service.ts @@ -58,9 +58,12 @@ export class ApplicationsService { } getLifetimeExtensionUser(lifetimeextension_id: string | number): Observable { - return this.http.get(`${ApiSettings.getApiBaseURL()}project_applications/lifetime/extensions/${lifetimeextension_id}/user/`, { - withCredentials: true, - }); + return this.http.get( + `${ApiSettings.getApiBaseURL()}project_applications/lifetime/extensions/${lifetimeextension_id}/user/`, + { + withCredentials: true, + }, + ); } getModificationUser(project_id: string | number): Observable { @@ -148,11 +151,11 @@ export class ApplicationsService { } /** - * Checks if some client has the resource available for an application. - * - * @param app_id - * @returns - */ + * Checks if some client has the resource available for an application. + * + * @param app_id + * @returns + */ getApplicationClientAvaiable(app_id: string): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}project_applications/${app_id}/clients/resource/`, { withCredentials: true, diff --git a/src/app/api-connector/credits.service.ts b/src/app/api-connector/credits.service.ts index 39a96f0536..352b5c1236 100644 --- a/src/app/api-connector/credits.service.ts +++ b/src/app/api-connector/credits.service.ts @@ -21,10 +21,13 @@ export class CreditsService { * @returns The expected credits for the resources. */ public getCreditsForApplication(flavors: Flavor[], months: number): Observable { - - return this.http.post(`${ApiSettings.getApiBaseURL()}creditManager/getCreditsForApplication/`, { flavors, months }, { - withCredentials: true, - }); + return this.http.post( + `${ApiSettings.getApiBaseURL()}creditManager/getCreditsForApplication/`, + { flavors, months }, + { + withCredentials: true, + }, + ); } /** @@ -32,8 +35,15 @@ export class CreditsService { * * @returns The expected credits for the resources. */ - public getExtraCreditsForExtension(cpus: number, ram: number, months: number, projectApplicationId: string): Observable { - const params: HttpParams = new HttpParams().set('new_cpu', cpus.toString()).set('new_ram', ram.toString()) + public getExtraCreditsForExtension( + cpus: number, + ram: number, + months: number, + projectApplicationId: string, + ): Observable { + const params: HttpParams = new HttpParams() + .set('new_cpu', cpus.toString()) + .set('new_ram', ram.toString()) .set('new_lifetime', months.toString()) .set('project_application_id', projectApplicationId); @@ -49,7 +59,8 @@ export class CreditsService { * @returns The expected credits for the resources. */ public getExtraCreditsForLifetimeExtension(months: number, projectApplicationId: string): Observable { - const params: HttpParams = new HttpParams().set('new_lifetime', months.toString()) + const params: HttpParams = new HttpParams() + .set('new_lifetime', months.toString()) .set('project_application_id', projectApplicationId); return this.http.get(`${ApiSettings.getApiBaseURL()}creditManager/getExtraCreditsNumberLifetime/`, { @@ -64,7 +75,6 @@ export class CreditsService { * @returns The expected credits for the resources. */ public getExtraCreditsForResourceExtension(flavors: Flavor[], projectApplicationId: string): Observable { - return this.http.post( `${ApiSettings.getApiBaseURL()}creditManager/getExtraCreditsNumberResource/`, { flavors, projectApplicationId }, @@ -116,7 +126,10 @@ export class CreditsService { start_timestamp: number, ): Observable<{}> { const params: {} = { - hours, flavor_pairs, compute_center_name, start_timestamp, + hours, + flavor_pairs, + compute_center_name, + start_timestamp, }; return this.http.post(`${ApiSettings.getApiBase()}public/credits_calculator/needed/`, params, { @@ -131,7 +144,10 @@ export class CreditsService { start_timestamp: number, ): Observable<{}> { const params: {} = { - credits, flavor_pairs, compute_center_name, start_timestamp, + credits, + flavor_pairs, + compute_center_name, + start_timestamp, }; return this.http.post(`${ApiSettings.getApiBase()}public/credits_calculator/time/`, params, { @@ -140,13 +156,10 @@ export class CreditsService { } public getCreditsWeights(): Observable { - - return this.http.get(`${ApiSettings.getApiBase()}public/creditsweights/`).pipe( - map( - (weights: IResourceWeight[]): ResourceWeight[] => weights.map( - (weight: IResourceWeight): ResourceWeight => new ResourceWeight(weight), - ), - ), - ); + return this.http + .get(`${ApiSettings.getApiBase()}public/creditsweights/`) + .pipe( + map((weights: IResourceWeight[]): ResourceWeight[] => weights.map((weight: IResourceWeight): ResourceWeight => new ResourceWeight(weight))), + ); } } diff --git a/src/app/api-connector/facility.service.ts b/src/app/api-connector/facility.service.ts index 8c09bb0720..014f5b4657 100644 --- a/src/app/api-connector/facility.service.ts +++ b/src/app/api-connector/facility.service.ts @@ -24,10 +24,10 @@ export class FacilityService { } /** - * Get all available computecenters. - * - * @returns - */ + * Get all available computecenters. + * + * @returns + */ getComputeCenters(): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}computecenters/`, { withCredentials: true, @@ -35,8 +35,8 @@ export class FacilityService { } /** - * Sets support e-mail addresses for computecenter. - */ + * Sets support e-mail addresses for computecenter. + */ setSupportMails(facilityId: string, supportMails: string): Observable { const params: HttpParams = new HttpParams().set('mails', supportMails); @@ -47,8 +47,8 @@ export class FacilityService { } /** - * Get support e-mail addresses for computecenter. - */ + * Get support e-mail addresses for computecenter. + */ getSupportMails(facilityId: string): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}computecenters/${facilityId}/supportMails/`, { withCredentials: true, @@ -146,11 +146,11 @@ export class FacilityService { } /** - * Sets the newsID of the facility news which contains the motd for facility with the corresponding facility ID. - * - * @param facilityID facility id of the facility to set the id - * @param newsId the id of the news containing the motd - */ + * Sets the newsID of the facility news which contains the motd for facility with the corresponding facility ID. + * + * @param facilityID facility id of the facility to set the id + * @param newsId the id of the news containing the motd + */ setMOTDForFacility(facilityID: string, newsId: string): Observable { const httpParams: HttpParams = new HttpParams().set('facilityID', facilityID).set('newsID', newsId); @@ -160,10 +160,10 @@ export class FacilityService { } /** - * Get all facility, where the current user is manager. - * - * @returns - */ + * Get all facility, where the current user is manager. + * + * @returns + */ getManagerFacilities(): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}facilityManagers/current/facilities/`, { withCredentials: true, @@ -178,12 +178,12 @@ export class FacilityService { } /** - * Get allowed groups from a facility with a specific status. - * - * @param facility - * @param status - * @returns - */ + * Get allowed groups from a facility with a specific status. + * + * @param facility + * @param status + * @returns + */ getFacilityAllowedGroupsWithDetailsAndSpecificStatus( facility: number | string, status: number, @@ -199,17 +199,26 @@ export class FacilityService { } /** - * Gets FacilityGroups by the elixirId of the member. - * - * @param facility the facility - * @param elixir_id the id of the member - */ - getFacilityGroupsByMemberElixirId(facility: number | string, elixir_id: string, isPi: boolean, isAdmin: boolean, isMember: boolean): Observable { + * Gets FacilityGroups by the elixirId of the member. + * + * @param facility the facility + * @param elixir_id the id of the member + */ + getFacilityGroupsByMemberElixirId( + facility: number | string, + elixir_id: string, + isPi: boolean, + isAdmin: boolean, + isMember: boolean, + ): Observable { return this.http .get(`${ApiSettings.getApiBaseURL()}computecenters/${facility}/projects/filter/`, { withCredentials: true, params: { - elixir_id, isPi, isAdmin, isMember, + elixir_id, + isPi, + isAdmin, + isMember, }, }) .pipe( @@ -218,11 +227,11 @@ export class FacilityService { } /** - * Get all resources assigned to a facility. - * - * @param facility id of the facility - * @returns - */ + * Get all resources assigned to a facility. + * + * @param facility id of the facility + * @returns + */ getFacilityResources(facility: number | string): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}computecenters/${facility}/projects/resources/`, { withCredentials: true, @@ -230,11 +239,11 @@ export class FacilityService { } /** - * Gets all facility applications which are waiting for conirmation. - * - * @param facility - * @returns - */ + * Gets all facility applications which are waiting for conirmation. + * + * @param facility + * @returns + */ getFacilityApplicationsWaitingForConfirmation(facility: number | string): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}computecenters/${facility}/applications/`, { withCredentials: true, @@ -242,11 +251,11 @@ export class FacilityService { } /** - * Gets all facility applications history. - * - * @param facility - * @returns - */ + * Gets all facility applications history. + * + * @param facility + * @returns + */ getFacilityApplicationsHistory(facility: number | string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/applications_history/`, @@ -257,11 +266,11 @@ export class FacilityService { } /** - * Get application for facility by id. - * - * @param facility self-speaking - * @param id self-speaking - */ + * Get application for facility by id. + * + * @param facility self-speaking + * @param id self-speaking + */ getFacilityApplicationById(facility: number | string, id: string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/applications/${id}/detail/`, @@ -272,11 +281,11 @@ export class FacilityService { } /** - * Gets all volumes from a specific facility. - * - * @param facility - * @returns - */ + * Gets all volumes from a specific facility. + * + * @param facility + * @returns + */ getFacilityVolumes(facility: number | string, items_per_page: number, current_page: number): Observable { const params: HttpParams = new HttpParams() .set('items_per_page', items_per_page.toString()) @@ -291,13 +300,13 @@ export class FacilityService { } /** - * Gets all volumes from a specific facility. - * - * @param facility - * @param currentPage - * @param snapsPerSite - * @returns - */ + * Gets all volumes from a specific facility. + * + * @param facility + * @param currentPage + * @param snapsPerSite + * @returns + */ getFacilitySnapshots( facility: number | string, currentPage: number, @@ -320,11 +329,11 @@ export class FacilityService { } /** - * Gets all facility modification applications which are waiting for conirmation. - * - * @param facility - * @returns - */ + * Gets all facility modification applications which are waiting for conirmation. + * + * @param facility + * @returns + */ getFacilityModificationApplicationsWaitingForConfirmation(facility: number | string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/modification_applications/`, @@ -335,12 +344,12 @@ export class FacilityService { } /** - * Approves an facility application. - * - * @param facility - * @param application_id - * @returns - */ + * Approves an facility application. + * + * @param facility + * @param application_id + * @returns + */ approveFacilityApplication(facility: number | string, application_id: number | string): Observable { const params: HttpParams = new HttpParams().set('action', 'approve'); @@ -385,12 +394,12 @@ export class FacilityService { } /** - * Deletes an RamFactor. - * - * @param facility - * @param resource_machine_id - * @returns - */ + * Deletes an RamFactor. + * + * @param facility + * @param resource_machine_id + * @returns + */ deleteResourceMachine( facility: number | string, resource_machine_id: number | string, @@ -516,11 +525,11 @@ export class FacilityService { } /** - * Updates the CoreFactor. - * - * @param facility - * @param factor - */ + * Updates the CoreFactor. + * + * @param facility + * @param factor + */ updateVolumeStorageFactor(facility: number | string, factor: VolumeStorageFactor): Observable { const params: HttpParams = new HttpParams().set('factor', JSON.stringify(factor)); @@ -535,11 +544,11 @@ export class FacilityService { } /** - * Updates the CoreFactor. - * - * @param facility - * @param factor - */ + * Updates the CoreFactor. + * + * @param facility + * @param factor + */ updateObjectStorageFactor(facility: number | string, factor: ObjectStorageFactor): Observable { const params: HttpParams = new HttpParams().set('factor', JSON.stringify(factor)); @@ -554,12 +563,12 @@ export class FacilityService { } /** - * Deletes an CoreFactor. - * - * @param facility - * @param factor_id - * @returns - */ + * Deletes an CoreFactor. + * + * @param facility + * @param factor_id + * @returns + */ deleteVolumeStorageFactor(facility: number | string, factor_id: number | string): Observable { return this.http.delete( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/resources/volumeStorageFactors/${factor_id}/`, @@ -570,12 +579,12 @@ export class FacilityService { } /** - * Deletes an CoreFactor. - * - * @param facility - * @param factor_id - * @returns - */ + * Deletes an CoreFactor. + * + * @param facility + * @param factor_id + * @returns + */ deleteObjectStorageFactor(facility: number | string, factor_id: number | string): Observable { return this.http.delete( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/resources/objectStorageFactors/${factor_id}/`, @@ -647,11 +656,11 @@ export class FacilityService { } /** - * Get CoreFactors from a facility. - * - * @param facility - * @returns - */ + * Get CoreFactors from a facility. + * + * @param facility + * @returns + */ getVolumeStorageFactors(facility: number | string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/resources/volumeStorageFactors/`, @@ -662,11 +671,11 @@ export class FacilityService { } /** - * Get CoreFactors from a facility. - * - * @param facility - * @returns - */ + * Get CoreFactors from a facility. + * + * @param facility + * @returns + */ getObjectStorageFactors(facility: number | string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/resources/objectStorageFactors/`, @@ -677,13 +686,13 @@ export class FacilityService { } /** - * Declines an application for the facility - * - * @param facility - * @param application_id - * @returns - */ - declineFacilityApplication(facility: string|number, application_id: number|string): Observable { + * Declines an application for the facility + * + * @param facility + * @param application_id + * @returns + */ + declineFacilityApplication(facility: string | number, application_id: number | string): Observable { const params: HttpParams = new HttpParams().set('action', 'decline'); return this.http.post( @@ -697,18 +706,18 @@ export class FacilityService { } /** - * Sends an email to all members of the facility. - * - * @param facility facility that should be contacted - * @param subject email subject - * @param message email message - * @param project_type which users to email - * @param reply reply address - * @param sendNews boolean if news should be send - * @param alternative_news_text an alternative news text - * @param news_tags additional tags - * @returns - */ + * Sends an email to all members of the facility. + * + * @param facility facility that should be contacted + * @param subject email subject + * @param message email message + * @param project_type which users to email + * @param reply reply address + * @param sendNews boolean if news should be send + * @param alternative_news_text an alternative news text + * @param news_tags additional tags + * @returns + */ sendMailToFacility( facility: string, subject: string, @@ -736,12 +745,12 @@ export class FacilityService { } /** - * Get Members of a project with emails. - * - * @param groupid id of the group - * @param facility id of the facility - * @returns - */ + * Get Members of a project with emails. + * + * @param groupid id of the group + * @param facility id of the facility + * @returns + */ getFacilityGroupRichMembers(groupid: number | string, facility: number | string): Observable { return this.http.get( `${ApiSettings.getApiBaseURL()}computecenters/${facility}/projects/${groupid}/members/`, @@ -760,13 +769,13 @@ export class FacilityService { }); } - approveTerminationByFM(groupId: number | string, facility: number|string): Observable { + approveTerminationByFM(groupId: number | string, facility: number | string): Observable { return this.http.delete(`${ApiSettings.getApiBaseURL()}computecenters/${facility}/projects/${groupId}/`, { withCredentials: true, }); } - declineTerminationByFM(groupId: number | string, facility: number|string): Observable { + declineTerminationByFM(groupId: number | string, facility: number | string): Observable { return this.http.get(`${ApiSettings.getApiBaseURL()}computecenters/${facility}/projects/${groupId}/`, { withCredentials: true, }); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a6a2d1f3bc..4c240f6b31 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,6 @@ import { HashLocationStrategy, LocationStrategy, CommonModule } from '@angular/common'; import { ErrorHandler, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; - import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { TabsModule } from 'ngx-bootstrap/tabs'; import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; @@ -9,7 +8,6 @@ import { NgChartsModule } from 'ng2-charts'; import { ModalModule } from 'ngx-bootstrap/modal'; import { PaginationModule } from 'ngx-bootstrap/pagination'; import { ClipboardModule } from 'ngx-clipboard'; - import { NgScrollbarModule } from 'ngx-scrollbar'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Angulartics2Module } from 'angulartics2'; @@ -18,6 +16,9 @@ import { TimepickerModule } from 'ngx-bootstrap/timepicker'; import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; import { NgSelectModule } from '@ng-select/ng-select'; import { AlertModule } from 'ngx-bootstrap/alert'; +import { MatomoModule, MatomoRouterModule } from 'ngx-matomo-client'; +import { environment } from '../environments/environment'; + import { AppComponent } from './app.component'; import { ApiSettings } from './api-connector/api-settings.service'; @@ -70,6 +71,11 @@ import { FacilityService } from './api-connector/facility.service'; TimepickerModule.forRoot(), BsDatepickerModule.forRoot(), AlertModule, + MatomoModule.forRoot({ + siteId: environment.MATOMO_SITE_ID, + trackerUrl: environment.MATOMO_TRACKING_URL, + }), + MatomoRouterModule, ], declarations: [ AppComponent, diff --git a/src/app/applications/application-card/application-card.component.html b/src/app/applications/application-card/application-card.component.html index af0582ae14..05d0a2ab73 100644 --- a/src/app/applications/application-card/application-card.component.html +++ b/src/app/applications/application-card/application-card.component.html @@ -1,49 +1,46 @@ - - - - {{ 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) { - - } - + + + + {{ 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 (!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 7d01029b74..e6c0a61873 100644 --- a/src/app/applications/application-card/application-card.component.ts +++ b/src/app/applications/application-card/application-card.component.ts @@ -23,105 +23,102 @@ import { User } from '../application.model/user.model'; export class ApplicationCardComponent 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(); - @Input() facilityView: boolean = false; - @Input() voView: boolean = false; - - bsModalRef: BsModalRef; - is_vo_admin: boolean = false; - selectedComputeCenter: ComputecenterComponent; - - ngOnInit() { - this.is_vo_admin = is_vo; - this.getAndSetPiAndUserApplication(); - - } - - getAndSetPiAndUserApplication() { - if (!this.application.project_application_user) { - this.getAndSetApplicationUser(); - } - if (!this.application.project_application_pi) { - this.getAndSetApplicationPi(); - } - - } - - getAndSetApplicationPi() { - this.applicationsService.getApplicationPI(this.application.project_application_id).subscribe((pi: User) => { - this.application.project_application_pi = pi; - - }); - } - - getAndSetApplicationUser() { - this.applicationsService.getApplicationUser(this.application.project_application_id).subscribe((user: User) => { - this.application.project_application_user = user; - - }); - } - - constructor( - private applicationsService: ApplicationsService, - private modalService: BsModalService, - private groupService: GroupService, - ) { - super(); - } - - triggerRemoveApplication() { - - this.removeApplicationTrigger.emit(this.application.project_application_id); - } - - triggerReloadNumbers() { - this.reloadNumbersTrigger.emit(); + @Input() application: Application; + @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; + @Input() computeCenters: ComputecenterComponent[] = []; + @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); + @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); + @Input() facilityView: boolean = false; + @Input() voView: boolean = false; + + bsModalRef: BsModalRef; + is_vo_admin: boolean = false; + selectedComputeCenter: ComputecenterComponent; + + ngOnInit() { + this.is_vo_admin = is_vo; + this.getAndSetPiAndUserApplication(); + } + + getAndSetPiAndUserApplication() { + if (!this.application.project_application_user) { + this.getAndSetApplicationUser(); } - - getApplication(): void { - this.applicationsService.getApplication(this.application.project_application_id.toString()).subscribe( - (aj: Application): void => { - this.application = aj; - }, - (error: any): void => { - console.log(error); - }, - ); + if (!this.application.project_application_pi) { + this.getAndSetApplicationPi(); } - - resetApplicationPI(): void { - this.applicationsService.resetPIValidation(this.application).subscribe((app: Application) => { - this.getApplication(); - }); + } + + getAndSetApplicationPi() { + this.applicationsService.getApplicationPI(this.application.project_application_id).subscribe((pi: User) => { + this.application.project_application_pi = pi; + }); + } + + getAndSetApplicationUser() { + this.applicationsService.getApplicationUser(this.application.project_application_id).subscribe((user: User) => { + this.application.project_application_user = user; + }); + } + + constructor( + private applicationsService: ApplicationsService, + private modalService: BsModalService, + private groupService: GroupService, + ) { + super(); + } + + triggerRemoveApplication() { + this.removeApplicationTrigger.emit(this.application.project_application_id); + } + + triggerReloadNumbers() { + this.reloadNumbersTrigger.emit(); + } + + getApplication(): void { + this.applicationsService.getApplication(this.application.project_application_id.toString()).subscribe( + (aj: Application): void => { + this.application = aj; + }, + (error: any): void => { + console.log(error); + }, + ); + } + + 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(); } - switchCollaps() { - this.isCollapsed = !this.isCollapsed; - } + this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); + this.bsModalRef.setClass('modal-lg'); + } - 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'); + 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( + 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( @@ -137,7 +134,7 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni }, (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!'; @@ -145,160 +142,155 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni 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'); + } + + 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(); - }, - (): 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'); - }, - ); - } + // 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(); - declineApplication(): void { - // const idx: number = this.all_applications.indexOf(app); - this.applicationsService.declineApplication(this.application.project_application_id).subscribe( + 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 => { - const message: string = 'The Application was declined.'; - - this.showNotificationModal('Success', message, 'success'); + this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); this.triggerRemoveApplication(); this.triggerReloadNumbers(); - }, (): void => { - this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); + this.updateNotificationModal('Failed', 'Application could not be removed!', true, '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(); - - } + ), + ); + } + + 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', '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(); } - }, - (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( + } 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'); @@ -309,7 +301,7 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni } }, (error: any): void => { - 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!'; @@ -317,67 +309,67 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni 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); + } + + /** + * 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(); } - }), - ); - } - - isCollapsed: boolean = true; - protected readonly Application_States = Application_States; - protected readonly ConfirmationActions = ConfirmationActions; - protected readonly ApplicationTabStates = ApplicationTabStates; + } + 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-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index 1fc75bf549..5ad723dca7 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -1,61 +1,106 @@ diff --git a/src/app/applications/application-detail/application-pi-detail/application-pi-detail.component.html b/src/app/applications/application-detail/application-pi-detail/application-pi-detail.component.html index 61032abcb1..d5d218bb85 100644 --- a/src/app/applications/application-detail/application-pi-detail/application-pi-detail.component.html +++ b/src/app/applications/application-detail/application-pi-detail/application-pi-detail.component.html @@ -1,98 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Approved by VO - {{ application?.approved_by_vo_manager }} -
Approved by FM - {{ application?.approved_by_facility_manager }} -
PI Name - @if (application.project_application_pi?.username) { - {{ application?.project_application_pi?.username }} - @if (application?.project_application_pi?.pi_project_count_total > 0) { - - {{ application?.project_application_pi?.pi_project_count_total }} - - - } - } @else if (this.application.project_application_pi_approved) { - - - } -
PI Email - @if (application?.project_application_pi?.email) { - {{ application?.project_application_pi?.email }} - } @else { - - - } -
PI institue or workgroup link
PI Affiliations - @if (application?.project_application_pi?.user_affiliations) { - {{ application?.project_application_pi?.user_affiliations }} - } @else { - - - } -
User Affiliations - @if (application?.project_application_pi?.user_affiliations) { - {{ application?.project_application_pi?.user_affiliations }} - } @else { - - - } -
User Name - @if (application?.project_application_pi?.username) { - {{ application?.project_application_pi?.username }} - } @else { - - - } -
User Email - @if (application?.project_application_pi?.email) { - {{ application?.project_application_pi?.email }} - } @else { - - - } -
Approved by VO + {{ application?.approved_by_vo_manager }} +
Approved by FM + {{ application?.approved_by_facility_manager }} +
PI Name + @if (application.project_application_pi?.username) { + {{ application?.project_application_pi?.username }} + @if (application?.project_application_pi?.pi_project_count_total > 0) { + + + {{ application?.project_application_pi?.pi_project_count_active }}/ + + {{ application?.project_application_pi?.pi_project_count_total }} + } + } @else if (this.application.project_application_pi_approved) { + + } +
PI Email + @if (application?.project_application_pi?.email) { + {{ application?.project_application_pi?.email }} + } @else { + + } +
PI institue or workgroup link
PI Affiliations + @if (application?.project_application_pi?.user_affiliations) { + {{ application?.project_application_pi?.user_affiliations }} + } @else { + + } +
User Affiliations + @if (application?.project_application_user?.user_affiliations) { + {{ application?.project_application_user?.user_affiliations }} + } @else { + + } +
User Name + @if (application?.project_application_user?.username) { + {{ application?.project_application_user?.username }} + } @else { + + } +
User Email + @if (application?.project_application_user?.email) { + {{ application?.project_application_user?.email }} + } @else { + + } +
diff --git a/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.html b/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.html index 4464d8082b..999841ec9d 100644 --- a/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.html +++ b/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.html @@ -1,58 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Lifetime Extension Requested from: - - @if (application?.project_lifetime_request?.user) { - {{ application?.project_lifetime_request?.user?.username }} - - ( {{ application?.project_lifetime_request?.user?.email }} | - {{ application?.project_lifetime_request?.user?.elixir_id }} - ) } - @else{ - - - } - -
Comment{{ application?.project_lifetime_request?.comment }}
Comment by Cloud Governance{{ application?.project_lifetime_request?.manager_comment }}
Extra Lifetime - {{ application?.project_lifetime_request?.extra_lifetime }} - month(s) - ending - {{ application?.project_lifetime_request?.new_end_date.length > 11 ? '' : 'on' }} - {{ application?.project_lifetime_request?.new_end_date }} - instead of - {{ application?.project_lifetime_request?.old_end_date }} -
Extra Credits - {{ application?.project_lifetime_request?.extra_credits }} - (Total: - {{ application?.totalLifetimeExtensionCredits }}) -
Date Submitted - {{ application?.project_lifetime_request?.date_submitted }} -
Lifetime Extension Requested from: + @if (application?.project_lifetime_request?.user) { + {{ application?.project_lifetime_request?.user?.username }} + + ( {{ application?.project_lifetime_request?.user?.email }} | + {{ application?.project_lifetime_request?.user?.elixir_id }} + ) + } @else { + + } +
Comment{{ application?.project_lifetime_request?.comment }}
Comment by Cloud Governance{{ application?.project_lifetime_request?.manager_comment }}
Extra Lifetime + {{ application?.project_lifetime_request?.extra_lifetime }} + month(s) - ending + {{ application?.project_lifetime_request?.new_end_date.length > 11 ? '' : 'on' }} + {{ application?.project_lifetime_request?.new_end_date }} + instead of + {{ application?.project_lifetime_request?.old_end_date }} +
Extra Credits + {{ application?.project_lifetime_request?.extra_credits }} + (Total: + {{ application?.totalLifetimeExtensionCredits }}) +
Date Submitted + {{ application?.project_lifetime_request?.date_submitted }} +
diff --git a/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.ts b/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.ts index 4998333c22..3f2a0e6f1c 100644 --- a/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.ts +++ b/src/app/applications/application-detail/lifetime-extension-detail/lifetime-extension-detail.component.ts @@ -11,19 +11,19 @@ import { User } from '../../application.model/user.model'; templateUrl: './lifetime-extension-detail.component.html', }) export class LifetimeExtensionDetailComponent extends ApplicationBaseClassComponent implements OnInit { - @Input() application: Application; + @Input() application: Application; - ngOnInit() { - this.getRequestingUser(); - } - - getRequestingUser() { - if (this.application.project_lifetime_request && !this.application.project_lifetime_request.user) { - this.applicationsService.getLifetimeExtensionUser(this.application.project_application_id).subscribe((user: User) => { + ngOnInit() { + this.getRequestingUser(); + } + getRequestingUser() { + if (this.application.project_lifetime_request && !this.application.project_lifetime_request.user) { + this.applicationsService + .getLifetimeExtensionUser(this.application.project_application_id) + .subscribe((user: User) => { this.application.project_lifetime_request.user = user; - }); - } } + } } diff --git a/src/app/applications/application-detail/modification-detail/modification-detail.component.html b/src/app/applications/application-detail/modification-detail/modification-detail.component.html index c655ba62e2..7874cc6770 100644 --- a/src/app/applications/application-detail/modification-detail/modification-detail.component.html +++ b/src/app/applications/application-detail/modification-detail/modification-detail.component.html @@ -1,104 +1,103 @@ - - - + + + - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - + >In development + Existing + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - + + - - + + - - + + - - - - + + + + - - - - - - - - + + + + + + + + - - - + + +
Modification Requested from:
Modification Requested from: @if (application?.project_modification_request?.user) { + + @if (application?.project_modification_request?.user) { + {{ application?.project_modification_request?.user?.username }} + ( {{ application?.project_modification_request?.user?.email }} | + {{ application?.project_modification_request?.user?.elixir_id }}) - {{ application?.project_modification_request?.user?.username }} - ( {{ application?.project_modification_request?.user?.email }} | - {{ application?.project_modification_request?.user?.elixir_id }})} - - @else{ - - - } -
Comment{{ application?.project_modification_request?.comment }}
Service status + } @else { + + } +
Comment{{ application?.project_modification_request?.comment }}
Service status In development - Existing -
VMs - Requested: - {{ application?.project_modification_request?.vms_requested }} -
Flavor: {{ flavor.name }}{{ application?.project_modification_request | flavorCounter: flavor }}
Total Cores
VMs + Requested: + {{ application?.project_modification_request?.vms_requested }} +
Flavor: {{ flavor.name }}{{ application?.project_modification_request | flavorCounter: flavor }}
Total Cores - {{ application?.project_modification_request?.total_cores }} -
Total RAM{{ application?.project_modification_request?.total_ram }} GB
Total GPUs - {{ application?.project_modification_request?.total_gpu }} -
+ {{ application?.project_modification_request?.total_cores }} +
Total RAM{{ application?.project_modification_request?.total_ram }} GB
Total GPUs + {{ application?.project_modification_request?.total_gpu }} +
Extra Credits
Extra Credits - {{ application?.project_modification_request?.extra_credits }} - (Total: {{ application?.totalModificationRequestCredits }}) -
+ {{ application?.project_modification_request?.extra_credits }} + (Total: {{ application?.totalModificationRequestCredits }}) +
Storage Limit
Storage Limit - {{ application?.project_modification_request?.volume_limit }} - GB -
Volume Counter + {{ application?.project_modification_request?.volume_limit }} + GB +
Volume Counter - {{ application?.project_modification_request?.volume_counter }} - volumes -
ObjectStorage - {{ application?.project_modification_request?.object_storage }} - GB -
Date Submitted + {{ application?.project_modification_request?.volume_counter }} + volumes +
ObjectStorage + {{ application?.project_modification_request?.object_storage }} + GB +
Date Submitted - {{ application?.project_modification_request?.date_submitted }} -
+ {{ application?.project_modification_request?.date_submitted }} +
diff --git a/src/app/applications/application-detail/modification-detail/modification-detail.component.ts b/src/app/applications/application-detail/modification-detail/modification-detail.component.ts index fc3af5ad93..ef1eccb51d 100644 --- a/src/app/applications/application-detail/modification-detail/modification-detail.component.ts +++ b/src/app/applications/application-detail/modification-detail/modification-detail.component.ts @@ -12,22 +12,19 @@ import { User } from '../../application.model/user.model'; templateUrl: './modification-detail.component.html', }) export class ModificationDetailComponent extends ApplicationBaseClassComponent implements OnInit { - @Input() application: Application; - @Input() is_vo_admin: boolean; - Application_States: typeof Application_States = Application_States; + @Input() application: Application; + @Input() is_vo_admin: boolean; + Application_States: typeof Application_States = Application_States; - ngOnInit() { - this.getRequestingUser(); - } - - getRequestingUser() { - if (this.application.project_modification_request && !this.application.project_modification_request.user) { - this.applicationsService.getModificationUser(this.application.project_application_id).subscribe((user: User) => { + ngOnInit() { + this.getRequestingUser(); + } - this.application.project_modification_request.user = user; - - }); - } + getRequestingUser() { + if (this.application.project_modification_request && !this.application.project_modification_request.user) { + this.applicationsService.getModificationUser(this.application.project_application_id).subscribe((user: User) => { + this.application.project_modification_request.user = user; + }); } - + } } diff --git a/src/app/applications/application-detail/resource-detail/resource-detail.component.html b/src/app/applications/application-detail/resource-detail/resource-detail.component.html index 11c78f76a6..fba0bb77b4 100644 --- a/src/app/applications/application-detail/resource-detail/resource-detail.component.html +++ b/src/app/applications/application-detail/resource-detail/resource-detail.component.html @@ -1,232 +1,329 @@ @if (application.project_modification_request) { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Modification
Modification Requested from: @if (application?.project_modification_request?.user) { - - {{ application?.project_modification_request?.user?.username }} - ( {{ application?.project_modification_request?.user?.email }} | - {{ application?.project_modification_request?.user?.elixir_id }}) - } @else { - - - } -
Comment{{ application?.project_modification_request?.comment }}
Service status - In development - Existing -
Date Submitted - {{ application?.project_modification_request?.date_submitted }} -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Modification
Modification Requested from: + @if (application?.project_modification_request?.user) { + {{ application?.project_modification_request?.user?.username }} + ( {{ application?.project_modification_request?.user?.email }} | + {{ application?.project_modification_request?.user?.elixir_id }}) + } @else { + + } +
Comment{{ application?.project_modification_request?.comment }}
Service status + In development + Existing +
Date Submitted + {{ application?.project_modification_request?.date_submitted }} +
} - - - - - - @if (application.project_modification_request) { - - - - } - - - - - - - @if (application.project_modification_request) { - - - - } - - - @for (flavorDiff of flavorDiffs; track flavorDiff.name) { - - - - @if (application.project_modification_request) { - - - - - } - - - } - - - - - - @if (application.project_modification_request) { - - - } - - - - - - @if (application.project_modification_request) { - - - } - - - - - @if (application.project_modification_request) { - - - } - - - - - - - @if (application.project_modification_request) { - - - } - - - - - - @if (application.project_modification_request) { - - - - } - - - - - - @if (application.project_modification_request) { - - - } - - - - - @if (application.project_modification_request) { - - - } - - - - - @if (application.project_modification_request) { - - - } - - + + + + @if (application.project_modification_request) { + + + + } + + + + + + + @if (application.project_modification_request) { + + + + } + + + @for (flavorDiff of flavorDiffs; track flavorDiff.name) { + + + + @if (application.project_modification_request) { + + + + } + + } + + + + + @if (application.project_modification_request) { + + + } + + + + + + @if (application.project_modification_request) { + + + } + + + + + @if (application.project_modification_request) { + + + } + + + + + + + @if (application.project_modification_request) { + + + } + + + + + + @if (application.project_modification_request) { + + + } + + + + + + @if (application.project_modification_request) { + + + } + + + + + @if (application.project_modification_request) { + + + } + + + + + @if (application.project_modification_request) { + + + } + +
ResourceCurrentChangesModification
VMs - {{ application?.project_application_vms_requested }} - - - {{ application.project_modification_request.vms_requested === application.project_application_vms_requested ? '' : (application.project_modification_request.vms_requested > application.project_application_vms_requested ? '+' : '-') }} {{ Math.abs(application.project_modification_request.vms_requested - application.project_application_vms_requested) }} - - {{ application.project_modification_request.vms_requested }}
Flavor: {{ flavorDiff.name }}{{ flavorDiff.current }} - - {{ flavorDiff.diff === 0 ? '' : (flavorDiff.diff > 0 ? '+' : '-') }} - {{ flavorDiff.diff }} - - {{ flavorDiff.new }}
Total Cores{{ application?.project_application_total_cores }} - - {{ application.project_modification_request.total_cores === application.project_application_total_cores ? '' : (application.project_modification_request.total_cores > application.project_application_total_cores ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.total_cores - application.project_application_total_cores) }} - - {{ application.project_modification_request.total_cores }}
Total RAM{{ application?.project_application_total_ram }} GB - - - - {{ application.project_modification_request.total_ram === application.project_application_total_ram ? '' : (application.project_modification_request.total_ram > application.project_application_total_ram ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.total_ram - application.project_application_total_ram) }} - - {{ application.project_modification_request.total_ram }}
Total GPUs{{ application?.project_application_total_gpu }} - - {{ application.project_modification_request.total_gpu === application.project_application_total_gpu ? '' : (application.project_modification_request.total_gpu > application.project_application_total_gpu ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.total_gpu - application.project_application_total_gpu) }} - - {{ application.project_modification_request.total_gpu }}
Initial Credits{{ application?.project_application_initial_credits }} - - + {{ application.project_modification_request.extra_credits }} - - {{ application.project_modification_request.extra_credits + application.project_application_initial_credits }}
Used Credits{{ current_credits }}
Storage Limit{{ application?.project_application_volume_limit }} GB - - {{ application.project_modification_request.volume_limit === application.project_application_volume_limit ? '' : (application.project_modification_request.volume_limit > application.project_application_volume_limit ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.volume_limit - application.project_application_volume_limit) }} - - {{ application.project_modification_request.volume_limit }}
Volume Counter{{ application?.project_application_volume_counter }} volumes - - {{ application.project_modification_request.volume_counter === application.project_application_volume_counter ? '' : (application.project_modification_request.volume_counter > application.project_application_volume_counter ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.volume_counter - application.project_application_volume_counter) }} - - {{ application.project_modification_request.volume_counter }}
ObjectStorage{{ application?.project_application_object_storage }} GB - - {{ application.project_modification_request.object_storage === application.project_application_object_storage ? '' : (application.project_modification_request.object_storage > application.project_application_object_storage ? '+' : '-') }} - {{ Math.abs(application.project_modification_request.object_storage - application.project_application_object_storage) }} - - {{ application.project_modification_request.object_storage }}
ResourceCurrentChangesModification
VMs + {{ application?.project_application_vms_requested }} + + + {{ + application.project_modification_request.vms_requested === application.project_application_vms_requested + ? '' + : application.project_modification_request.vms_requested > application.project_application_vms_requested + ? '+' + : '-' + }} + {{ + Math.abs( + application.project_modification_request.vms_requested - application.project_application_vms_requested + ) + }} + + {{ application.project_modification_request.vms_requested }}
Flavor: {{ flavorDiff.name }}{{ flavorDiff.current }} + + {{ flavorDiff.diff === 0 ? '' : flavorDiff.diff > 0 ? '+' : '-' }} + {{ flavorDiff.diff }} + + {{ flavorDiff.new }}
Total Cores{{ application?.project_application_total_cores }} + + {{ + application.project_modification_request.total_cores === application.project_application_total_cores + ? '' + : application.project_modification_request.total_cores > application.project_application_total_cores + ? '+' + : '-' + }} + {{ + Math.abs( + application.project_modification_request.total_cores - application.project_application_total_cores + ) + }} + + {{ application.project_modification_request.total_cores }}
Total RAM{{ application?.project_application_total_ram }} GB + + {{ + application.project_modification_request.total_ram === application.project_application_total_ram + ? '' + : application.project_modification_request.total_ram > application.project_application_total_ram + ? '+' + : '-' + }} + {{ + Math.abs(application.project_modification_request.total_ram - application.project_application_total_ram) + }} + + {{ application.project_modification_request.total_ram }}
Total GPUs{{ application?.project_application_total_gpu }} + + {{ + application.project_modification_request.total_gpu === application.project_application_total_gpu + ? '' + : application.project_modification_request.total_gpu > application.project_application_total_gpu + ? '+' + : '-' + }} + {{ + Math.abs(application.project_modification_request.total_gpu - application.project_application_total_gpu) + }} + + {{ application.project_modification_request.total_gpu }}
Initial Credits{{ application?.project_application_initial_credits }} + + + {{ application.project_modification_request.extra_credits }} + + + {{ application.project_modification_request.extra_credits + application.project_application_initial_credits }} +
Used Credits{{ current_credits }}
Storage Limit{{ application?.project_application_volume_limit }} GB + + {{ + application.project_modification_request.volume_limit === application.project_application_volume_limit + ? '' + : application.project_modification_request.volume_limit > application.project_application_volume_limit + ? '+' + : '-' + }} + {{ + Math.abs( + application.project_modification_request.volume_limit - application.project_application_volume_limit + ) + }} + + {{ application.project_modification_request.volume_limit }}
Volume Counter{{ application?.project_application_volume_counter }} volumes + + {{ + application.project_modification_request.volume_counter === application.project_application_volume_counter + ? '' + : application.project_modification_request.volume_counter > + application.project_application_volume_counter + ? '+' + : '-' + }} + {{ + Math.abs( + application.project_modification_request.volume_counter - application.project_application_volume_counter + ) + }} + + {{ application.project_modification_request.volume_counter }}
ObjectStorage{{ application?.project_application_object_storage }} GB + + {{ + application.project_modification_request.object_storage === application.project_application_object_storage + ? '' + : application.project_modification_request.object_storage > + application.project_application_object_storage + ? '+' + : '-' + }} + {{ + Math.abs( + application.project_modification_request.object_storage - application.project_application_object_storage + ) + }} + + {{ application.project_modification_request.object_storage }}
diff --git a/src/app/applications/application-detail/resource-detail/resource-detail.component.ts b/src/app/applications/application-detail/resource-detail/resource-detail.component.ts index 5f9af57ec8..39b6078612 100644 --- a/src/app/applications/application-detail/resource-detail/resource-detail.component.ts +++ b/src/app/applications/application-detail/resource-detail/resource-detail.component.ts @@ -6,10 +6,10 @@ import { ApplicationBaseClassComponent } from '../../../shared/shared_modules/ba import { Flavor } from '../../../virtualmachines/virtualmachinemodels/flavor'; interface FlavorDiff { - name: string; - current: number; - diff: number; - new: number; + name: string + current: number + diff: number + new: number } /** @@ -20,60 +20,61 @@ interface FlavorDiff { templateUrl: './resource-detail.component.html', }) export class ResourceDetailComponent extends ApplicationBaseClassComponent implements OnInit { - @Input() application: Application; - @Input() is_vo_admin: boolean; - @Input() current_credits: number; - protected readonly Math = Math; - protected readonly green = green; - flavorDiffs: FlavorDiff[] = []; + @Input() application: Application; + @Input() is_vo_admin: boolean; + @Input() current_credits: number; + protected readonly Math = Math; + protected readonly green = green; + flavorDiffs: FlavorDiff[] = []; - ngOnInit() { - this.getFlavorChanges(); - this.getModificationRequestingUser(); - } - - getModificationRequestingUser() { - if (this.application.project_modification_request && !this.application.project_modification_request.user) { - this.applicationsService.getModificationUser(this.application.project_application_id).subscribe((user: User) => { + ngOnInit() { + this.getFlavorChanges(); + this.getModificationRequestingUser(); + } - this.application.project_modification_request.user = user; - - }); - } + getModificationRequestingUser() { + if (this.application.project_modification_request && !this.application.project_modification_request.user) { + this.applicationsService.getModificationUser(this.application.project_application_id).subscribe((user: User) => { + this.application.project_modification_request.user = user; + }); } + } - getFlavorChanges() { - this.flavorDiffs = []; + getFlavorChanges() { + this.flavorDiffs = []; - // Initialize flavorDiffs with current flavors - this.application.flavors.forEach((flavor: Flavor) => { - this.flavorDiffs.push({ - name: flavor.name, current: flavor.counter, diff: 0, new: 0, - }); + // Initialize flavorDiffs with current flavors + this.application.flavors.forEach((flavor: Flavor) => { + this.flavorDiffs.push({ + name: flavor.name, + current: flavor.counter, + diff: 0, + new: 0, }); + }); - // Iterate over modification request flavors - if (this.application.project_modification_request) { - this.application.project_modification_request.flavors.forEach((modificationFlavor: Flavor) => { - const existingFlavorDiffIndex = this.flavorDiffs.findIndex(flavorDiff => flavorDiff.name === modificationFlavor.name); - - if (existingFlavorDiffIndex !== -1) { - // Flavor diff with same name exists - const existingFlavorDiff = this.flavorDiffs[existingFlavorDiffIndex]; - existingFlavorDiff.new = modificationFlavor.counter; - existingFlavorDiff.diff = existingFlavorDiff.new - existingFlavorDiff.current; - } else { - // Flavor diff with same name does not exist, add new flavor diff - this.flavorDiffs.push({ - name: modificationFlavor.name, - current: 0, // Set current as 0 as it's not present in the application flavors - diff: modificationFlavor.counter, - new: modificationFlavor.counter, - }); - } - }); - } + // Iterate over modification request flavors + if (this.application.project_modification_request) { + this.application.project_modification_request.flavors.forEach((modificationFlavor: Flavor) => { + const existingFlavorDiffIndex = this.flavorDiffs.findIndex( + flavorDiff => flavorDiff.name === modificationFlavor.name, + ); + if (existingFlavorDiffIndex !== -1) { + // Flavor diff with same name exists + const existingFlavorDiff = this.flavorDiffs[existingFlavorDiffIndex]; + existingFlavorDiff.new = modificationFlavor.counter; + existingFlavorDiff.diff = existingFlavorDiff.new - existingFlavorDiff.current; + } else { + // Flavor diff with same name does not exist, add new flavor diff + this.flavorDiffs.push({ + name: modificationFlavor.name, + current: 0, // Set current as 0 as it's not present in the application flavors + diff: modificationFlavor.counter, + new: modificationFlavor.counter, + }); + } + }); } - + } } diff --git a/src/app/applications/application-facility-actions/application-facility-actions.component.html b/src/app/applications/application-facility-actions/application-facility-actions.component.html index 3a2c083d9c..734ef802b7 100644 --- a/src/app/applications/application-facility-actions/application-facility-actions.component.html +++ b/src/app/applications/application-facility-actions/application-facility-actions.component.html @@ -1,161 +1,120 @@ - -
- @switch (tabState) { - - - @case (ApplicationTabStates.SUBMITTED) { - - @if (application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) { - - } - @if (application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) { - - - } - - - } - @case (ApplicationTabStates.LIFETIME_EXTENSION) { - - - - - - - } - @case (ApplicationTabStates.CREDITS_EXTENSION) { - - } - @case (ApplicationTabStates.MODIFICATION_EXTENSION) { - - - - - } - @case (ApplicationTabStates.TERMINATION_REQUEST) { - - - - - - } - } - - - - - - - -
+
+ @switch (tabState) { + @case (ApplicationTabStates.SUBMITTED) { + @if (application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) { + + } + @if (application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) { + + } + } + @case (ApplicationTabStates.LIFETIME_EXTENSION) { + + + + } + @case (ApplicationTabStates.CREDITS_EXTENSION) {} + @case (ApplicationTabStates.MODIFICATION_EXTENSION) { + + + + } + @case (ApplicationTabStates.TERMINATION_REQUEST) { + + + + } + } + + +
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 981ddbce05..f0435db1b8 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 @@ -25,249 +25,258 @@ export class ApplicationFacilityActionsComponent extends AbstractBaseClass { protected readonly ConfirmationActions = ConfirmationActions; protected readonly ApplicationTabStates = ApplicationTabStates; - @Input() application: Application; - @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; - @Input() computeCenters: ComputecenterComponent[] = []; - @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); - @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); - isCollapsed: boolean = true; - bsModalRef: BsModalRef; - @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); - - constructor(private facilityService: FacilityService, private modalService: BsModalService, private applicationsService: ApplicationsService) { - super(); - } - - switchCollaps() { - this.switchCollapseEvent.emit(); - } - - triggerRemoveApplication() { - - this.removeApplicationTrigger.emit(this.application.project_application_id); - } - - triggerReloadNumbers() { - this.reloadNumbersTrigger.emit(); - } - - declineApplication(): void { - this.showNotificationModal('Decline Application', 'Waiting..', 'info'); - - 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( + @Input() application: Application; + @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; + @Input() computeCenters: ComputecenterComponent[] = []; + @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); + @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); + isCollapsed: boolean = true; + bsModalRef: BsModalRef; + @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); + + constructor( + private facilityService: FacilityService, + private modalService: BsModalService, + private applicationsService: ApplicationsService, + ) { + super(); + } + + switchCollaps() { + this.switchCollapseEvent.emit(); + } + + triggerRemoveApplication() { + this.removeApplicationTrigger.emit(this.application.project_application_id); + } + + triggerReloadNumbers() { + this.reloadNumbersTrigger.emit(); + } + + declineApplication(): void { + this.showNotificationModal('Decline Application', 'Waiting..', 'info'); + + this.facilityService + .declineFacilityApplication( + this.application.project_application_compute_center.FacilityId, + this.application.project_application_id, + ) + .subscribe( (): void => { - this.showNotificationModal('Success', 'Successfully approved extension!', 'success'); + this.showNotificationModal('Success', 'Successfully declined the application.', 'success'); this.triggerReloadNumbers(); this.triggerRemoveApplication(); + + // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); }, (): void => { - this.showNotificationModal('Failed', 'The approval of the extension request has failed.', 'danger'); + 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'); + }, + ); + } + + showNotificationModal( + notificationModalTitle: string, + notificationModalMessage: string, + notificationModalType: string, + ) { + const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; + if (this.bsModalRef) { + this.bsModalRef.hide(); } - /** - * Decline an extension request. - * - * @param application_id - */ - public declineExtension(): void { - this.applicationsService.declineAdditionalLifetime(this.application.project_application_id).subscribe( + 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 declined extension!', 'success'); + this.showNotificationModal('Success', 'Successfully approved the application.', 'success'); this.triggerReloadNumbers(); this.triggerRemoveApplication(); + + // this.getAllApplicationsHistory(this.selectedFacility['FacilityId']); }, (): void => { - this.showNotificationModal('Failed', 'The decline of the extension request has failed.', 'danger'); + this.showNotificationModal('Failed', 'Failed to approve the application.', 'danger'); }, ); - } - - 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'); - } - - 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'); - }, - ); - } - - showConfirmationModal(action: ConfirmationActions): void { - - const initialState = { - application: this.application, action, - }; - - this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); - this.subscribeToBsModalRef(); - } - - approveModification(): void { - this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( + } + + showConfirmationModal(action: ConfirmationActions): void { + const initialState = { + application: this.application, + action, + }; + + 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'); + }, + ); + } + + 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.showNotificationModal('Success', 'Successfully approved modification!', 'success'); this.triggerReloadNumbers(); this.triggerRemoveApplication(); + this.showNotificationModal('Success', 'The project was terminated.', 'success'); }, - (): void => { - this.showNotificationModal('Failed', 'The approval of the modification request has failed.', 'danger'); + (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'); + } }, ); - } - - declineModification(): void { - this.applicationsService.declineModificationRequest(this.application.project_application_id).subscribe( + } + + declineTermination(): void { + this.facilityService + .declineTerminationByFM( + this.application.project_application_perun_id, + this.application.project_application_compute_center.FacilityId, + ) + .subscribe( (): void => { - this.showNotificationModal('Success', 'Successfully declined modification!', 'success'); this.triggerReloadNumbers(); this.triggerRemoveApplication(); + this.showNotificationModal('Success', 'The termination of the project was declined.', 'success'); }, - (): void => { - this.showNotificationModal('Failed', 'The decline of the modification request has failed.', 'danger'); + (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'); + } }, ); - } - - 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'); - } - }, - ); - } - - 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'); - } - }, - ); - } - - 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; - } + } + + 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-formular/application-formular.component.ts b/src/app/applications/application-formular/application-formular.component.ts index a14fce71d6..5a101e65d5 100644 --- a/src/app/applications/application-formular/application-formular.component.ts +++ b/src/app/applications/application-formular/application-formular.component.ts @@ -1,7 +1,8 @@ import { - ChangeDetectorRef, Component, Input, OnInit, ViewChild, + ChangeDetectorRef, Component, Input, OnInit, ViewChild, inject, } from '@angular/core'; import { NgForm } from '@angular/forms'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Flavor } from '../../virtualmachines/virtualmachinemodels/flavor'; import { FlavorService } from '../../api-connector/flavor.service'; import { FlavorType } from '../../virtualmachines/virtualmachinemodels/flavorType'; @@ -51,6 +52,8 @@ export class ApplicationFormularComponent extends ApplicationBaseClassComponent @Input() is_validation: boolean = false; @Input() hash: string; + private readonly tracker = inject(MatomoTracker); + userinfo: Userinfo; valid_pi_affiliations; unknownPiAffiliationsConfirmation: boolean = false; @@ -113,6 +116,11 @@ export class ApplicationFormularComponent extends ApplicationBaseClassComponent } ngOnInit(): void { + if (!this.is_validation) { + const typeStr: string = this.openstack_project ? ' Openstack' : 'SimpleVM'; + this.tracker.trackPageView(`New Application Formular: ${typeStr}`); + } + this.getUserinfo(); this.getListOfFlavors(); this.getListOfTypes(); diff --git a/src/app/applications/application-list/application-list.component.html b/src/app/applications/application-list/application-list.component.html index 5e4d0de289..1959563cb1 100644 --- a/src/app/applications/application-list/application-list.component.html +++ b/src/app/applications/application-list/application-list.component.html @@ -1,32 +1,32 @@ -
-
- - - - - - - - - - - - - - - - @for (application of applications; track application.project_application_id) { - - - } - -
Project NameShort NameDate submittedUserInstituteCompute CenterActions
-
+
+
+ + + + + + + + + + + + + + + @for (application of applications; track application.project_application_id) { + + } + +
Project NameShort NameDate submittedUserInstituteCompute CenterActions
+
diff --git a/src/app/applications/application-list/application-list.component.ts b/src/app/applications/application-list/application-list.component.ts index ae582b1ce3..2d87e22604 100644 --- a/src/app/applications/application-list/application-list.component.ts +++ b/src/app/applications/application-list/application-list.component.ts @@ -15,34 +15,35 @@ import { is_vo } from '../../shared/globalvar'; styleUrl: './application-list.component.scss', }) export class ApplicationListComponent implements OnInit { - @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); + @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); - @Input() applications: Application[] = []; - @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; - @Input() computeCenters: ComputecenterComponent[] = []; - @Input() facilityView:boolean = false; - @Input() voView:boolean = false; + @Input() applications: Application[] = []; + @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; + @Input() computeCenters: ComputecenterComponent[] = []; + @Input() facilityView: boolean = false; + @Input() voView: boolean = false; - is_vo_admin: boolean = false; + is_vo_admin: boolean = false; - ngOnInit() { - this.is_vo_admin = is_vo; + ngOnInit() { + this.is_vo_admin = is_vo; + } - } - - triggerReloadNumbers() { - console.log('trigger reload 2'); - this.reloadNumbersTrigger.emit(); - } + triggerReloadNumbers() { + console.log('trigger reload 2'); + this.reloadNumbersTrigger.emit(); + } - removeApplicationFromList(application_id: string | number) { - const idx: number = this.applications.findIndex((application: Application) => application.project_application_id === application_id); + removeApplicationFromList(application_id: string | number) { + const idx: number = this.applications.findIndex( + (application: Application) => application.project_application_id === application_id, + ); - if (idx !== -1) { - console.log('remove index'); - this.applications.splice(idx, 1); - } + if (idx !== -1) { + console.log('remove index'); + this.applications.splice(idx, 1); } + } - protected readonly Application_States = Application_States; + protected readonly Application_States = Application_States; } diff --git a/src/app/applications/application-vo-actions/application-vo-actions.component.html b/src/app/applications/application-vo-actions/application-vo-actions.component.html index c400edc050..fc8510a4c8 100644 --- a/src/app/applications/application-vo-actions/application-vo-actions.component.html +++ b/src/app/applications/application-vo-actions/application-vo-actions.component.html @@ -1,341 +1,304 @@ @if (is_vo_admin) { - - - @if ((application | hasstatusinlist: Application_States.SUBMITTED) || - (application | hasstatusinlist: Application_States.CONFIRMATION_DECLINED) || - ((application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && - !application?.project_application_compute_center?.FacilityId)) { - - } @else if (application?.project_application_compute_center?.Name) { - {{ application?.project_application_compute_center?.Name }} - } - - -
- - - @if (application?.processing_vo_initials && is_vo_admin) { - - - } - @if (!application?.processing_vo_initials && is_vo_admin) { - - } - - - @switch (tabState) { - - @case (ApplicationTabStates.SUBMITTED) { - - @if ((application | hasstatusinlist: Application_States.SUBMITTED) && - !application?.project_application_openstack_project) { - - } - @if (application | hasstatusinlist: Application_States.SUBMITTED) { - - } - @if (application.project_application_pi_approved && - (application | hasstatusinlist: Application_States.SUBMITTED)) { - - } - @if ((application | hasstatusinlist: Application_States.CONFIRMATION_DECLINED) || - ((application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && - !application?.project_application_compute_center?.FacilityId)) { - - } - @if ((application | hasstatusinlist: Application_States.SUBMITTED) && - !(application | hasstatusinlist: Application_States.APPROVED)) { - - } - @if ((application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && - application?.project_application_compute_center?.FacilityId) { - - - } - @if ((application | hasstatusinlist: Application_States.SUBMITTED) && - application?.project_application_openstack_project) { - - } - - } - @case (ApplicationTabStates.LIFETIME_EXTENSION) { - @if ((application | hasstatusinlist: Application_States.LIFETIME_EXTENSION_REQUESTED) && - application?.project_lifetime_request) { - - - - - } - - } - @case (ApplicationTabStates.CREDITS_EXTENSION) { - - } - @case (ApplicationTabStates.MODIFICATION_EXTENSION) { - @if ((application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && - application?.project_application_openstack_project && - application?.project_modification_request) { - - - } - - @if ((application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && - !application?.project_application_openstack_project && - application?.project_modification_request) { - - - } - - @if ((application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && - application?.project_modification_request) { - - } - @if ((application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && - application?.project_modification_request) { - - } - - - } - @case (ApplicationTabStates.TERMINATION_REQUEST) { - - } - } - - - - - - - -
- -} \ No newline at end of file + + @if ( + (application | hasstatusinlist: Application_States.SUBMITTED) || + (application | hasstatusinlist: Application_States.CONFIRMATION_DECLINED) || + ((application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && + !application?.project_application_compute_center?.FacilityId) + ) { + + } @else if (application?.project_application_compute_center?.Name) { + {{ application?.project_application_compute_center?.Name }} + } + + +
+ @if (application?.processing_vo_initials && is_vo_admin) { + + } + @if (!application?.processing_vo_initials && is_vo_admin) { + + } + + @switch (tabState) { + @case (ApplicationTabStates.SUBMITTED) { + + @if ( + (application | hasstatusinlist: Application_States.SUBMITTED) && + !application?.project_application_openstack_project + ) { + + } + @if (application | hasstatusinlist: Application_States.SUBMITTED) { + + } + @if ( + application.project_application_pi_approved && (application | hasstatusinlist: Application_States.SUBMITTED) + ) { + + } + @if ( + (application | hasstatusinlist: Application_States.CONFIRMATION_DECLINED) || + ((application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && + !application?.project_application_compute_center?.FacilityId) + ) { + + } + @if ( + (application | hasstatusinlist: Application_States.SUBMITTED) && + !(application | hasstatusinlist: Application_States.APPROVED) + ) { + + } + @if ( + (application | hasstatusinlist: Application_States.WAIT_FOR_CONFIRMATION) && + application?.project_application_compute_center?.FacilityId + ) { + + } + @if ( + (application | hasstatusinlist: Application_States.SUBMITTED) && + application?.project_application_openstack_project + ) { + + } + } + @case (ApplicationTabStates.LIFETIME_EXTENSION) { + @if ( + (application | hasstatusinlist: Application_States.LIFETIME_EXTENSION_REQUESTED) && + application?.project_lifetime_request + ) { + + + + } + } + @case (ApplicationTabStates.CREDITS_EXTENSION) {} + @case (ApplicationTabStates.MODIFICATION_EXTENSION) { + @if ( + (application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && + application?.project_application_openstack_project && + application?.project_modification_request + ) { + + } + + @if ( + (application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && + !application?.project_application_openstack_project && + application?.project_modification_request + ) { + + } + + @if ( + (application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && + application?.project_modification_request + ) { + + } + @if ( + (application | hasstatusinlist: Application_States.MODIFICATION_REQUESTED) && + application?.project_modification_request + ) { + + } + } + @case (ApplicationTabStates.TERMINATION_REQUEST) {} + } + + +
+ +} 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 7b1d8cf6a3..68191fff20 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,15 +14,9 @@ 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'; @@ -35,161 +29,162 @@ 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) => { + @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'); - + 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'); - - } - }); - } - - showAdjustApplicationModal() { - this.adjustApplicationModal.showAdjustApplicationModal(this.application).subscribe((changed: boolean) => { - if (changed) { - this.getApplication(); - - this.showNotificationModal('Success', 'The resources of the application were adjusted successfully!', 'success'); - - } else { - 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(); - } + } - 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']; - }); - } - } + showAdjustApplicationModal() { + this.adjustApplicationModal.showAdjustApplicationModal(this.application).subscribe((changed: boolean) => { + if (changed) { + this.getApplication(); - showConfirmationModal(action: ConfirmationActions): void { - let initialState = {}; - if (action === ConfirmationActions.APPROVE_APPLICATION) { - const application_center = !this.selectedComputeCenter.FacilityId; - initialState = { application: this.application, action, application_center }; + this.showNotificationModal('Success', 'The resources of the application were adjusted successfully!', 'success'); } else { - initialState = { - application: this.application, action, - }; + this.showNotificationModal('Failed', 'The adjustment of the resources has failed!', 'danger'); } - this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' }); - this.subscribeToBsModalRef(); + }); + } + + 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']; + }); } - - unsetProcessingVoManager(application: Application): void { - if (this.is_vo_admin) { - this.voService.unsetProcessingVoManager(application.project_application_id).subscribe(() => { - application.processing_vo_initials = null; - }); - } + } + + 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, + }; } - - 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(); + 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; + }); } - - 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'); - }, - ); + } + + 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, + }; } - getApplication(): void { - this.applicationsService.getApplication(this.application.project_application_id.toString()).subscribe( - (aj: Application): void => { - this.application = aj; - }, - (error: any): void => { - console.log(error); - }, - ); - } + this.bsModalRef = this.modalService.show(ClientLimitsComponent, { initialState }); + this.subscribeToBsModalRef(); + } - assignGroupToFacility(): void { - if (this.selectedComputeCenter) { - this.groupService.assignGroupToResource(this.application.project_application_perun_id, this.selectedComputeCenter.FacilityId).subscribe( + 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(); @@ -200,40 +195,42 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements this.showNotificationModal('Failed', 'Project could not be created!', 'danger'); }, ); - } else { - this.showNotificationModal('Failed', 'You need to select an compute center!', 'danger'); - } + } else { + this.showNotificationModal('Failed', 'You need to select an compute center!', 'danger'); } - - resetApplicationPI(): void { - this.applicationsService.resetPIValidation(this.application).subscribe((app: Application) => { - this.getApplication(); - }); - } - - switchCollaps() { - this.switchCollapseEvent.emit(); + } + + 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(); } - 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'); + } - createSimpleVmProjectGroup(): void { - this.showNotificationModal('Info', 'Creating Project...', 'info'); + 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( + 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( @@ -249,7 +246,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements }, (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!'; @@ -257,160 +254,155 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements 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'); + } + + 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(); - }, - (): 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'); - }, - ); - } + // 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(); - declineApplication(): void { - // const idx: number = this.all_applications.indexOf(app); - this.applicationsService.declineApplication(this.application.project_application_id).subscribe( + 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 => { - const message: string = 'The Application was declined.'; - - this.showNotificationModal('Success', message, 'success'); + this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); this.triggerRemoveApplication(); this.triggerReloadNumbers(); - }, (): void => { - this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); + this.updateNotificationModal('Failed', 'Application could not be removed!', true, '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(); - - } + ), + ); + } + + 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', '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(); } - }, - (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( + } 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'); @@ -421,7 +413,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements } }, (error: any): void => { - 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!'; @@ -429,67 +421,67 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements 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(); - } + } + + /** + * 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); + 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(); } - }), - ); - } - - isCollapsed: boolean = true; - protected readonly Application_States = Application_States; - protected readonly ConfirmationActions = ConfirmationActions; - protected readonly ApplicationTabStates = ApplicationTabStates; + } + 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.model/user.model.ts b/src/app/applications/application.model/user.model.ts index 42fde49920..6bd3c43bd9 100644 --- a/src/app/applications/application.model/user.model.ts +++ b/src/app/applications/application.model/user.model.ts @@ -3,8 +3,9 @@ */ export class User { username: string; - user_affiliations: string [] = []; + user_affiliations: string[] = []; elixir_id: string; email: string; pi_project_count_total: number = 0; + pi_project_count_active: number = 0; } diff --git a/src/app/applications/applications.component.ts b/src/app/applications/applications.component.ts index 4d2b052312..6659018b55 100644 --- a/src/app/applications/applications.component.ts +++ b/src/app/applications/applications.component.ts @@ -1,9 +1,10 @@ /* eslint-disable no-lonely-if */ import { - ChangeDetectorRef, Component, OnDestroy, OnInit, + ChangeDetectorRef, Component, OnDestroy, OnInit, inject, } from '@angular/core'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { Subscription } from 'rxjs'; +import { MatomoTracker } from 'ngx-matomo-client'; import { ApplicationsService } from '../api-connector/applications.service'; import { ApiSettings } from '../api-connector/api-settings.service'; import { Application } from './application.model/application.model'; @@ -44,6 +45,7 @@ import { ApplicationTabStates } from '../shared/enums/application-tab-states'; ], }) export class ApplicationsComponent extends ApplicationBaseClassComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); title: string = 'Application Overview'; tab_state: number = ApplicationTabStates.SUBMITTED; ApplicationTabStates: typeof ApplicationTabStates = ApplicationTabStates; @@ -101,6 +103,7 @@ export class ApplicationsComponent extends ApplicationBaseClassComponent impleme } ngOnInit(): void { + this.tracker.trackPageView('Application Overview'); this.is_vo_admin = is_vo; if (this.is_vo_admin) { this.getApplicationNumbers(); diff --git a/src/app/applications/applications.module.ts b/src/app/applications/applications.module.ts index 15f3403727..6b67681a4a 100644 --- a/src/app/applications/applications.module.ts +++ b/src/app/applications/applications.module.ts @@ -23,20 +23,14 @@ import { InformationDetailComponent } from './application-detail/information-det import { AdjustmentDetailComponent } from './application-detail/adjustment-detail/adjustment-detail.component'; import { ResourceDetailComponent } from './application-detail/resource-detail/resource-detail.component'; import { ModificationDetailComponent } from './application-detail/modification-detail/modification-detail.component'; -import { - CreditsExtensionDetailComponent, -} from './application-detail/credits-extension-detail/credits-extension-detail.component'; -import { - LifetimeExtensionDetailComponent, -} from './application-detail/lifetime-extension-detail/lifetime-extension-detail.component'; +import { CreditsExtensionDetailComponent } from './application-detail/credits-extension-detail/credits-extension-detail.component'; +import { LifetimeExtensionDetailComponent } from './application-detail/lifetime-extension-detail/lifetime-extension-detail.component'; import { NewsModule } from '../news/news.module'; import { SharedModuleModule } from '../shared/shared_modules/shared-module.module'; import { ApplicationListComponent } from './application-list/application-list.component'; import { ApplicationCardComponent } from './application-card/application-card.component'; import { ApplicationVoActionsComponent } from './application-vo-actions/application-vo-actions.component'; -import { - ApplicationFacilityActionsComponent, -} from './application-facility-actions/application-facility-actions.component'; +import { ApplicationFacilityActionsComponent } from './application-facility-actions/application-facility-actions.component'; /** * Applications Module. @@ -77,9 +71,7 @@ import { ApplicationCardComponent, ApplicationVoActionsComponent, ApplicationFacilityActionsComponent, - ], exports: [ApplicationDetailComponent, ApplicationListComponent], }) -export class ApplicationsModule { -} +export class ApplicationsModule {} diff --git a/src/app/applications/type-overview.component.ts b/src/app/applications/type-overview.component.ts index d15b76acfc..b802721b07 100644 --- a/src/app/applications/type-overview.component.ts +++ b/src/app/applications/type-overview.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; +import { MatomoTracker } from 'ngx-matomo-client'; import { WIKI_WORKSHOPS, OPENSTACK_LINK, PROJECT_TYPES_LINK, SIMPLE_VM_LINK, } from '../../links/links'; @@ -12,6 +13,7 @@ import { styleUrls: ['./type-overview.component.css'], }) export class TypeOverviewComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); title: string = 'Project Type Overview'; @@ -32,6 +34,7 @@ export class TypeOverviewComponent implements OnInit { OPENSTACK_LINK: string = OPENSTACK_LINK; ngOnInit(): any { + this.tracker.trackPageView('New Project - Project Type Overview'); this.simpleVM_logo_link = `${this.static_img_folder}simpleVM_Logo.svg`; this.simpleVM_curve_logo = `${this.static_img_folder}/simplevm-info-page/flatlearning.svg`; this.simpleVM_ease_logo = `${this.static_img_folder}/simplevm-info-page/easytouse.svg`; @@ -42,5 +45,4 @@ export class TypeOverviewComponent implements OnInit { this.openstack_conf_logo = `${this.static_img_folder}/openstack-info-page/configuration.svg`; this.openstack_scale_logo = `${this.static_img_folder}/openstack-info-page/scale.svg`; } - } diff --git a/src/app/credits-calculator/credits-calculator.component.ts b/src/app/credits-calculator/credits-calculator.component.ts index 7e39df59ed..e3f994f75d 100644 --- a/src/app/credits-calculator/credits-calculator.component.ts +++ b/src/app/credits-calculator/credits-calculator.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { MatomoTracker } from 'ngx-matomo-client'; import { FacilityService } from '../api-connector/facility.service'; import { FlavorService } from '../api-connector/flavor.service'; import { Flavor } from '../virtualmachines/virtualmachinemodels/flavor'; @@ -19,6 +20,7 @@ import { ResourceWeight } from './resource-weights.model/resource-weights.model' providers: [FacilityService, FlavorService, CreditsService, GroupService], }) export class CreditsCalculatorComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); title: string = 'Credits Calculator'; got_all_cc: boolean = false; got_all_flavor: boolean = false; @@ -62,6 +64,7 @@ export class CreditsCalculatorComponent implements OnInit { } ngOnInit(): void { + this.tracker.trackPageView('Credits Calculator'); this.flavor_service.getListOfTypesAvailable().subscribe((result: FlavorType[]) => { this.flavor_types = result; }); diff --git a/src/app/facility_manager/facility.application.component.ts b/src/app/facility_manager/facility.application.component.ts index 0139a75af1..146615ab5c 100644 --- a/src/app/facility_manager/facility.application.component.ts +++ b/src/app/facility_manager/facility.application.component.ts @@ -1,4 +1,7 @@ -import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, Component, OnInit, inject, +} from '@angular/core'; +import { MatomoTracker } from 'ngx-matomo-client'; import { FacilityService } from '../api-connector/facility.service'; import { UserService } from '../api-connector/user.service'; import { GroupService } from '../api-connector/group.service'; @@ -7,7 +10,6 @@ import { Application } from '../applications/application.model/application.model import { Application_States } from '../shared/shared_modules/baseClass/abstract-base-class'; import { ApplicationsService } from '../api-connector/applications.service'; import { ApplicationBaseClassComponent } from '../shared/shared_modules/baseClass/application-base-class.component'; - // eslint-disable-next-line no-shadow enum TabStates { 'SUBMITTED' = 0, @@ -27,6 +29,7 @@ enum TabStates { providers: [FacilityService, UserService, GroupService, ApplicationsService, ApiSettings], }) export class FacilityApplicationComponent extends ApplicationBaseClassComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); numberOfExtensionRequests: number = 0; numberOfModificationRequests: number = 0; numberOfCreditRequests: number = 0; @@ -225,6 +228,7 @@ export class FacilityApplicationComponent extends ApplicationBaseClassComponent } ngOnInit(): void { + this.tracker.trackPageView('Facility Application Overview'); this.facilityService.getManagerFacilities().subscribe((result: any): void => { this.managerFacilities = result; this.selectedFacility = this.managerFacilities[0]; diff --git a/src/app/facility_manager/facilityprojectsoverview.component.ts b/src/app/facility_manager/facilityprojectsoverview.component.ts index ddb38f765f..4bbf018218 100644 --- a/src/app/facility_manager/facilityprojectsoverview.component.ts +++ b/src/app/facility_manager/facilityprojectsoverview.component.ts @@ -1,8 +1,9 @@ import { - Component, Input, OnInit, QueryList, ViewChildren, + Component, Input, OnInit, QueryList, ViewChildren, inject, } from '@angular/core'; import { Observable, Subject, take } from 'rxjs'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { ProjectMember } from '../projectmanagement/project_member.model'; import { environment } from '../../environments/environment'; import { ApiSettings } from '../api-connector/api-settings.service'; @@ -32,6 +33,7 @@ import { CsvMailTemplateModel } from '../shared/classes/csvMailTemplate.model'; providers: [FacilityService, UserService, GroupService, ApiSettings, NewsService, ProjectSortService], }) export class FacilityProjectsOverviewComponent extends AbstractBaseClass implements OnInit { + private readonly tracker = inject(MatomoTracker); @Input() voRegistrationLink: string = environment.voRegistrationLink; title: string = 'Projects Overview'; @@ -147,6 +149,7 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme } ngOnInit(): void { + this.tracker.trackPageView('Facility Project Overview'); this.facilityService.getManagerFacilities().subscribe((result: any): void => { this.managerFacilities = result; this.selectedFacility = this.managerFacilities[0]; diff --git a/src/app/facility_manager/imagetags.component.ts b/src/app/facility_manager/imagetags.component.ts index ad75951c0b..7243f0a27b 100644 --- a/src/app/facility_manager/imagetags.component.ts +++ b/src/app/facility_manager/imagetags.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import { forkJoin } from 'rxjs'; +import { MatomoTracker } from 'ngx-matomo-client'; import { ImageService } from '../api-connector/image.service'; import { BlockedImageTag, BlockedImageTagResenv, ImageLogo, ImageMode, ImageTag, @@ -16,6 +17,7 @@ import { BiocondaService } from '../api-connector/bioconda.service'; providers: [ImageService, FacilityService, BiocondaService], }) export class ImageTagComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); title: string = 'Image Tags'; @@ -50,7 +52,11 @@ export class ImageTagComponent implements OnInit { */ public selectedFacility: [string, number]; - constructor(private imageService: ImageService, private facilityService: FacilityService, private biocondaService: BiocondaService) { + constructor( + private imageService: ImageService, + private facilityService: FacilityService, + private biocondaService: BiocondaService, + ) { // constructor for ImageTags } @@ -91,18 +97,18 @@ export class ImageTagComponent implements OnInit { this.imageService.getBlockedImageTags(this.selectedFacility['FacilityId']), this.imageService.getImageModes(this.selectedFacility['FacilityId']), this.imageService.getBlockedImageTagsResenv(this.selectedFacility['FacilityId']), - ) - .subscribe((res: any): void => { - this.imageTags = res[0]; - this.imageLogos = res[1]; - this.blockedImageTags = res[2]; - this.imageModes = res[3]; - this.blockedImageTagsResenv = res[4]; - this.isLoaded = true; - }); + ).subscribe((res: any): void => { + this.imageTags = res[0]; + this.imageLogos = res[1]; + this.blockedImageTags = res[2]; + this.imageModes = res[3]; + this.blockedImageTagsResenv = res[4]; + this.isLoaded = true; + }); } ngOnInit(): void { + this.tracker.trackPageView('Image Tags'); this.facilityService.getManagerFacilities().subscribe((result: any): void => { this.managerFacilities = result; this.selectedFacility = this.managerFacilities[0]; @@ -113,15 +119,14 @@ export class ImageTagComponent implements OnInit { this.imageService.getBlockedImageTags(this.selectedFacility['FacilityId']), this.imageService.getImageModes(this.selectedFacility['FacilityId']), this.imageService.getBlockedImageTagsResenv(this.selectedFacility['FacilityId']), - ) - .subscribe((res: any): void => { - this.imageTags = res[0]; - this.imageLogos = res[1]; - this.blockedImageTags = res[2]; - this.imageModes = res[3]; - this.blockedImageTagsResenv = res[4]; - this.isLoaded = true; - }); + ).subscribe((res: any): void => { + this.imageTags = res[0]; + this.imageLogos = res[1]; + this.blockedImageTags = res[2]; + this.imageModes = res[3]; + this.blockedImageTagsResenv = res[4]; + this.isLoaded = true; + }); }); } @@ -150,10 +155,12 @@ export class ImageTagComponent implements OnInit { addTag(tag: string, input: HTMLInputElement): void { if (input.validity.valid) { - this.imageService.addImageTags(tag.trim(), this.checkedModes, this.selectedFacility['FacilityId']).subscribe((newTag: ImageTag): void => { - this.checkedModes = []; - this.imageTags.push(newTag); - }); + this.imageService + .addImageTags(tag.trim(), this.checkedModes, this.selectedFacility['FacilityId']) + .subscribe((newTag: ImageTag): void => { + this.checkedModes = []; + this.imageTags.push(newTag); + }); this.alertRed = false; } else { this.alertRed = true; @@ -166,16 +173,15 @@ export class ImageTagComponent implements OnInit { description: this.newModeDescription, copy_field: this.newModeCopy, }; - this.imageService.addImageMode(newMode, this.selectedFacility['FacilityId']).subscribe((createdMode: ImageMode): void => { - - this.newModeName = ''; - this.newModeDescription = ''; - this.newModeCopy = ''; - this.imageModes.push(createdMode); - this.getTagModeSuggestions(); - - }); - + this.imageService + .addImageMode(newMode, this.selectedFacility['FacilityId']) + .subscribe((createdMode: ImageMode): void => { + this.newModeName = ''; + this.newModeDescription = ''; + this.newModeCopy = ''; + this.imageModes.push(createdMode); + this.getTagModeSuggestions(); + }); } deleteTag(tag: ImageTag): void { @@ -208,9 +214,11 @@ export class ImageTagComponent implements OnInit { addBlockedTag(tag: string, input: HTMLInputElement): void { if (input.validity.valid) { - this.imageService.addBlockedImageTag(tag.trim(), this.selectedFacility['FacilityId']).subscribe((newTag: BlockedImageTag): void => { - this.blockedImageTags.push(newTag); - }); + this.imageService + .addBlockedImageTag(tag.trim(), this.selectedFacility['FacilityId']) + .subscribe((newTag: BlockedImageTag): void => { + this.blockedImageTags.push(newTag); + }); this.alertRed_blocked = false; } else { this.alertRed_blocked = true; @@ -250,5 +258,4 @@ export class ImageTagComponent implements OnInit { }); }); } - } diff --git a/src/app/facility_manager/newsmanagement/news-manager.component.ts b/src/app/facility_manager/newsmanagement/news-manager.component.ts index 1c33fe4808..143829bd53 100644 --- a/src/app/facility_manager/newsmanagement/news-manager.component.ts +++ b/src/app/facility_manager/newsmanagement/news-manager.component.ts @@ -1,15 +1,15 @@ import { - Component, OnDestroy, OnInit, ViewChild, + Component, OnDestroy, OnInit, ViewChild, inject, } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { BehaviorSubject, Subscription } from 'rxjs'; import { ModalDirective } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { NewsService } from '../../api-connector/news.service'; import { FacilityService } from '../../api-connector/facility.service'; import { environment } from '../../../environments/environment'; import { FacilityNews } from './facility-news'; import { WIKI_MOTD } from '../../../links/links'; - /** * News-Manager Class to manage news in wordPress. */ @@ -19,6 +19,7 @@ import { WIKI_MOTD } from '../../../links/links'; providers: [NewsService, FacilityService], }) export class NewsManagerComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); title: string = 'News Management'; public production: boolean = environment.production; WIKI_MOTD: string = WIKI_MOTD; @@ -72,6 +73,7 @@ export class NewsManagerComponent implements OnInit, OnDestroy { * Method on site initialization. */ ngOnInit(): void { + this.tracker.trackPageView('News Management'); this.subscription.add( this.facilityService.getComputeCenters().subscribe((computeCenters: any[]): void => { this.computeCenters = computeCenters; diff --git a/src/app/facility_manager/resources/resources.component.ts b/src/app/facility_manager/resources/resources.component.ts index 8748458dac..241f591b6c 100644 --- a/src/app/facility_manager/resources/resources.component.ts +++ b/src/app/facility_manager/resources/resources.component.ts @@ -1,9 +1,10 @@ import { - Component, ElementRef, OnInit, ViewChild, + Component, ElementRef, OnInit, ViewChild, inject, } from '@angular/core'; import { download, mkConfig, generateCsv, CsvOutput, } from 'export-to-csv'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Resources } from '../../vo_manager/resources/resources'; import { FacilityService } from '../../api-connector/facility.service'; import { ObjectStorageFactor } from './object-storage-factor'; @@ -22,6 +23,7 @@ import { GPUSpecification } from './gpu-specification'; providers: [FacilityService], }) export class ResourcesComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); title: string = 'Resource Overview'; tableId: string = 'contentToConvert'; @@ -154,6 +156,7 @@ export class ResourcesComponent implements OnInit { } ngOnInit(): void { + this.tracker.trackPageView('Facility Resources'); this.facilityService.getManagerFacilities().subscribe((result: [string, number][]): void => { this.managerFacilities = result; this.selectedFacility = this.managerFacilities[0]; diff --git a/src/app/help/help.component.ts b/src/app/help/help.component.ts index cce73bd7b1..118ca0535e 100644 --- a/src/app/help/help.component.ts +++ b/src/app/help/help.component.ts @@ -1,8 +1,8 @@ -import { Component } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; +import { MatomoTracker } from 'ngx-matomo-client'; import { WIKI, CLOUD_PORTAL_SUPPORT_MAIL, STATUS_LINK, SUPPORT_LINK, ZAMMAD_HELPDESK_LINK, } from '../../links/links'; - /** * Help component. */ @@ -11,11 +11,16 @@ import { templateUrl: './help.component.html', providers: [], }) -export class HelpComponent { +export class HelpComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); WIKI: string = WIKI; CLOUD_PORTAL_SUPPORT_MAIL: string = CLOUD_PORTAL_SUPPORT_MAIL; STATUS_LINK: string = STATUS_LINK; SUPPORT_LINK: string = SUPPORT_LINK; ZAMMAD_HELPDESK_LINK: string = ZAMMAD_HELPDESK_LINK; title: string = 'Help'; + + ngOnInit(): void { + this.tracker.trackPageView('Help'); + } } diff --git a/src/app/news/news.component.ts b/src/app/news/news.component.ts index be0990a2f4..f8cb143f10 100644 --- a/src/app/news/news.component.ts +++ b/src/app/news/news.component.ts @@ -37,7 +37,7 @@ export class NewsComponent implements OnInit, OnDestroy { pullDrag: false, dots: true, navSpeed: 700, - navText: ['', ''], + navText: ["", ""], responsive: { 0: { items: 1, @@ -55,7 +55,10 @@ export class NewsComponent implements OnInit, OnDestroy { nav: true, }; - constructor(private news_service: NewsService, private groupService: GroupService) { + constructor( + private news_service: NewsService, + private groupService: GroupService, + ) { // eslint-disable-next-line no-empty-function } diff --git a/src/app/projectmanagement/modals/adjust-application/adjust-application.component.html b/src/app/projectmanagement/modals/adjust-application/adjust-application.component.html index 92f8b8ac77..4106c18141 100644 --- a/src/app/projectmanagement/modals/adjust-application/adjust-application.component.html +++ b/src/app/projectmanagement/modals/adjust-application/adjust-application.component.html @@ -1,482 +1,465 @@ - + +
+ } + + + - diff --git a/src/app/projectmanagement/modals/adjust-application/adjust-application.component.ts b/src/app/projectmanagement/modals/adjust-application/adjust-application.component.ts index f3662ee6c1..bd6c98ff84 100644 --- a/src/app/projectmanagement/modals/adjust-application/adjust-application.component.ts +++ b/src/app/projectmanagement/modals/adjust-application/adjust-application.component.ts @@ -24,11 +24,11 @@ export class AdjustApplicationComponent implements OnInit { modalId: number | string | undefined; totalNumberOfCores: number = 0; newFlavors: { - [id: string]: { - counter: number - flavor: Flavor - } - } = {}; + [id: string]: { + counter: number + flavor: Flavor + } + } = {}; totalRAM: number = 0; atLeastOneVM: boolean = false; @@ -40,153 +40,148 @@ export class AdjustApplicationComponent implements OnInit { adjustedApplication: Application; FlavorTypeShortcuts: typeof FlavorTypeShortcuts = FlavorTypeShortcuts; - @Output() eventSuccess: EventEmitter = new EventEmitter(); - - constructor( - private modalService: BsModalService, - private applicationsService: ApplicationsService, - private creditsService: CreditsService, - private flavorService: FlavorService, - ) { - } - - ngOnInit() { - this.loaded = false; - this.loadedFlavorTypes = false; - this.loadedFlavors = false; - this.adjustedApplication = new Application(this.application); - this.getAvailableFlavorTypes(); - this.getAvailableFlavors(); - } - - getAvailableFlavors() { - this.flavorService.getListOfFlavorsAvailable(undefined, undefined, true).subscribe((flavList: Flavor[]): void => { - this.flavorList = flavList; - this.loadedFlavors = true; - this.loaded = this.loadedFlavorTypes && this.loadedFlavors; - - }); + @Output() eventSuccess: EventEmitter = new EventEmitter(); + + constructor( + private modalService: BsModalService, + private applicationsService: ApplicationsService, + private creditsService: CreditsService, + private flavorService: FlavorService, + ) {} + + ngOnInit() { + this.loaded = false; + this.loadedFlavorTypes = false; + this.loadedFlavors = false; + this.adjustedApplication = new Application(this.application); + this.getAvailableFlavorTypes(); + this.getAvailableFlavors(); + } + + getAvailableFlavors() { + this.flavorService.getListOfFlavorsAvailable(undefined, undefined, true).subscribe((flavList: Flavor[]): void => { + this.flavorList = flavList; + this.loadedFlavors = true; + this.loaded = this.loadedFlavorTypes && this.loadedFlavors; + }); + } + + getAvailableFlavorTypes() { + this.flavorService.getListOfTypesAvailable().subscribe((availableTypes: FlavorType[]): void => { + this.typeList = availableTypes; + this.loadedFlavorTypes = true; + this.loaded = this.loadedFlavorTypes && this.loadedFlavors; + }); + } + + calculateRamCores(): void { + this.totalNumberOfCores = 0; + this.totalRAM = 0; + this.totalGPU = 0; + // tslint:disable-next-line:forin + for (const extensionFlavorsKey in this.newFlavors) { + const fl: any = this.newFlavors[extensionFlavorsKey]; + this.totalRAM += fl.flavor.ram_gib * fl.counter; + this.totalNumberOfCores += fl.flavor.vcpus * fl.counter; + this.totalGPU += fl.flavor.gpu * fl.counter; } - - getAvailableFlavorTypes() { - this.flavorService.getListOfTypesAvailable().subscribe((availableTypes: FlavorType[]): void => { - this.typeList = availableTypes; - this.loadedFlavorTypes = true; - this.loaded = this.loadedFlavorTypes && this.loadedFlavors; - }); - } - - calculateRamCores(): void { - this.totalNumberOfCores = 0; - this.totalRAM = 0; - this.totalGPU = 0; - // tslint:disable-next-line:forin - for (const extensionFlavorsKey in this.newFlavors) { - const fl: any = this.newFlavors[extensionFlavorsKey]; - this.totalRAM += fl.flavor.ram_gib * fl.counter; - this.totalNumberOfCores += fl.flavor.vcpus * fl.counter; - this.totalGPU += fl.flavor.gpu * fl.counter; + } + + checkIfTypeGotSimpleVMFlavorOrIsCustom(type: FlavorType): boolean { + for (const flav of this.flavorList) { + if ( + (flav.type.shortcut === type.shortcut && flav.simple_vm) + || type.shortcut === FlavorTypeShortcuts.CUSTOM_FLAVOR + ) { + return true; } } - checkIfTypeGotSimpleVMFlavorOrIsCustom(type: FlavorType): boolean { - for (const flav of this.flavorList) { - if ( - (flav.type.shortcut === type.shortcut && flav.simple_vm) - || type.shortcut === FlavorTypeShortcuts.CUSTOM_FLAVOR - ) { - return true; - } - } - - return false; - } + return false; + } - togglePersonalDataType(checked: boolean, data_type: string) { - switch (data_type) { - case 'person_related': { - if (!checked) { - this.adjustedApplication.project_application_no_personal_data = false; - this.adjustedApplication.project_application_nonsensitive_data = false; - this.adjustedApplication.project_application_sensitive_data = false; - } - break; - } - case 'no_personal_data': { - if (checked) { - this.adjustedApplication.project_application_nonsensitive_data = false; - this.adjustedApplication.project_application_sensitive_data = false; - } - break; + togglePersonalDataType(checked: boolean, data_type: string) { + switch (data_type) { + case 'person_related': { + if (!checked) { + this.adjustedApplication.project_application_no_personal_data = false; + this.adjustedApplication.project_application_nonsensitive_data = false; + this.adjustedApplication.project_application_sensitive_data = false; } - case 'nonsensitive': { - if (checked) { - this.adjustedApplication.project_application_no_personal_data = false; - } - break; + break; + } + case 'no_personal_data': { + if (checked) { + this.adjustedApplication.project_application_nonsensitive_data = false; + this.adjustedApplication.project_application_sensitive_data = false; } - case 'sensitive': { - if (checked) { - this.adjustedApplication.project_application_no_personal_data = false; - } - break; + break; + } + case 'nonsensitive': { + if (checked) { + this.adjustedApplication.project_application_no_personal_data = false; } - default: - break; + break; } - } - - hide(): void { - this.modalService.hide(this.modalId); - } - - checkIfMinimumSelected(): void { - let numberOfVMs: number = 0; - for (const fl of this.adjustedApplication.flavors) { - numberOfVMs += this.adjustedApplication.getFlavorCounter(fl); + case 'sensitive': { + if (checked) { + this.adjustedApplication.project_application_no_personal_data = false; + } + break; } - this.atLeastOneVM = numberOfVMs > 0 || this.adjustedApplication.project_application_openstack_project; - } - - onChangeFlavor(flavor: Flavor, value: number): void { - this.adjustedApplication.setFlavorInFlavors(flavor, value); - this.checkIfMinimumSelected(); - this.creditsService - .getCreditsForApplication(this.adjustedApplication.flavors, this.adjustedApplication.project_application_lifetime) - .toPromise() - .then((credits: number): void => { - this.adjustedApplication.project_application_initial_credits = credits; - }) - .catch((err: any): void => console.log(err)); - } - - showAdjustApplicationModal(application: Application): EventEmitter { - const initialState = { - application, - }; - const bsModalRef: BsModalRef = this.modalService.show(AdjustApplicationComponent, { initialState }); - bsModalRef.setClass('modal-lg'); - this.modalId = bsModalRef.id; - - return bsModalRef.content.eventSuccess; + default: + break; } + } - adjustApplication(): void { - this.loaded = false; - this.applicationsService.adjustApplication(this.adjustedApplication).subscribe( - (): void => { - this.hide(); + hide(): void { + this.modalService.hide(this.modalId); + } - this.eventSuccess.emit(true); - - }, - (): void => { - this.hide(); - - this.eventSuccess.emit(false); - - }, - ); + checkIfMinimumSelected(): void { + let numberOfVMs: number = 0; + for (const fl of this.adjustedApplication.flavors) { + numberOfVMs += this.adjustedApplication.getFlavorCounter(fl); } - + this.atLeastOneVM = numberOfVMs > 0 || this.adjustedApplication.project_application_openstack_project; + } + + onChangeFlavor(flavor: Flavor, value: number): void { + this.adjustedApplication.setFlavorInFlavors(flavor, value); + this.checkIfMinimumSelected(); + this.creditsService + .getCreditsForApplication(this.adjustedApplication.flavors, this.adjustedApplication.project_application_lifetime) + .toPromise() + .then((credits: number): void => { + this.adjustedApplication.project_application_initial_credits = credits; + }) + .catch((err: any): void => console.log(err)); + } + + showAdjustApplicationModal(application: Application): EventEmitter { + const initialState = { + application, + }; + const bsModalRef: BsModalRef = this.modalService.show(AdjustApplicationComponent, { initialState }); + bsModalRef.setClass('modal-lg'); + this.modalId = bsModalRef.id; + + return bsModalRef.content.eventSuccess; + } + + adjustApplication(): void { + this.loaded = false; + this.applicationsService.adjustApplication(this.adjustedApplication).subscribe( + (): void => { + this.hide(); + + this.eventSuccess.emit(true); + }, + (): void => { + this.hide(); + + this.eventSuccess.emit(false); + }, + ); + } } diff --git a/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.html b/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.html index c4469c8380..4e09857fd5 100644 --- a/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.html +++ b/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.html @@ -1,120 +1,109 @@ + diff --git a/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.ts b/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.ts index 5ceb390fab..2dcb3a6f35 100644 --- a/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.ts +++ b/src/app/projectmanagement/modals/adjust-lifetime/adjust-lifetime-request.component.ts @@ -20,49 +20,49 @@ export class AdjustLifetimeRequestComponent implements OnInit { application: Application; adjustedApplicationLifetimeExtension: ApplicationLifetimeExtension; - @Output() eventSuccess: EventEmitter = new EventEmitter(); + @Output() eventSuccess: EventEmitter = new EventEmitter(); - constructor( - private modalService: BsModalService, - private applicationsService: ApplicationsService, - ) { - } + constructor( + private modalService: BsModalService, + private applicationsService: ApplicationsService, + ) {} - ngOnInit() { - this.loaded = false; - this.adjustedApplicationLifetimeExtension = new ApplicationLifetimeExtension(this.application.project_lifetime_request); - this.loaded = true; - } + ngOnInit() { + this.loaded = false; + this.adjustedApplicationLifetimeExtension = new ApplicationLifetimeExtension( + this.application.project_lifetime_request, + ); + this.loaded = true; + } - hide(): void { + hide(): void { + this.modalService.hide(this.modalId); + } - this.modalService.hide(this.modalId); - } + showAdjustLifetimeExtensionModal(application: Application): EventEmitter { + const initialState = { + application, + }; + const bsModalRef: BsModalRef = this.modalService.show(AdjustLifetimeRequestComponent, { initialState }); + bsModalRef.setClass('modal-lg'); + this.modalId = bsModalRef.id; - showAdjustLifetimeExtensionModal(application: Application): EventEmitter { - const initialState = { - application, - }; - const bsModalRef: BsModalRef = this.modalService.show(AdjustLifetimeRequestComponent, { initialState }); - bsModalRef.setClass('modal-lg'); - this.modalId = bsModalRef.id; + return bsModalRef.content.eventSuccess; + } - return bsModalRef.content.eventSuccess; - } - - adjustLifetimeExtension(): void { - this.loaded = false; - this.applicationsService.adjustLifetimeExtension(this.adjustedApplicationLifetimeExtension).subscribe((): void => { + adjustLifetimeExtension(): void { + this.loaded = false; + this.applicationsService.adjustLifetimeExtension(this.adjustedApplicationLifetimeExtension).subscribe( + (): void => { this.hide(); this.eventSuccess.emit(true); - - }, (): void => { + }, + (): void => { this.hide(); this.eventSuccess.emit(false); - - }); - } - + }, + ); + } } diff --git a/src/app/projectmanagement/overview.component.ts b/src/app/projectmanagement/overview.component.ts index 07b7b70af5..4c487d37b5 100644 --- a/src/app/projectmanagement/overview.component.ts +++ b/src/app/projectmanagement/overview.component.ts @@ -7,6 +7,7 @@ import { OnInit, Renderer2, ViewChild, + inject, } from '@angular/core'; import * as moment from 'moment'; import { forkJoin, Observable, Subscription } from 'rxjs'; @@ -14,6 +15,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { DOCUMENT } from '@angular/common'; import { Chart } from 'chart.js'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { environment } from '../../environments/environment'; import { ProjectMemberApplication } from './project_member_application'; import { Userinfo } from '../userinfo/userinfo.model'; @@ -50,7 +52,6 @@ import { LifetimeRequestComponent } from './modals/lifetime-request/lifetime-req import { CreditsRequestComponent } from './modals/credits-request/credits-request.component'; import { ExtensionEntryComponent } from './modals/testimonial/extension-entry.component'; import { WITHDRAWAL_TYPES, WithdrawModalComponent } from './modals/withdraw/withdraw-modal.component'; - /** * Projectoverview component. */ @@ -68,6 +69,7 @@ import { WITHDRAWAL_TYPES, WithdrawModalComponent } from './modals/withdraw/with ], }) export class OverviewComponent extends ApplicationBaseClassComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); bsModalRef: BsModalRef; modificationRequestDisabled: boolean = false; lifetimeExtensionDisabled: boolean = false; @@ -195,6 +197,7 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements this.project_application = null; this.project_members = []; this.application_id = paramsId.id; + this.tracker.trackPageView(`Project Overview for pid: ${paramsId.id}`); this.is_vo_admin = is_vo; this.getApplication(); diff --git a/src/app/shared/enums/application-tab-states.ts b/src/app/shared/enums/application-tab-states.ts index bdbd1b7ca5..cfb74ccb22 100644 --- a/src/app/shared/enums/application-tab-states.ts +++ b/src/app/shared/enums/application-tab-states.ts @@ -1,7 +1,7 @@ export enum ApplicationTabStates { - 'SUBMITTED' = 0, - 'CREDITS_EXTENSION' = 1, - 'LIFETIME_EXTENSION' = 2, - 'MODIFICATION_EXTENSION' = 3, - 'TERMINATION_REQUEST' = 4, + 'SUBMITTED' = 0, + 'CREDITS_EXTENSION' = 1, + 'LIFETIME_EXTENSION' = 2, + 'MODIFICATION_EXTENSION' = 3, + 'TERMINATION_REQUEST' = 4, } diff --git a/src/app/shared/modal/confirmation_actions.ts b/src/app/shared/modal/confirmation_actions.ts index aa14ac25ba..c9f0bd2c37 100644 --- a/src/app/shared/modal/confirmation_actions.ts +++ b/src/app/shared/modal/confirmation_actions.ts @@ -1,16 +1,16 @@ export enum ConfirmationActions { - DECLINE_MODIFICATION, - DECLINE_EXTENSION, - DECLINE_CREDITS, - DECLINE_APPLICATION, - APPROVE_MODIFICATION, - APPROVE_EXTENSION, - APPROVE_CREDITS, - APPROVE_APPLICATION, - DISABLE_APPLICATION, - ENABLE_APPLICATION, - DELETE_APPLICATION, - RESET_PI, - APPROVE_TERMINATION, - DECLINE_TERMINATION + DECLINE_MODIFICATION, + DECLINE_EXTENSION, + DECLINE_CREDITS, + DECLINE_APPLICATION, + APPROVE_MODIFICATION, + APPROVE_EXTENSION, + APPROVE_CREDITS, + APPROVE_APPLICATION, + DISABLE_APPLICATION, + ENABLE_APPLICATION, + DELETE_APPLICATION, + RESET_PI, + APPROVE_TERMINATION, + DECLINE_TERMINATION, } diff --git a/src/app/shared/modal/confirmation_types.ts b/src/app/shared/modal/confirmation_types.ts index 88a97022d6..6ee951aa6b 100644 --- a/src/app/shared/modal/confirmation_types.ts +++ b/src/app/shared/modal/confirmation_types.ts @@ -1,8 +1,8 @@ export enum ConfirmationTypes { - ENABLE, - DISABLE, - APPROVE, - DECLINE, - DELETE, - RESET_PI + ENABLE, + DISABLE, + APPROVE, + DECLINE, + DELETE, + RESET_PI, } diff --git a/src/app/shared/shared_modules/baseClass/application-base-class.component.ts b/src/app/shared/shared_modules/baseClass/application-base-class.component.ts index 48822f38cd..cf49e0cb30 100644 --- a/src/app/shared/shared_modules/baseClass/application-base-class.component.ts +++ b/src/app/shared/shared_modules/baseClass/application-base-class.component.ts @@ -21,54 +21,54 @@ import { User } from '../../../applications/application.model/user.model'; }) export class ApplicationBaseClassComponent extends AbstractBaseClass { /** - * If all Applications are loaded, important for the loader. - * - * @type {boolean} - */ + * If all Applications are loaded, important for the loader. + * + * @type {boolean} + */ isLoaded: boolean = false; FlavorTypeShortcuts: typeof FlavorTypeShortcuts = FlavorTypeShortcuts; /** - * Selected Application. - */ + * Selected Application. + */ selectedApplication: Application; /** - * All available compute centers. - * - * @type {Array} - */ + * All available compute centers. + * + * @type {Array} + */ computeCenters: ComputecenterComponent[] = []; /** - * List of flavor types. - */ + * List of flavor types. + */ typeList: FlavorType[]; /** - * Total number of cores. - * - * @type {number} - */ + * Total number of cores. + * + * @type {number} + */ totalNumberOfCores: number = 0; /** - * Total number of ram. - * - * @type {number} - */ + * Total number of ram. + * + * @type {number} + */ totalRAM: number = 0; /** - * Total number of GPUs - */ + * Total number of GPUs + */ totalGPU: number = 0; newFlavors: { - [id: string]: { - counter: number - flavor: Flavor - } - } = {}; + [id: string]: { + counter: number + flavor: Flavor + } + } = {}; GPU_SHORTCUT = 'GPU'; HMF_SHORTCUT = 'HMF'; @@ -76,57 +76,57 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { extension_request: boolean = false; /** - * If shortname is valid. - * - * @type {boolean} - */ + * If shortname is valid. + * + * @type {boolean} + */ public wronginput: boolean = false; /** - * - */ + * + */ constantStrings: Object; /** - * List of flavors. - */ + * List of flavors. + */ flavorList: Flavor[] = []; extraResourceCommentRequired: boolean = false; /** - * If all userApplications are loaded, important for the loader. - * - * @type {boolean} - */ + * If all userApplications are loaded, important for the loader. + * + * @type {boolean} + */ isLoaded_userApplication: boolean = false; public project_application_pi_approved: boolean = false; /** - * Name of the project. - */ + * Name of the project. + */ public projectName: string; public project_application_report_allowed: boolean = false; /** - * Applications of the user viewing the Application overview. - * - * @type {Array} - */ + * Applications of the user viewing the Application overview. + * + * @type {Array} + */ user_applications: Application[] = []; constructor( - protected userService: UserService, - protected applicationsService: ApplicationsService, - protected facilityService: FacilityService, - private cdRef: ChangeDetectorRef, + protected userService: UserService, + protected applicationsService: ApplicationsService, + protected facilityService: FacilityService, + private cdRef: ChangeDetectorRef, ) { super(); } /** - * Gets all available compute centers and saves them in the computeCenters attribute. - */ + * Gets all available compute centers and saves them in the computeCenters attribute. + */ getComputeCenters(): void { this.facilityService.getComputeCenters().subscribe((result: [{ [key: string]: string }]): void => { for (const cc of result) { @@ -162,8 +162,8 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { if ( (entry?.flavor?.type?.shortcut.toUpperCase() === this.GPU_SHORTCUT - || entry?.flavor?.type?.shortcut.toUpperCase() === this.HMF_SHORTCUT) - && entry.counter > 0 + || entry?.flavor?.type?.shortcut.toUpperCase() === this.HMF_SHORTCUT) + && entry.counter > 0 ) { this.extraResourceCommentRequired = true; this.cdRef.detectChanges(); @@ -173,26 +173,20 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { } this.extraResourceCommentRequired = false; this.cdRef.detectChanges(); - } getApplicationPi(application: Application) { if (!application.project_application_pi) { this.applicationsService.getApplicationPI(application.project_application_id).subscribe((pi: User) => { - application.project_application_pi = pi; - }); } - } getApplicationUser(application: Application) { if (!application.project_application_user) { this.applicationsService.getApplicationUser(application.project_application_id).subscribe((user: User) => { - application.project_application_user = user; - }); } } @@ -200,9 +194,7 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { getExtensionUser(application: Application) { if (application.project_lifetime_request && !application.project_lifetime_request.user) { this.applicationsService.getLifetimeExtensionUser(application.project_application_id).subscribe((user: User) => { - application.project_lifetime_request.user = user; - }); } } @@ -210,9 +202,7 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { getModificationUser(application: Application) { if (application.project_modification_request && !application.project_modification_request.user) { this.applicationsService.getLifetimeExtensionUser(application.project_application_id).subscribe((user: User) => { - application.project_modification_request.user = user; - }); } } @@ -231,11 +221,11 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { } /** - * Get details of member like name and email by elixir. - * - * @param application - * @param collapse_id - */ + * Get details of member like name and email by elixir. + * + * @param application + * @param collapse_id + */ public getMemberDetailsByElixirIdIfCollapsed(application: Application, collapse_id: string): void { if (!this.getCollapseStatus(collapse_id)) { this.getMemberDetailsByElixirId(application); @@ -256,11 +246,11 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { } /** - * Get status name by status id. - * - * @param id - * @returns - */ + * Get status name by status id. + * + * @param id + * @returns + */ public getStatusById(id: number): string { const dummy: string = 'Unknown'; if (Application_States_Strings[Application_States[id]]) { @@ -271,20 +261,20 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { } /** - * Sets the selected application. - * - * @param application - */ + * Sets the selected application. + * + * @param application + */ setSelectedApplication(application: Application): void { this.selectedApplication = application; } /** - * Uses the param types to safe the available FlavorTypes to the array typeList. - * Also it fills the array collapseList with booleans of value 'false' so all flavor-categories are shown in the application form. - * - * @param types array of all available FlavorTypes - */ + * Uses the param types to safe the available FlavorTypes to the array typeList. + * Also it fills the array collapseList with booleans of value 'false' so all flavor-categories are shown in the application form. + * + * @param types array of all available FlavorTypes + */ setListOfTypes(types: FlavorType[]): void { let index: number = -1; for (let i: number = 0; i < types.length; i += 1) { @@ -303,17 +293,17 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { } /** - * Check if short name is valid. - * - * @param shortname - */ + * Check if short name is valid. + * + * @param shortname + */ public checkShortname(shortname: string): void { this.wronginput = !/^[a-zA-Z0-9\s]*$/.test(shortname); } /** - * Fills the array constantStrings with values dependent of keys which are used to indicate inputs from the application-form - */ + * Fills the array constantStrings with values dependent of keys which are used to indicate inputs from the application-form + */ generateConstants(): void { this.constantStrings = []; this.constantStrings['project_application_shortname'] = 'Shortname: '; @@ -342,21 +332,19 @@ export class ApplicationBaseClassComponent extends AbstractBaseClass { for (const key in this.flavorList) { if (key in this.flavorList) { - this.constantStrings[ - `project_application_${this.flavorList[key].name}` - ] = `Number of VMs of type ${this.flavorList[key].name}: `; + this.constantStrings[`project_application_${this.flavorList[key].name}`] = `Number of VMs of type ${this.flavorList[key].name}: `; } } } /** - * This function concatenates a given key combined with a given value to a string - * which is used on the confirmation-modal. - * - * @param key the key to access a string in the array constantStrings - * @param val the value that is concatenated with the string from the array and an optional addition (depending on the key) - * @returns the concatenated string for the confirmation-modal - */ + * This function concatenates a given key combined with a given value to a string + * which is used on the confirmation-modal. + * + * @param key the key to access a string in the array constantStrings + * @param val the value that is concatenated with the string from the array and an optional addition (depending on the key) + * @returns the concatenated string for the confirmation-modal + */ matchString(key: string, val: string): string { if (key in this.constantStrings) { switch (key) { diff --git a/src/app/userinfo/userinfo.component.ts b/src/app/userinfo/userinfo.component.ts index 6c1885157e..fd98ce2725 100644 --- a/src/app/userinfo/userinfo.component.ts +++ b/src/app/userinfo/userinfo.component.ts @@ -1,6 +1,9 @@ -import { Component, EventEmitter, OnInit } from '@angular/core'; +import { + Component, EventEmitter, OnInit, inject, +} from '@angular/core'; import { forkJoin } from 'rxjs'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Userinfo } from './userinfo.model'; import { ApiSettings } from '../api-connector/api-settings.service'; import { KeyService } from '../api-connector/key.service'; @@ -120,6 +123,8 @@ export class UserInfoComponent implements OnInit { confirmEventEmitter: EventEmitter = new EventEmitter(); + private readonly tracker = inject(MatomoTracker); + constructor( private groupService: GroupService, private userService: UserService, @@ -152,6 +157,7 @@ export class UserInfoComponent implements OnInit { } ngOnInit(): void { + this.tracker.trackPageView('User Info'); this.getUserinfo(); this.isFreemiumActive(); this.isUserSimpleVmMember(); diff --git a/src/app/validation-application/validation-application.component.ts b/src/app/validation-application/validation-application.component.ts index 954f8ad8af..1dcfb1f8af 100644 --- a/src/app/validation-application/validation-application.component.ts +++ b/src/app/validation-application/validation-application.component.ts @@ -1,12 +1,12 @@ import { - AfterViewChecked, ChangeDetectorRef, Component, OnInit, + AfterViewChecked, ChangeDetectorRef, Component, OnInit, inject, } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { MatomoTracker } from 'ngx-matomo-client'; import { ApplicationsService } from '../api-connector/applications.service'; import { Application } from '../applications/application.model/application.model'; import { ApplicationBaseClassComponent } from '../shared/shared_modules/baseClass/application-base-class.component'; import { FlavorService } from '../api-connector/flavor.service'; - /** * Application validation modal. */ @@ -17,6 +17,7 @@ import { FlavorService } from '../api-connector/flavor.service'; providers: [ApplicationsService, FlavorService], }) export class ValidationApplicationComponent extends ApplicationBaseClassComponent implements OnInit, AfterViewChecked { + private readonly tracker = inject(MatomoTracker); application: Application; isLoadedApplication: boolean = false; hash: string; @@ -50,6 +51,7 @@ export class ValidationApplicationComponent extends ApplicationBaseClassComponen ngOnInit(): void { this.activatedRoute.params.subscribe((paramsId: any): void => { this.hash = paramsId.hash; + this.tracker.trackPageView(`Application validation for hash: ${paramsId.hash}`); this.applicationsService.getApplicationValidationByHash(this.hash).subscribe( (app: Application): void => { diff --git a/src/app/virtualmachines/addvm.component.ts b/src/app/virtualmachines/addvm.component.ts index 021629e15f..9c927ed1bb 100644 --- a/src/app/virtualmachines/addvm.component.ts +++ b/src/app/virtualmachines/addvm.component.ts @@ -1,5 +1,5 @@ import { - Component, DoCheck, OnDestroy, OnInit, ViewChild, + Component, DoCheck, OnDestroy, OnInit, ViewChild, inject, } from '@angular/core'; import { forkJoin, Subscription } from 'rxjs'; import { Router } from '@angular/router'; @@ -12,6 +12,7 @@ import { WIKI_VOLUME_OVERVIEW, } from 'links/links'; import { KeyValue } from '@angular/common'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Image } from './virtualmachinemodels/image'; import { Flavor } from './virtualmachinemodels/flavor'; import { Userinfo } from '../userinfo/userinfo.model'; @@ -56,6 +57,7 @@ import { ImageService } from '../api-connector/image.service'; ], }) export class VirtualMachineComponent implements OnInit, DoCheck, OnDestroy { + private readonly tracker = inject(MatomoTracker); SIXTY_SIX_PERCENT: number = 66; SEVENTY_FIVE: number = 75; @@ -783,6 +785,7 @@ export class VirtualMachineComponent implements OnInit, DoCheck, OnDestroy { } ngOnInit(): void { + this.tracker.trackPageView('Create New Instance'); this.initializeData(); this.is_vo = is_vo; } diff --git a/src/app/virtualmachines/clusters/add-cluster/add-cluster.component.ts b/src/app/virtualmachines/clusters/add-cluster/add-cluster.component.ts index 47021af8fd..ceb296293d 100644 --- a/src/app/virtualmachines/clusters/add-cluster/add-cluster.component.ts +++ b/src/app/virtualmachines/clusters/add-cluster/add-cluster.component.ts @@ -1,9 +1,10 @@ import { - ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, + ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, inject, } from '@angular/core'; import { forkJoin, Subscription } from 'rxjs'; import { Router } from '@angular/router'; import { KeyValue } from '@angular/common'; +import { MatomoTracker } from 'ngx-matomo-client'; import { GroupService } from '../../../api-connector/group.service'; import { ImageService } from '../../../api-connector/image.service'; import { KeyService } from '../../../api-connector/key.service'; @@ -49,6 +50,7 @@ import { ProjectMember } from '../../../projectmanagement/project_member.model'; ], }) export class AddClusterComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); is_vo: boolean = false; CLOUD_PORTAL_SUPPORT_MAIL: string = CLOUD_PORTAL_SUPPORT_MAIL; STATUS_LINK: string = STATUS_LINK; @@ -524,6 +526,7 @@ export class AddClusterComponent implements OnInit, OnDestroy { } ngOnInit(): void { + this.tracker.trackPageView('Create Cluster'); this.initializeData(); this.generateRandomName(); this.subscription.add( diff --git a/src/app/virtualmachines/clusters/clusterdetail/clusterdetail.component.ts b/src/app/virtualmachines/clusters/clusterdetail/clusterdetail.component.ts index 8511a567b3..6ae64d9312 100644 --- a/src/app/virtualmachines/clusters/clusterdetail/clusterdetail.component.ts +++ b/src/app/virtualmachines/clusters/clusterdetail/clusterdetail.component.ts @@ -1,8 +1,11 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { + Component, OnDestroy, OnInit, inject, +} from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { ClipboardService } from 'ngx-clipboard'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Clusterinfo } from '../clusterinfo'; import { VirtualmachineService } from '../../../api-connector/virtualmachine.service'; import { VirtualMachineStates } from '../../virtualmachinemodels/virtualmachinestates'; @@ -27,6 +30,7 @@ import { TemplateNames } from '../../conda/template-names'; providers: [VirtualmachineService], }) export class ClusterdetailComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); WIKI_RSTUDIO_LINK: string = WIKI_RSTUDIO_LINK; WIKI_GUACAMOLE_LINK: string = WIKI_GUACAMOLE_LINK; WIKI_VOLUME_OVERVIEW: string = WIKI_VOLUME_OVERVIEW; @@ -62,6 +66,7 @@ export class ClusterdetailComponent implements OnInit, OnDestroy { ngOnInit(): void { this.activatedRoute.params.subscribe((paramsId: any): void => { this.cluster_id = paramsId.id; + this.tracker.trackPageView(`Cluster Detail Page: ${paramsId.id}`); this.setClusterById(); }); } diff --git a/src/app/virtualmachines/clusters/clusteroverview/clusterOverview.component.ts b/src/app/virtualmachines/clusters/clusteroverview/clusterOverview.component.ts index 049bc85b5d..a0c66edc07 100644 --- a/src/app/virtualmachines/clusters/clusteroverview/clusterOverview.component.ts +++ b/src/app/virtualmachines/clusters/clusteroverview/clusterOverview.component.ts @@ -1,9 +1,12 @@ /* eslint-disable no-mixed-spaces-and-tabs */ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { + Component, OnDestroy, OnInit, inject, +} from '@angular/core'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { UntypedFormBuilder } from '@angular/forms'; import { ClipboardService } from 'ngx-clipboard'; +import { MatomoTracker } from 'ngx-matomo-client'; import { VirtualmachineService } from '../../../api-connector/virtualmachine.service'; import { FullLayoutComponent } from '../../../layouts/full-layout.component'; import { UserService } from '../../../api-connector/user.service'; @@ -45,7 +48,7 @@ export const SCALING_SCRIPT_NAME: string = 'scaling.py'; }) export class ClusterOverviewComponent extends AbstractBaseClass implements OnInit, OnDestroy { title: string = 'Cluster Overview'; - + private readonly tracker = inject(MatomoTracker); private subscription: Subscription = new Subscription(); VirtualMachineStates: VirtualMachineStates = new VirtualMachineStates(); @@ -278,6 +281,7 @@ export class ClusterOverviewComponent extends AbstractBaseClass implements OnIni } ngOnInit(): void { + this.tracker.trackPageView('Cluster Overview'); this.getClusters(); this.is_vo_admin = is_vo; this.get_is_facility_manager(); diff --git a/src/app/virtualmachines/snapshots/snapshotOverview.component.ts b/src/app/virtualmachines/snapshots/snapshotOverview.component.ts index 462eb38560..2b0eb02927 100644 --- a/src/app/virtualmachines/snapshots/snapshotOverview.component.ts +++ b/src/app/virtualmachines/snapshots/snapshotOverview.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import { forkJoin, Subject } from 'rxjs'; import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; +import { MatomoTracker } from 'ngx-matomo-client'; import { ImageService } from '../../api-connector/image.service'; import { SnapshotModel } from './snapshot.model'; import { IResponseTemplate } from '../../api-connector/response-template'; @@ -26,6 +27,7 @@ enum Snapshot_Delete_Statuses { providers: [FacilityService, ImageService], }) export class SnapshotOverviewComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); snapshot_page: SnapshotPage = new SnapshotPage(); WIKI_SNAPSHOTS: string = WIKI_SNAPSHOTS; CLOUD_PORTAL_SUPPORT_MAIL: string = CLOUD_PORTAL_SUPPORT_MAIL; @@ -210,6 +212,7 @@ export class SnapshotOverviewComponent implements OnInit { } ngOnInit(): void { + this.tracker.trackPageView('Snapshot Overview'); this.getSnapshots(); this.filterChanged diff --git a/src/app/virtualmachines/vmOverview.component.ts b/src/app/virtualmachines/vmOverview.component.ts index 8907b10008..3043950fd9 100644 --- a/src/app/virtualmachines/vmOverview.component.ts +++ b/src/app/virtualmachines/vmOverview.component.ts @@ -1,9 +1,10 @@ import { - Component, OnDestroy, OnInit, QueryList, ViewChildren, + Component, OnDestroy, OnInit, QueryList, ViewChildren, inject, } from '@angular/core'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { ClipboardService } from 'ngx-clipboard'; +import { MatomoTracker } from 'ngx-matomo-client'; import { VirtualmachineService } from '../api-connector/virtualmachine.service'; import { VirtualMachine } from './virtualmachinemodels/virtualmachine'; import { VirtualMachinePage } from './virtualmachinemodels/virtualMachinePage'; @@ -28,6 +29,7 @@ import { ApplicationsService } from '../api-connector/applications.service'; providers: [FacilityService, ImageService, UserService, FullLayoutComponent, GroupService, ClientService], }) export class VmOverviewComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); /** * Title of page */ @@ -178,6 +180,7 @@ export class VmOverviewComponent implements OnInit, OnDestroy { } ngOnInit(): void { + this.tracker.trackPageView('Instance Overview'); this.set_cluster_allowed(); this.getVms(); this.is_vo_admin = is_vo; diff --git a/src/app/virtualmachines/vmdetail/vmdetail.component.ts b/src/app/virtualmachines/vmdetail/vmdetail.component.ts index 02e085dc0e..627d286a07 100644 --- a/src/app/virtualmachines/vmdetail/vmdetail.component.ts +++ b/src/app/virtualmachines/vmdetail/vmdetail.component.ts @@ -1,9 +1,12 @@ -import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; +import { + Component, OnInit, ChangeDetectorRef, inject, +} from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Subject, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { ClipboardService } from 'ngx-clipboard'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { FlavorService } from '../../api-connector/flavor.service'; import { ApplicationsService } from '../../api-connector/applications.service'; import { FacilityService } from '../../api-connector/facility.service'; @@ -63,6 +66,7 @@ import { NotificationModalComponent } from '../../shared/modal/notification-moda ], }) export class VmDetailComponent extends AbstractBaseClass implements OnInit { + private readonly tracker = inject(MatomoTracker); vm_id: string; conda_logs: Condalog; title: string = 'Instance Detail'; @@ -193,6 +197,7 @@ export class VmDetailComponent extends AbstractBaseClass implements OnInit { ngOnInit(): void { this.activatedRoute.params.subscribe((paramsId: any): void => { this.vm_id = paramsId.id; + this.tracker.trackPageView(`Instance Detail Page: ${paramsId.id}`); this.getVmCondaLogs(); this.getVmById(); this.snapshotSearchTerm diff --git a/src/app/virtualmachines/volumes/volumeOverview.component.ts b/src/app/virtualmachines/volumes/volumeOverview.component.ts index bf84b00514..ac89315bf1 100644 --- a/src/app/virtualmachines/volumes/volumeOverview.component.ts +++ b/src/app/virtualmachines/volumes/volumeOverview.component.ts @@ -1,11 +1,12 @@ import { - Component, OnDestroy, OnInit, ViewChild, + Component, OnDestroy, OnInit, ViewChild, inject, } from '@angular/core'; import { forkJoin, lastValueFrom, Subject, Subscription, } from 'rxjs'; import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; import { AbstractControl, UntypedFormControl, ValidatorFn } from '@angular/forms'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Volume } from './volume'; import { VirtualmachineService } from '../../api-connector/virtualmachine.service'; import { VirtualMachine } from '../virtualmachinemodels/virtualmachine'; @@ -33,6 +34,7 @@ import { IsMigratedProjectIdPipe } from '../../pipe-module/pipes/migratedList'; }) export class VolumeOverviewComponent extends AbstractBaseClass implements OnInit, OnDestroy { @ViewChild('errorModal') errorModal: any; + private readonly tracker = inject(MatomoTracker); volume_page: VolumePage = new VolumePage(); @@ -283,6 +285,7 @@ export class VolumeOverviewComponent extends AbstractBaseClass implements OnInit } ngOnInit(): void { + this.tracker.trackPageView('Volume Overview'); this.getVolumes(); this.getUserApprovedProjects(); this.facilityService.getManagerFacilities().subscribe((result: any): void => { diff --git a/src/app/virtualmachines/workshop/add-workshop/add-workshop.component.ts b/src/app/virtualmachines/workshop/add-workshop/add-workshop.component.ts index eb28ec0e37..fa80bf2895 100644 --- a/src/app/virtualmachines/workshop/add-workshop/add-workshop.component.ts +++ b/src/app/virtualmachines/workshop/add-workshop/add-workshop.component.ts @@ -1,10 +1,11 @@ import { - Component, DoCheck, OnDestroy, OnInit, ViewChild, + Component, DoCheck, OnDestroy, OnInit, ViewChild, inject, } from '@angular/core'; import { Subscription } from 'rxjs'; import { KeyValue } from '@angular/common'; import transliterate from '@sindresorhus/transliterate'; import { Router } from '@angular/router'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Workshop } from '../workshop.model'; import { Userinfo } from '../../../userinfo/userinfo.model'; import { GroupService } from '../../../api-connector/group.service'; @@ -40,6 +41,7 @@ import { BiocondaService } from '../../../api-connector/bioconda.service'; ], }) export class AddWorkshopComponent implements OnInit, OnDestroy, DoCheck { + private readonly tracker = inject(MatomoTracker); title: string = 'New workshop VMs'; WIKI_WORKSHOPS: string = WIKI_WORKSHOPS; @@ -132,6 +134,7 @@ export class AddWorkshopComponent implements OnInit, OnDestroy, DoCheck { } ngOnInit(): void { + this.tracker.trackPageView('New Workshop'); this.get_applications(); this.get_user_data(); } diff --git a/src/app/virtualmachines/workshop/workshop-overview/workshop-overview.component.ts b/src/app/virtualmachines/workshop/workshop-overview/workshop-overview.component.ts index c2ecebd4ec..6f9db57913 100644 --- a/src/app/virtualmachines/workshop/workshop-overview/workshop-overview.component.ts +++ b/src/app/virtualmachines/workshop/workshop-overview/workshop-overview.component.ts @@ -1,7 +1,8 @@ import { - Component, OnInit, OnDestroy, ViewChild, + Component, OnInit, OnDestroy, ViewChild, inject, } from '@angular/core'; import { Subscription } from 'rxjs'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Workshop } from '../workshop.model'; import { GroupService } from '../../../api-connector/group.service'; import { UrlData } from '../workshop-urlinfo.model'; @@ -23,6 +24,7 @@ interface MemberVm { providers: [GroupService, WorkshopService], }) export class WorkshopOverviewComponent implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); title: string = 'Workshop management'; @ViewChild('confirmInterferingSlotModal') confirmInterfereModal: any; @@ -71,6 +73,7 @@ export class WorkshopOverviewComponent implements OnInit, OnDestroy { } ngOnInit(): void { + this.tracker.trackPageView('Workshop Overview'); this.newWorkShopTimeFrame = new WorkshopTimeFrame({ id: null, end_time: new Date(), diff --git a/src/app/vo_manager/VoOverviewComponent.ts b/src/app/vo_manager/VoOverviewComponent.ts index d7ee2544a3..9a207966b7 100644 --- a/src/app/vo_manager/VoOverviewComponent.ts +++ b/src/app/vo_manager/VoOverviewComponent.ts @@ -1,10 +1,11 @@ import { - Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren, + Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren, inject, } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { Observable, Subscription, take } from 'rxjs'; import { BsModalRef, BsModalService, ModalDirective } from 'ngx-bootstrap/modal'; import * as FileSaver from 'file-saver'; +import { MatomoTracker } from 'ngx-matomo-client'; import { VoService } from '../api-connector/vo.service'; import { ProjectMember } from '../projectmanagement/project_member.model'; import { GroupService } from '../api-connector/group.service'; @@ -35,6 +36,7 @@ import { CsvMailTemplateModel } from '../shared/classes/csvMailTemplate.model'; providers: [VoService, GroupService, FacilityService, ProjectSortService], }) export class VoOverviewComponent extends AbstractBaseClass implements OnInit, OnDestroy { + private readonly tracker = inject(MatomoTracker); title: string = 'VO Overview'; public emailSubject: string; public emailReply: string = ''; @@ -107,6 +109,7 @@ export class VoOverviewComponent extends AbstractBaseClass implements OnInit, On } ngOnInit(): void { + this.tracker.trackPageView('Vo Overview'); this.getVoProjects(); this.getComputeCenters(); this.voService.getNewsletterSubscriptionCounter().subscribe((result: IResponseTemplate): void => { diff --git a/src/app/vo_manager/clients/clientOverview.component.ts b/src/app/vo_manager/clients/clientOverview.component.ts index aa38bc1152..78fa1f819a 100644 --- a/src/app/vo_manager/clients/clientOverview.component.ts +++ b/src/app/vo_manager/clients/clientOverview.component.ts @@ -1,6 +1,9 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { + Component, OnDestroy, OnInit, inject, +} from '@angular/core'; import { Subscription } from 'rxjs'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { MatomoTracker } from 'ngx-matomo-client'; import { Client } from './client.model'; import { ClientService } from '../../api-connector/client.service'; import { ApiSettings } from '../../api-connector/api-settings.service'; @@ -11,18 +14,15 @@ import { FacilityService } from '../../api-connector/facility.service'; import { IResponseTemplate } from '../../api-connector/response-template'; import { is_vo } from '../../shared/globalvar'; import { ClientLimitsComponent } from './modals/client-limits..component'; - /** * Client component. */ @Component({ - selector: 'app-client-overview', - templateUrl: 'clientOverview.html', - providers: [FacilityService, UserService, GroupService, ClientService, ApiSettings], + selector: 'app-client-overview', + templateUrl: 'clientOverview.html', + providers: [FacilityService, UserService, GroupService, ClientService, ApiSettings], }) - export class ClientOverviewComponent implements OnInit, OnDestroy { - title: string = 'Client Overview'; /** * All clients. @@ -64,12 +64,13 @@ export class ClientOverviewComponent implements OnInit, OnDestroy { isLoaded: boolean = false; subscription: Subscription = new Subscription(); + private readonly tracker = inject(MatomoTracker); constructor( -private facilityService: FacilityService, -private userService: UserService, - private clientservice: ClientService, -private modalService: BsModalService, + private facilityService: FacilityService, + private userService: UserService, + private clientservice: ClientService, + private modalService: BsModalService, ) { this.facilityService = facilityService; this.userService = userService; @@ -145,7 +146,6 @@ private modalService: BsModalService, * @param location */ postClient(host: string, port: string, location: string): void { - if (host && port && location) { this.subscription.add( this.clientservice.postClient(host, port, location).subscribe((newClient: Client): void => { @@ -167,16 +167,15 @@ private modalService: BsModalService, switchActiveClient(id: string): void { this.subscription.add( - this.clientservice.switchActive(id).subscribe( - (client: Client) => { - this.clients[this.clients.indexOf(this.selectedClient)] = client; - this.selectedClient = null; - }, - ), + this.clientservice.switchActive(id).subscribe((client: Client) => { + this.clients[this.clients.indexOf(this.selectedClient)] = client; + this.selectedClient = null; + }), ); } ngOnInit(): void { + this.tracker.trackPageView('VO Clients Overview'); this.is_vo_admin = is_vo; this.getClientsChecked(); this.getComputeCenters(); @@ -185,5 +184,4 @@ private modalService: BsModalService, ngOnDestroy() { this.subscription.unsubscribe(); } - } diff --git a/src/app/vo_manager/maintenance/maintenance.component.ts b/src/app/vo_manager/maintenance/maintenance.component.ts index db4837c1fd..d2c09bb26f 100644 --- a/src/app/vo_manager/maintenance/maintenance.component.ts +++ b/src/app/vo_manager/maintenance/maintenance.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { BsModalService } from 'ngx-bootstrap/modal'; import 'svg2pdf.js'; +import { MatomoTracker } from 'ngx-matomo-client'; import { WorkshopService } from '../../api-connector/workshop.service'; import { WorkshopTimeFrame } from '../../virtualmachines/workshop/workshopTimeFrame.model'; import { VoService } from '../../api-connector/vo.service'; @@ -19,6 +20,7 @@ import { NotificationModalComponent } from '../../shared/modal/notification-moda providers: [WorkshopService, VoService], }) export class MaintenanceComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); is_vo_admin: boolean = false; title: string = 'Maintenance'; @@ -44,6 +46,7 @@ export class MaintenanceComponent implements OnInit { ) {} ngOnInit(): void { + this.tracker.trackPageView('Maintenance'); this.newMaintenanceTimeFrame = new MaintenanceTimeFrame({ name: '', start_time: new Date(), diff --git a/src/app/vo_manager/number-charts/number-charts.component.ts b/src/app/vo_manager/number-charts/number-charts.component.ts index e1695f481e..d6cbcd89c4 100644 --- a/src/app/vo_manager/number-charts/number-charts.component.ts +++ b/src/app/vo_manager/number-charts/number-charts.component.ts @@ -1,10 +1,10 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import html2canvas from 'html2canvas'; import * as saveSVG from 'save-svg-as-png'; import bb, { areaSpline, bar, Chart } from 'billboard.js'; import { jsPDF } from 'jspdf'; import * as d3 from 'd3'; - +import { MatomoTracker } from 'ngx-matomo-client'; import { NumbersService } from '../../api-connector/numbers.service'; import 'svg2pdf.js'; @@ -18,6 +18,7 @@ import 'svg2pdf.js'; providers: [NumbersService], }) export class NumberChartsComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); is_vo_admin: boolean = true; title: string = 'Cloud Numbers'; @@ -62,6 +63,7 @@ export class NumberChartsComponent implements OnInit { private endDatesResources: any[] = ['x']; ngOnInit(): void { + this.tracker.trackPageView('Cloud Numbers'); this.getData(); } diff --git a/src/app/vo_manager/resources/resources.component.ts b/src/app/vo_manager/resources/resources.component.ts index 22bed1ac41..4092e7a2bf 100644 --- a/src/app/vo_manager/resources/resources.component.ts +++ b/src/app/vo_manager/resources/resources.component.ts @@ -1,10 +1,11 @@ import { - Component, ElementRef, OnInit, ViewChild, + Component, ElementRef, OnInit, ViewChild, inject, } from '@angular/core'; import { CsvOutput, download, generateCsv, mkConfig, } from 'export-to-csv'; +import { MatomoTracker } from 'ngx-matomo-client'; import { VoService } from '../../api-connector/vo.service'; import { Resources } from './resources'; @@ -18,6 +19,7 @@ import { Resources } from './resources'; providers: [VoService], }) export class ResourcesComponent implements OnInit { + private readonly tracker = inject(MatomoTracker); title: string = 'VO Overview: Resources'; @ViewChild('resourcesTable') pdfTable: ElementRef; @@ -58,5 +60,7 @@ export class ResourcesComponent implements OnInit { download(csvConfig)(csv); } - ngOnInit(): void {} + ngOnInit(): void { + this.tracker.trackPageView('VO Overview Resources'); + } } diff --git a/src/assets/js/matomo.js b/src/assets/js/matomo.js deleted file mode 100644 index 3dc1887943..0000000000 --- a/src/assets/js/matomo.js +++ /dev/null @@ -1,9 +0,0 @@ -var idSite = 2; -var matomoTrackingApiUrl = "https.//cloud.denbi.de/matomo/" - -var _paq = window._paq = window._paq || []; -_paq.push(['setTrackerUrl', matomoTrackingApiUrl]); -_paq.push(['setSiteId', idSite]); -_paq.push(['trackPageView']); -_paq.push(['enableLinkTracking']); - diff --git a/src/environments/environment.custom.ts b/src/environments/environment.custom.ts index ca17165b06..13631f6f4b 100644 --- a/src/environments/environment.custom.ts +++ b/src/environments/environment.custom.ts @@ -1,6 +1,8 @@ const API_HOST: string = window['env']['API_HOST'] || 'cloud.denbi.de'; const VO_NAME: string = window['env']['VO_NAME'] || 'denbi'; const NEW_SIMPLE_VM: string = window['env']['NEW_SIMPLE_VM'] || 'https://simplevm.denbi.de'; +const MATOMO_SITE_ID = window['env']['MATOMO_SITE_ID'] || 22; +const MATOMO_TRACKING_URL = window['env']['MATOMO_TRACKING_URL'] || 'https://piwik.cebitec.uni-bielefeld.de/'; export const environment: any = { WIKI_PRE: `https://${API_HOST}/wiki/`, @@ -18,5 +20,6 @@ export const environment: any = { voRegistrationLink: `https://signup.aai.lifescience-ri.eu/fed/registrar/?vo=elixir&targetnew=https://signup.aai.lifescience-ri.eu/fed/registrar/?vo=${VO_NAME}`, login: `https://${API_HOST}/portal/api/v0/loggedUser/`, webapp: `https://${API_HOST}/portal/webapp/`, - matomoServer: '//cloud.denbi.de/matomo/', + MATOMO_SITE_ID, + MATOMO_TRACKING_URL, }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 0d3e16ca7b..db5230cd45 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -5,6 +5,8 @@ const VO_NAME: string = window['env']['VO_NAME'] || 'denbi-dev'; const NEW_SIMPLE_VM: string = window['env']['NEW_SIMPLE_VM'] || 'https://simplevm.denbi.de'; +const MATOMO_SITE_ID = window['env']['MATOMO_SITE_ID'] || 0; +const MATOMO_TRACKING_URL = window['env']['MATOMO_TRACKING_URL'] || ''; export const environment: any = { WIKI_PRE: 'https://portal-dev.denbi.de/wiki/', @@ -24,5 +26,6 @@ export const environment: any = { 'https://signup.aai.lifescience-ri.eu/fed/registrar/?vo=elixir&targetnew=https://signup.aai.lifescience-ri.eu/fed/registrar/?vo=denbi-dev', login: 'http://localhost:8000/api/v0/loggedUser/', webapp: 'http://localhost:8001/', - matomoServer: '', + MATOMO_SITE_ID, + MATOMO_TRACKING_URL, }; diff --git a/src/static/webapp/assets/environment/env.template.js b/src/static/webapp/assets/environment/env.template.js index 1f914d1783..fc68324ad5 100644 --- a/src/static/webapp/assets/environment/env.template.js +++ b/src/static/webapp/assets/environment/env.template.js @@ -1,10 +1,11 @@ -(function(window) { - window.env = window.env || {}; +;(function (window) { + window.env = window.env || {} - // Environment variables - window["env"]["API_HOST"] = "${API_HOST}"; - window["env"]["VO"] = "${VO}"; - window["env"]["PRODUCTION"] = "${PRODUCTION}"; - window['env']['VO_NAME'] = "${VO_NAME}"; - -})(this); + // Environment variables + window['env']['API_HOST'] = '${API_HOST}' + window['env']['VO'] = '${VO}' + window['env']['PRODUCTION'] = '${PRODUCTION}' + window['env']['VO_NAME'] = '${VO_NAME}' + window['env']['MATOMO_SITE_ID'] = '${MATOMO_SITE_ID}' + window['env']['MATOMO_TRACKING_URL'] = '${MATOMO_TRACKING_URL}' +})(this)