diff --git a/package-lock.json b/package-lock.json index 468482af1f..2f55688e60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@denbi/cloud-portal-webapp", - "version": "4.847.0", + "version": "4.848.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@denbi/cloud-portal-webapp", - "version": "4.847.0", + "version": "4.848.0", "dependencies": { "@angular-eslint/eslint-plugin": "^17.3.0", "@angular/animations": "17.3.10", @@ -88,7 +88,7 @@ "eslint-config-airbnb-base": "15.0.0", "eslint-plugin-import": "^2.29.0", "eslint-plugin-jsdoc": "48.2.7", - "eslint-plugin-no-null": "*", + "eslint-plugin-no-null": "latest", "eslint-plugin-prefer-arrow": "1.2.3", "exports-loader": "5.0.0", "file-loader": "6.2.0", @@ -17449,10 +17449,11 @@ } }, "node_modules/undici": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.15.0.tgz", - "integrity": "sha512-VviMt2tlMg1BvQ0FKXxrz1eJuyrcISrL2sPfBf7ZskX/FCEc/7LeThQaoygsMJpNqrATWQIsRVx+1Dpe4jaYuQ==", + "version": "6.19.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.2.tgz", + "integrity": "sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.17" } diff --git a/package.json b/package.json index 5afada3c1a..5dddf1e030 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@denbi/cloud-portal-webapp", - "version": "4.847.0", + "version": "4.848.0", "description": "de.NBI Cloud Portal", "scripts": { "ng": "ng serve", @@ -124,7 +124,7 @@ "webpack-cli": "5.1.4" }, "overrides": { - "undici": "6.15.0", + "undici": "6.19.2", "vite": "5.2.12" }, "lint-staged": { diff --git a/src/app/applications/application-card/application-card.component.html b/src/app/applications/application-card/application-card.component.html index 05d0a2ab73..b3c4b50121 100644 --- a/src/app/applications/application-card/application-card.component.html +++ b/src/app/applications/application-card/application-card.component.html @@ -23,6 +23,7 @@ [computeCenters]="computeCenters" (reloadNumbersTrigger)="triggerReloadNumbers()" (removeApplicationTrigger)="triggerRemoveApplication()" + (reloadApplicationTrigger)="getApplication()" > } @else if (facilityView) { } @if (!isCollapsed) { = new EventEmitter(); @Input() facilityView: boolean = false; @Input() voView: boolean = false; + @ViewChild('applicationdetail') applicationDetailComponent: ApplicationDetailComponent; bsModalRef: BsModalRef; is_vo_admin: boolean = false; - selectedComputeCenter: ComputecenterComponent; ngOnInit() { this.is_vo_admin = is_vo; @@ -61,11 +56,7 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni }); } - constructor( - private applicationsService: ApplicationsService, - private modalService: BsModalService, - private groupService: GroupService, - ) { + constructor(private applicationsService: ApplicationsService) { super(); } @@ -88,288 +79,11 @@ export class ApplicationCardComponent extends AbstractBaseClass implements OnIni ); } - resetApplicationPI(): void { - this.applicationsService.resetPIValidation(this.application).subscribe(() => { - this.getApplication(); - }); - } - switchCollaps() { this.isCollapsed = !this.isCollapsed; } - showNotificationModal( - notificationModalTitle: string, - notificationModalMessage: string, - notificationModalType: string, - ) { - const initialState = { notificationModalTitle, notificationModalType, notificationModalMessage }; - if (this.bsModalRef) { - this.bsModalRef.hide(); - } - - this.bsModalRef = this.modalService.show(NotificationModalComponent, { initialState }); - this.bsModalRef.setClass('modal-lg'); - } - - createSimpleVmProjectGroup(): void { - this.showNotificationModal('Info', 'Creating Project...', 'info'); - - if (this.selectedComputeCenter && this.selectedComputeCenter.FacilityId) { - this.groupService - .createGroupByApplication(this.application.project_application_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (res: any): void => { - if (!res['client_available'] && !res['created']) { - this.showNotificationModal( - 'Failed', - `The client ${res['client_name']} has not the necessary resources left!`, - 'danger', - ); - } else { - this.showNotificationModal('Success', 'The project was created!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - } - }, - (error: any): void => { - console.log(error); - const errorMessage = error && error.error === 'locked' - ? 'Project is locked and could not be created!' - : 'Project could not be created!'; - - this.showNotificationModal('Failed', errorMessage, 'danger'); - console.log(error); - }, - ); - } - } - - approveModificationRequest(): void { - this.applicationsService.approveModificationRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The resource modification request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - - // this.all_applications.splice(this.all_applications.indexOf(application), 1); - } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of resource modification failed!', 'danger'); - }, - ); - } - - declineModificationRequest(): void { - this.applicationsService.deleteModificationRequest(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The resource modification request was declined!', 'success'); - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - - this.getApplication(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of resource modification failed!', 'danger'); - }, - ); - } - - deleteApplication(): void { - // const idx: number = this.all_applications.indexOf(application); - - this.subscription.add( - this.applicationsService.deleteApplication(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Success', 'The application has been successfully removed', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.updateNotificationModal('Failed', 'Application could not be removed!', true, 'danger'); - }, - ), - ); - } - - declineLifetimeExtension(): void { - this.applicationsService.deleteAdditionalLifetimeRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The project extension was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of project extension failed!', 'danger'); - }, - ); - } - - declineCreditExtension(): void { - this.applicationsService.deleteAdditionalCreditsRequests(this.application.project_application_id).subscribe( - (): void => { - this.showNotificationModal('Declined', 'The credit extension request was declined!', 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Decline of credit extension failed!', 'danger'); - }, - ); - } - - declineApplication(): void { - // const idx: number = this.all_applications.indexOf(app); - this.applicationsService.declineApplication(this.application.project_application_id).subscribe( - (): void => { - const message: string = 'The Application was declined.'; - - this.showNotificationModal('Success', message, 'success'); - this.triggerRemoveApplication(); - this.triggerReloadNumbers(); - }, - (): void => { - this.showNotificationModal('Failed', 'Application could not be declined!', 'danger'); - }, - ); - } - - approveLifetimeExtension(): void { - this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( - (res: Response): void => { - if (this.application.project_application_openstack_project) { - this.getApplication(); - this.showNotificationModal('Success', 'The request has been sent to the facility manager.', 'success'); - } else { - this.showNotificationModal('Success', 'The project has been extended!', 'success'); - } - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - } - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Project lifetime could not be extendend!', 'danger'); - }, - ); - } - - approveCreditExtension(): void { - this.applicationsService.approveAdditionalCreditsRequest(this.application.project_application_id).subscribe( - (res: Response): void => { - this.showNotificationModal('Success', 'The credit extension request was approved!', 'success'); - if (!this.application.project_application_openstack_project) { - if (res.status === HttpStatusCode.Accepted) { - this.triggerReloadNumbers(); - this.triggerRemoveApplication(); - } - } else { - this.getApplication(); - } - }, - (err: any): void => { - console.log('error', err.status); - this.showNotificationModal('Failed', 'Approval of credit extension failed!', 'danger'); - }, - ); - } - - createOpenStackProjectGroup(): void { - this.groupService - .createGroupOpenStack(this.application.project_application_id, this.selectedComputeCenter.FacilityId) - .subscribe( - (result: { [key: string]: string }): void => { - if (result['Error']) { - this.showNotificationModal('Failed', result['Error'], 'danger'); - } else { - this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); - this.getApplication(); - // this.switchApproveLocked(false); - } - }, - (error: any): void => { - const errorMessage = error && error.error === 'locked' - ? 'Project is locked and could not be created!' - : 'Project could not be created!'; - - this.showNotificationModal('Failed', errorMessage, 'danger'); - console.log(error); - }, - ); - } - - /** - * Function to listen to modal results. - */ - subscribeToBsModalRef(): void { - this.subscription.add( - this.bsModalRef.content.event.subscribe((result: any) => { - let action = null; - if ('action' in result) { - action = result['action']; - } - if ('createSimpleVM' in result) { - this.createSimpleVmProjectGroup(); - } - if (action === ConfirmationActions.APPROVE_MODIFICATION) { - this.approveModificationRequest(); - } - if ('closed' in result) { - // this.switchApproveLocked(false); - } - if (action === ConfirmationActions.DECLINE_MODIFICATION) { - this.declineModificationRequest(); - } - if (action === ConfirmationActions.DELETE_APPLICATION) { - this.deleteApplication(); - } - if (action === ConfirmationActions.DECLINE_EXTENSION) { - this.declineLifetimeExtension(); - } - if (action === ConfirmationActions.DECLINE_CREDITS) { - this.declineCreditExtension(); - } - if (action === ConfirmationActions.DECLINE_APPLICATION) { - this.declineApplication(); - } - - if (action === ConfirmationActions.APPROVE_EXTENSION) { - this.approveLifetimeExtension(); - } - if (action === ConfirmationActions.RESET_PI) { - this.resetApplicationPI(); - } - if (action === ConfirmationActions.APPROVE_CREDITS) { - this.approveCreditExtension(); - } - if (action === ConfirmationActions.APPROVE_APPLICATION) { - if (this.application.project_application_openstack_project) { - this.createOpenStackProjectGroup(); - } - } - if (action === 'adjustedModificationRequest') { - // this.isLoaded = false; - // this.changeTabState(ApplicationTabStates.MODIFICATION_EXTENSION); - } - }), - ); - } - isCollapsed: boolean = true; protected readonly Application_States = Application_States; protected readonly ConfirmationActions = ConfirmationActions; - protected readonly ApplicationTabStates = ApplicationTabStates; } diff --git a/src/app/applications/application-detail/resource-detail/resource-detail.component.html b/src/app/applications/application-detail/resource-detail/resource-detail.component.html index fba0bb77b4..2f1d6a30fc 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 @@ -101,11 +101,11 @@ {{ flavorDiff.diff === 0 ? '' : flavorDiff.diff > 0 ? '+' : '-' }} - {{ flavorDiff.diff }} + {{ Math.abs(flavorDiff.diff) }} diff --git a/src/app/applications/application-facility-actions/application-facility-actions.component.ts b/src/app/applications/application-facility-actions/application-facility-actions.component.ts index f0435db1b8..a3b3ea5f4e 100644 --- a/src/app/applications/application-facility-actions/application-facility-actions.component.ts +++ b/src/app/applications/application-facility-actions/application-facility-actions.component.ts @@ -33,6 +33,7 @@ export class ApplicationFacilityActionsComponent extends AbstractBaseClass { isCollapsed: boolean = true; bsModalRef: BsModalRef; @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); + @Output() reloadApplicationTrigger: EventEmitter = new EventEmitter(); constructor( private facilityService: FacilityService, @@ -54,6 +55,10 @@ export class ApplicationFacilityActionsComponent extends AbstractBaseClass { this.reloadNumbersTrigger.emit(); } + triggerReloadApplication(): void { + this.reloadApplicationTrigger.emit(); + } + declineApplication(): void { this.showNotificationModal('Decline Application', 'Waiting..', 'info'); diff --git a/src/app/applications/application-list/application-list.component.ts b/src/app/applications/application-list/application-list.component.ts index f761a7873e..c1c4a11e4d 100644 --- a/src/app/applications/application-list/application-list.component.ts +++ b/src/app/applications/application-list/application-list.component.ts @@ -15,72 +15,73 @@ import { is_vo } from '../../shared/globalvar'; styleUrl: './application-list.component.scss', }) export class ApplicationListComponent implements OnInit, OnChanges { - @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; - dataTestId: string = ''; + @Input() applications: Application[] = []; + @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; + @Input() computeCenters: ComputecenterComponent[] = []; + @Input() facilityView: boolean = false; + @Input() voView: boolean = false; - is_vo_admin: boolean = false; + dataTestId: string = ''; - ngOnInit() { - this.is_vo_admin = is_vo; - this.setDataTestId(); - } + is_vo_admin: boolean = false; - ngOnChanges(changes: SimpleChanges) { - this.setDataTestId(); + ngOnInit() { + this.is_vo_admin = is_vo; + this.setDataTestId(); + } - } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ngOnChanges(changes: SimpleChanges) { + this.setDataTestId(); + } - setDataTestId(): void { - console.log('set data test id'); - switch (this.tabState) { - case ApplicationTabStates.SUBMITTED: { - this.dataTestId = 'submitted_applications_container'; - break; - } - case ApplicationTabStates.CREDITS_EXTENSION: { - this.dataTestId = 'credits_requests_applications_container'; - break; - } - case ApplicationTabStates.LIFETIME_EXTENSION: { - this.dataTestId = 'lifetime_requests_applications_container'; - break; - } - case ApplicationTabStates.MODIFICATION_EXTENSION: { - this.dataTestId = 'modification_requests_applications_container'; - break; - } - case ApplicationTabStates.TERMINATION_REQUEST: { - this.dataTestId = 'termination_requests_applications_container'; - break; - } - default: { - break; - } + setDataTestId(): void { + console.log('set data test id'); + switch (this.tabState) { + case ApplicationTabStates.SUBMITTED: { + this.dataTestId = 'submitted_applications_container'; + break; + } + case ApplicationTabStates.CREDITS_EXTENSION: { + this.dataTestId = 'credits_requests_applications_container'; + break; + } + case ApplicationTabStates.LIFETIME_EXTENSION: { + this.dataTestId = 'lifetime_requests_applications_container'; + break; + } + case ApplicationTabStates.MODIFICATION_EXTENSION: { + this.dataTestId = 'modification_requests_applications_container'; + break; + } + case ApplicationTabStates.TERMINATION_REQUEST: { + this.dataTestId = 'termination_requests_applications_container'; + break; + } + default: { + break; } - console.log(this.dataTestId); } + console.log(this.dataTestId); + } - 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.ts b/src/app/applications/application-vo-actions/application-vo-actions.component.ts index 68191fff20..958abb6c2f 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 @@ -33,6 +33,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements @Input() tabState: ApplicationTabStates = ApplicationTabStates.SUBMITTED; @Input() computeCenters: ComputecenterComponent[] = []; @Output() reloadNumbersTrigger: EventEmitter = new EventEmitter(); + @Output() reloadApplicationTrigger: EventEmitter = new EventEmitter(); @Output() removeApplicationTrigger: EventEmitter = new EventEmitter(); @Output() switchCollapseEvent: EventEmitter = new EventEmitter(); @@ -64,7 +65,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements .showAdjustLifetimeExtensionModal(this.application) .subscribe((eventSuccess: boolean) => { if (eventSuccess) { - this.getApplication(); + this.triggerReloadApplication(); this.showNotificationModal( 'Success', 'The lifetime of the extension request were adjusted successfully!', @@ -76,10 +77,14 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements }); } + triggerReloadApplication(): void { + this.reloadApplicationTrigger.emit(); + } + showAdjustApplicationModal() { this.adjustApplicationModal.showAdjustApplicationModal(this.application).subscribe((changed: boolean) => { if (changed) { - this.getApplication(); + this.triggerReloadApplication(); this.showNotificationModal('Success', 'The resources of the application were adjusted successfully!', 'success'); } else { @@ -160,7 +165,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements removeApplicationFromFacilityConfirmation(): void { this.groupService.removeGroupFromResource(this.application.project_application_perun_id.toString()).subscribe( (): void => { - this.getApplication(); + this.triggerReloadApplication(); this.showNotificationModal('Success', 'The application was removed from the compute center', 'success'); }, (): void => { @@ -169,24 +174,13 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements ); } - 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(); + this.triggerReloadApplication(); this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); }, @@ -202,7 +196,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements resetApplicationPI(): void { this.applicationsService.resetPIValidation(this.application).subscribe(() => { - this.getApplication(); + this.triggerReloadApplication(); }); } @@ -269,7 +263,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements // this.all_applications.splice(this.all_applications.indexOf(application), 1); } } else { - this.getApplication(); + this.triggerReloadApplication(); } }, (err: any): void => { @@ -286,7 +280,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements this.triggerReloadNumbers(); this.triggerRemoveApplication(); - this.getApplication(); + this.triggerReloadApplication(); }, (err: any): void => { console.log('error', err.status); @@ -360,7 +354,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements this.applicationsService.approveAdditionalLifetime(this.application.project_application_id).subscribe( (res: Response): void => { if (this.application.project_application_openstack_project) { - this.getApplication(); + this.triggerReloadApplication(); this.showNotificationModal('Success', 'The request has been sent to the facility manager.', 'success'); } else { this.showNotificationModal('Success', 'The project has been extended!', 'success'); @@ -389,7 +383,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements this.triggerRemoveApplication(); } } else { - this.getApplication(); + this.triggerReloadApplication(); } }, (err: any): void => { @@ -408,7 +402,7 @@ export class ApplicationVoActionsComponent extends AbstractBaseClass implements this.showNotificationModal('Failed', result['Error'], 'danger'); } else { this.showNotificationModal('Success', 'The project was assigned to the facility.', 'success'); - this.getApplication(); + this.triggerReloadApplication(); // this.switchApproveLocked(false); } }, diff --git a/src/app/applications/type-overview.component.html b/src/app/applications/type-overview.component.html index 174f0f468a..e0561c5a7d 100644 --- a/src/app/applications/type-overview.component.html +++ b/src/app/applications/type-overview.component.html @@ -1,762 +1,722 @@ @if (is_vo_admin) { -
- -
- -
- Our de.NBI Cloud Project Types - -
- -
- -
- -
- -
- - -
-
-
- SimpleVM -
-
-
-
- -
-
- Ease -
-
- Ease of Use – SimpleVM lets you start and stop VMs with a few - clicks - which means that - there is no additional configuration necessary. -
-
-
- -
-
- Curve -
-
- Flat Learning Curve – If you want to use SimpleVM you don’t have to - learn about - resource management, like network configurations or storage management. No - background - knowledge in Cloud - Computing is necessary. -
-
-
- -
-
- Remote -
-
- Remote Desktop – If you don’t want to use SimpleVM via terminal you - can - easily connect - to your VM using a Remote Desktop. -
-
-
-
-
- -
-
- Workshop support – Create a workshop and start multiple configured - VMs - for your - participants with just a few clicks. To learn more about our workshop support click - here. -
-
-
- -
-
- Typical use cases: -
    -
  • - Tools and Pipelines: SimpleVM is a quick way to get up and - running with your tools - and pipelines in the cloud. -
  • -
  • - Remote Desktop: Launch your own Desktop or a browser-based - IDE - in the cloud (based - on Apache Guacamole, RStudio, Theia IDE, and more) and be able to run - programs - with graphical user - interfaces in addition to the command-line. -
  • -
-
-
+
+ +
+ +
+ Our de.NBI Cloud Project Types + +
+ +
+ +
+ +
+ +
+ + +
+
+
+ SimpleVM +
+
+
+
+ +
+
+ Ease +
+
+ Ease of Use – SimpleVM lets you start and stop VMs with a few clicks which means that + there is no additional configuration necessary. +
+
+
+ +
+
+ Curve +
+
+ Flat Learning Curve – If you want to use SimpleVM you don’t have to learn about + resource management, like network configurations or storage management. No background knowledge in + Cloud Computing is necessary. +
+
+
+ +
+
+ Remote +
+
+ Remote Desktop – If you don’t want to use SimpleVM via terminal you can easily + connect to your VM using a Remote Desktop. +
+
+
+
+
+ +
+
+ Workshop support – Create a workshop and start multiple configured VMs for your + participants with just a few clicks. To learn more about our workshop support click + here. +
+
+
+ +
+
+ Typical use cases: +
    +
  • + Tools and Pipelines: SimpleVM is a quick way to get up and running with your + tools and pipelines in the cloud. +
  • +
  • + Remote Desktop: Launch your own Desktop or a browser-based IDE in the cloud + (based on Apache Guacamole, RStudio, Theia IDE, and more) and be able to run programs with + graphical user interfaces in addition to the command-line. +
  • +
+
+
-
-
- -
-
-
- Want to learn more about SimpleVM? -
- -
-
-
- -
+
+
+ +
+
+
+ Want to learn more about SimpleVM? +
+ +
+
+
+ +
- -
- - -
-
-
- Openstack -
-
-
-
- -
-
- Scale -
-
- Scalability – Easy scaling of virtual machines and distribution of - data - for efficient - computations. -
-
-
- -
-
- Configuration -
-
- Configurability – OpenStack allows the configuration of any - resource - type available, - such as virtual machines, network, block and object storage. -
-
-
- -
-
- API -
-
- API Access – Any interaction with OpenStack can be automated via - its - API enabling users - to script actions, e.g. starting and stopping of virtual machines. -
-
-
- -
-
- Typical use cases: -
    -
  • - Distributed Workflows: Distribution of workflows on - multiple - virtual machines. -
  • -
  • Services: The ability to offer services for other - researchers. -
  • -
-
-
+ +
+ + +
+
+
+ Openstack +
+
+
+
+ +
+
+ Scale +
+
+ Scalability – Easy scaling of virtual machines and distribution of data for efficient + computations. +
+
+
+ +
+
+ Configuration +
+
+ Configurability – OpenStack allows the configuration of any resource type available, + such as virtual machines, network, block and object storage. +
+
+
+ +
+
+ API +
+
+ API Access – Any interaction with OpenStack can be automated via its API enabling + users to script actions, e.g. starting and stopping of virtual machines. +
+
+
+ +
+
+ Typical use cases: +
    +
  • + Distributed Workflows: Distribution of workflows on multiple virtual machines. +
  • +
  • Services: The ability to offer services for other researchers.
  • +
+
+
-
-
- -
-
-
- Want to learn more about Openstack? -
- -
-
-
- -
-
- - -
-
-
- Kubernetes -
-
-
-
- -
-
- Scale -
-
- Scalability – Easy scaling of virtual machines and distribution of - data for efficient - computations. -
-
-
- -
-
- Configuration -
-
- Configurability – Kubernetes allows the configuration of any - resource type available, - such as virtual machines, network. -
-
-
- -
-
- API -
-
- API Access – Any interaction with Kubernetes can be automated via - its API enabling - users to script actions, e.g. starting and stopping of containerized services. -
-
-
- -
-
- Typical use cases: -
    -
  • - Workflow Engines: Workflow engines like Nextflow allow you - to run your analysis on - top of Kubernetes. -
  • -
  • - Services: The ability to offer stateless and stateful - (databases) services for - other researchers. -
  • -
-
-
+
+
+ +
+
+
+ Want to learn more about Openstack? +
+ +
+
+
+ +
+
+ + +
+
+
+ Kubernetes +
+
+
+
+ +
+
+ Scale +
+
+ Scalability – Easy scaling of containers and distribution of data for efficient + computations. +
+
+
+ +
+
+ Configuration +
+
+ Configurability – Kubernetes allows the configuration of any resource type available, + such as virtual machines, network. +
+
+
+ +
+
+ API +
+
+ API Access – Any interaction with Kubernetes can be automated via its API enabling + users to script actions, e.g. starting and stopping of containerized services. +
+
+
+ +
+
+ Typical use cases: +
    +
  • + Workflow Engines: Workflow engines like Nextflow allow you to run your analysis + on top of Kubernetes. +
  • +
  • + Services: The ability to offer stateless and stateful (databases) services for + other researchers. +
  • +
+
+
-
-
-
-
-
- Want to learn more about Kubernetes? -
- -
-
-
- -
+
+
+
+
+
+ Want to learn more about Kubernetes? +
+ +
+
+
+ +
- - -
- -
-
- -
-
- Want to learn more about SimpleVM? -
- -
- - -
-
- Want to learn more about Openstack? -
- -
-
-
- Want to learn more about Kubernetes? -
- -
- -
-
-
-
-
-
- Want to learn the Difference? -
- -
-
-
-
- -
- -
- -
- -
- -
+ +
+ +
+
+ +
+
+ Want to learn more about SimpleVM? +
+ +
+ + +
+
+ Want to learn more about Openstack? +
+ +
+
+
+ Want to learn more about Kubernetes? +
+ +
+
+
+
+
+
+
+ Want to learn the Difference? +
+ +
+
+
+
+ +
+ +
+ +
+ +
+ +
} @else { -
- -
- -
- Our de.NBI Cloud Project Types - -
- -
- -
- - -
- -
- -
- -
-
-
- SimpleVM -
-
-
-
- -
-
- Ease -
-
- Ease of Use – SimpleVM lets you start and stop VMs with a few - clicks which means that - there is no additional configuration necessary. -
-
-
- -
-
- Curve -
-
- Flat Learning Curve – If you want to use SimpleVM you don’t have to - learn about - resource management, like network configurations or storage management. No - background knowledge in Cloud - Computing is necessary. -
-
-
- -
-
- Remote -
-
- Remote Desktop – If you don’t want to use SimpleVM via terminal you - can easily connect - to your VM using a Remote Desktop. -
-
-
-
-
- -
-
- Workshop support – Create a workshop and start multiple configured - VMs for your - participants with just a few clicks. To learn more about our workshop support click - here. -
-
-
- -
-
-
-
- Typical use cases: -
-
-
-
-
-
- • Tools and Pipelines - – SimpleVM is a quick way to get up and running with your tools and pipelines in - the cloud. -
-
-
-
-
-
- • Remote Desktop - – Launch your own Desktop or a browser based IDE in the cloud (based on Apache - Guacamole, RStudio, - Theia IDE and more) and be able to run programs with graphical user interfaces - in addition to the - command-line. -
-
-
-
-
- -
-
-
- Want to learn more about SimpleVM? -
- -
-
- -
- - - -
-
-
- Want to learn the Difference between SimpleVM and Openstack? -
- -
-
+
+ +
+ +
+ Our de.NBI Cloud Project Types + +
+ +
+ +
+ + +
+ +
+ +
+ +
+
+
+ SimpleVM +
+
+
+
+ +
+
+ Ease +
+
+ Ease of Use – SimpleVM lets you start and stop VMs with a few clicks which means that + there is no additional configuration necessary. +
+
+
+ +
+
+ Curve +
+
+ Flat Learning Curve – If you want to use SimpleVM you don’t have to learn about + resource management, like network configurations or storage management. No background knowledge in + Cloud Computing is necessary. +
+
+
+ +
+
+ Remote +
+
+ Remote Desktop – If you don’t want to use SimpleVM via terminal you can easily + connect to your VM using a Remote Desktop. +
+
+
+
+
+ +
+
+ Workshop support – Create a workshop and start multiple configured VMs for your + participants with just a few clicks. To learn more about our workshop support click + here. +
+
+
+ +
+
+
+
+ Typical use cases: +
+
+
+
+
+
+ • Tools and Pipelines + – SimpleVM is a quick way to get up and running with your tools and pipelines in the cloud. +
+
+
+
+
+
+ • Remote Desktop + – Launch your own Desktop or a browser based IDE in the cloud (based on Apache Guacamole, RStudio, + Theia IDE and more) and be able to run programs with graphical user interfaces in addition to the + command-line. +
+
+
+
+
+ +
+
+
+ Want to learn more about SimpleVM? +
+ +
+
+ +
- -
- -
-
-
- Openstack -
-
-
-
- -
-
- Scale -
-
- Scalability – Easy scaling of virtual machines and distribution of - data for efficient - computations. -
-
-
- -
-
- Configuration -
-
- Configurability – OpenStack allows the configuration of any - resource type available, - such as virtual machines, network, block and object storage. -
-
-
- -
-
- API -
-
- API Access – Any interaction with OpenStack can be automated via - its API enabling users - to script actions, e.g. starting and stopping of virtual machines. -
-
-
- -
-
-
-
- Typical use cases: -
-
-
-
-
-
- • Distributed Workflows - – Distribution of workflows on multiple virtual machines. -
-
-
-
-
-
- • Services - – The ability to offer services for other researchers. -
-
-
-
-
- -
-
-
- Want to learn more about Openstack? -
- -
-
-
- -
- -
- -
-
- -
-
- Want to learn more about SimpleVM? -
- -
- -
-
- Want to learn the Difference? -
- -
- -
-
- Want to learn more about Openstack? -
- -
-
-
- -
- -
- -
- -
- -
+ + +
+
+
+ Want to learn the Difference between SimpleVM and Openstack? +
+ +
+
-} \ No newline at end of file + +
+ +
+
+
+ Openstack +
+
+
+
+ +
+
+ Scale +
+
+ Scalability – Easy scaling of virtual machines and distribution of data for efficient + computations. +
+
+
+ +
+
+ Configuration +
+
+ Configurability – OpenStack allows the configuration of any resource type available, + such as virtual machines, network, block and object storage. +
+
+
+ +
+
+ API +
+
+ API Access – Any interaction with OpenStack can be automated via its API enabling + users to script actions, e.g. starting and stopping of virtual machines. +
+
+
+ +
+
+
+
+ Typical use cases: +
+
+
+
+
+
+ • Distributed Workflows + – Distribution of workflows on multiple virtual machines. +
+
+
+
+
+
+ • Services + – The ability to offer services for other researchers. +
+
+
+
+
+ +
+
+
+ Want to learn more about Openstack? +
+ +
+
+
+ +
+ +
+ +
+
+ +
+
+ Want to learn more about SimpleVM? +
+ +
+ +
+
+ Want to learn the Difference? +
+ +
+ +
+
+ Want to learn more about Openstack? +
+ +
+
+
+ +
+ +
+ +
+ +
+ +
+} diff --git a/src/app/facility_manager/facilityprojectsoverview.component.html b/src/app/facility_manager/facilityprojectsoverview.component.html index cd9cc581dd..d7feed64bd 100644 --- a/src/app/facility_manager/facilityprojectsoverview.component.html +++ b/src/app/facility_manager/facilityprojectsoverview.component.html @@ -45,8 +45,7 @@
- -
diff --git a/src/app/facility_manager/facilityprojectsoverview.component.ts b/src/app/facility_manager/facilityprojectsoverview.component.ts index 4bbf018218..b722a8d618 100644 --- a/src/app/facility_manager/facilityprojectsoverview.component.ts +++ b/src/app/facility_manager/facilityprojectsoverview.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit, QueryList, ViewChildren, inject, } from '@angular/core'; -import { Observable, Subject, take } from 'rxjs'; +import { Observable, take } from 'rxjs'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { MatomoTracker } from 'ngx-matomo-client'; import { ProjectMember } from '../projectmanagement/project_member.model'; @@ -19,10 +19,10 @@ import { import { ProjectSortService } from '../shared/shared_modules/services/project-sort.service'; import { AbstractBaseClass } from '../shared/shared_modules/baseClass/abstract-base-class'; import { ProjectEmailModalComponent } from '../shared/modal/email/project-email-modal/project-email-modal.component'; -import { NotificationModalComponent } from '../shared/modal/notification-modal'; import { MembersListModalComponent } from '../shared/modal/members/members-list-modal.component'; import { EmailService } from '../api-connector/email.service'; import { CsvMailTemplateModel } from '../shared/classes/csvMailTemplate.model'; +import { ProjectCsvTemplatedEmailModalComponent } from '../shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component'; /** * Facility Project overview component. @@ -43,9 +43,7 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme public memberFilter: string = ''; filteredMembers: object[] = []; selectedMember: object[] = []; - facility_members: object[] = []; - filterChanged: Subject = new Subject(); isLoaded: boolean = false; projects: Application[] = []; projectsCopy: Application[] = []; @@ -183,7 +181,11 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme ); } } + openProjectCSVMailModal(): void { + console.log('show'); + this.bsModalRef = this.modalService.show(ProjectCsvTemplatedEmailModalComponent, { class: 'modal-lg' }); + } onSort({ column, direction }: SortEvent) { // resetting other headers this.headers.forEach(header => { @@ -196,10 +198,6 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme this.sortProjectService.sortDirection = direction; } - searchForUserInFacility(searchString: string): void { - this.facilityService.getFilteredMembersOfFacility(searchString); - } - filterMembers(bare_searchString: string): void { this.filteredMembers = []; const searchString: string = bare_searchString.toLowerCase(); @@ -516,24 +514,6 @@ export class FacilityProjectsOverviewComponent extends AbstractBaseClass impleme initialState = { selectedProjects: this.selectedEmailProjects }; } this.bsModalRef = this.modalService.show(ProjectEmailModalComponent, { initialState, class: 'modal-lg' }); - this.bsModalRef.content.event.subscribe((sent_successfully: boolean) => { - if (sent_successfully) { - const initialStateNotification = { - notificationModalTitle: 'Success', - notificationModalType: 'success', - notificationModalMessage: 'Mails were successfully sent', - }; - - this.modalService.show(NotificationModalComponent, { initialState: initialStateNotification }); - } else { - const initialStateNotification = { - notificationModalTitle: 'Failed', - notificationModalType: 'danger', - notificationModalMessage: 'Failed to send mails!', - }; - this.modalService.show(NotificationModalComponent, { initialState: initialStateNotification }); - } - }); } setFacilitySupportMails(supportMails: string): void { diff --git a/src/app/projectmanagement/modals/withdraw/withdraw-modal.component.ts b/src/app/projectmanagement/modals/withdraw/withdraw-modal.component.ts index ff6ca1edcf..bd8eef3a06 100644 --- a/src/app/projectmanagement/modals/withdraw/withdraw-modal.component.ts +++ b/src/app/projectmanagement/modals/withdraw/withdraw-modal.component.ts @@ -39,6 +39,8 @@ export class WithdrawModalComponent { this.event.emit(true); }); break; + default: + this.event.emit(false); } } diff --git a/src/app/projectmanagement/projectmanagement.module.ts b/src/app/projectmanagement/projectmanagement.module.ts index 2b53063b0a..96bd65b697 100644 --- a/src/app/projectmanagement/projectmanagement.module.ts +++ b/src/app/projectmanagement/projectmanagement.module.ts @@ -25,6 +25,7 @@ import { ResultComponent } from './modals/result/result.component'; import { SharedModuleModule } from '../shared/shared_modules/shared-module.module'; import { AdjustLifetimeRequestComponent } from './modals/adjust-lifetime/adjust-lifetime-request.component'; import { AdjustApplicationComponent } from './modals/adjust-application/adjust-application.component'; +import { WithdrawModalComponent } from './modals/withdraw/withdraw-modal.component'; /** * Projectmanagment module. @@ -59,6 +60,7 @@ import { AdjustApplicationComponent } from './modals/adjust-application/adjust-a ExtensionEntryComponent, AdjustLifetimeRequestComponent, AdjustApplicationComponent, + WithdrawModalComponent, ], exports: [ProjectOsDetailsComponent, ExtensionEntryComponent], }) diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html new file mode 100644 index 0000000000..adb3016ba2 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.html @@ -0,0 +1,194 @@ + + + + + diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts new file mode 100644 index 0000000000..aa5c04b137 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email-modal.component.ts @@ -0,0 +1,94 @@ +import { + Component, EventEmitter, OnDestroy, OnInit, +} from '@angular/core'; +import { BsModalRef } from 'ngx-bootstrap/modal'; +import { Application } from '../../../../applications/application.model/application.model'; +import { EmailService } from '../../../../api-connector/email.service'; +import { STATUS_LINK } from '../../../../../links/links'; +import { CsvMailTemplateModel } from '../../../classes/csvMailTemplate.model'; +import { NotificationModalComponent } from '../../notification-modal'; + +@Component({ + selector: 'app-project-csv-templated-email-modal', + templateUrl: './project-csv-templated-email-modal.component.html', + styleUrls: ['./project-csv-templated-email.scss'], + providers: [EmailService], +}) +export class ProjectCsvTemplatedEmailModalComponent implements OnInit, OnDestroy { + csvMailTemplate: CsvMailTemplateModel; + csvFile: File; + + emailAdminsOnly: boolean; + emailSubject: string; + emailReply: string; + emailText: string; + templates: string[]; + validCSVExample = `Project, VM, LOCATION +Proj1, VM_1, Bielefeld +Proj2, VM_2, Giessen`; + + public event: EventEmitter = new EventEmitter(); + + constructor( + public bsModalRef: BsModalRef, + private emailService: EmailService, + private notificationModal: NotificationModalComponent, + ) { + // eslint-disable-next-line no-empty-function + } + + ngOnInit() { + this.getMailTemplates(); + } + + onCsvFileSelected(event): void { + const inputElement = event.target as HTMLInputElement; + this.csvFile = inputElement.files[0]; + if (this.csvFile) { + this.emailService.sendCsvTemplate(this.csvFile).subscribe( + (csvTemplate: CsvMailTemplateModel) => { + this.csvMailTemplate = csvTemplate; + }, + (error: CsvMailTemplateModel) => { + this.csvMailTemplate = error; + console.log(error['error']); + }, + ); + } + } + + getMailTemplates(): void { + this.emailService.getMailTemplates().subscribe((res: string[]) => { + this.templates = res; + }); + } + + sentProjectsTemplatedMail(): void { + const project_ids = this.csvMailTemplate.valid_projects.map((pr: Application) => pr.project_application_perun_id); + this.notificationModal.showInfoNotificationModal('Info', 'Sending Mails...'); + + this.emailService + .sendCsvTemplatedMail( + this.csvFile, + project_ids, + this.emailSubject, + this.emailText, + this.emailAdminsOnly, + this.emailReply, + ) + .subscribe( + () => { + this.notificationModal.showSuccessFullNotificationModal('Success', 'Mails were successfully sent!'); + }, + () => { + this.notificationModal.showDangerNotificationModal('Failed', 'Failed to send mails!'); + }, + ); + } + + ngOnDestroy(): void { + this.bsModalRef.hide(); + } + + protected readonly STATUS_LINK = STATUS_LINK; +} diff --git a/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss new file mode 100644 index 0000000000..a86e9ffc41 --- /dev/null +++ b/src/app/shared/modal/email/project-csv-templated-email-modal/project-csv-templated-email.scss @@ -0,0 +1,25 @@ +.templates-container { + border: 1px solid #ccc; + padding: 10px; + background-color: #f9f9f9; +} + +.templates-list { + margin: 10px 0; + font-family: monospace; +} + +.valid-example { + border: 1px solid #ccc; + padding: 10px; + background-color: #f9f9f9; + margin-top: 10px; +} + +.valid-example-heading { + margin-bottom: 5px; +} + +.valid-example-content { + font-family: monospace; +} \ No newline at end of file diff --git a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html index 5584431736..1b9623c3e8 100644 --- a/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html +++ b/src/app/shared/modal/email/project-email-modal/project-email-modal.component.html @@ -16,31 +16,6 @@