Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:deNBI/cloud-portal-webapp into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
dweinholz committed Nov 26, 2024
2 parents 88c18f1 + afdc1ac commit d6b0fac
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 48 deletions.
13 changes: 7 additions & 6 deletions src/app/projectmanagement/overview.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ <h3>
</button>

<button
(click)="removeCheckedMembers()"
(click)="showConfirmationModalRemoveMembers()"
[disabled]="checked_member_list.length <= 0 || remove_members_clicked"
class="btn btn-outline-danger"
style="margin-bottom: 5px"
Expand Down Expand Up @@ -1075,9 +1075,10 @@ <h3>
<tr *ngFor="let member of project_members" [ngStyle]="{ color: member.isAdmin ? '#005AA9' : 'black' }">
<td *ngIf="project_application.user_is_admin || is_vo_admin">
<input
(change)="checkUnCheckMember(member.memberId)"
(change)="checkUnCheckMember(member)"
*ngIf="userinfo?.MemberId.toString() !== member.memberId.toString()"
[checked]="isMemberChecked(member.memberId)"
[checked]="isMemberChecked(member)"
[disabled]="member.isPi"
id="{{ member.userId }}"
name="member.userId"
type="checkbox"
Expand Down Expand Up @@ -1110,7 +1111,7 @@ <h3>
<td *ngIf="project_application.user_is_pi || project_application.user_is_admin || is_vo_admin">
<div class="btn-group" role="group">
<button
(click)="promoteAdmin(member.userId, member.userName); notificationModal.show()"
(click)="promoteAdmin(member.userId, member.userName)"
*ngIf="!member.isAdmin"
class="btn btn-primary"
style="margin: 2px"
Expand All @@ -1120,7 +1121,7 @@ <h3>
</button>

<button
(click)="removeAdmin(member.userId, member.userName); notificationModal.show()"
(click)="removeAdmin(member.userId, member.userName)"
*ngIf="
member.isAdmin && userinfo?.MemberId.toString() !== member.memberId.toString() && !member.isPi
"
Expand All @@ -1132,7 +1133,7 @@ <h3>
<i class="fa fa-minus-circle"></i>&nbsp; Remove Admin status
</button>
<button
(click)="removeMember(member.memberId, member.userName); notificationModal.show()"
(click)="showConfirmationModalRemoveMember(member)"
*ngIf="userinfo?.MemberId.toString() !== member.memberId.toString()"
[id]="'remove_member_' + member.userName"
[disabled]="member?.isPi"
Expand Down
127 changes: 96 additions & 31 deletions src/app/projectmanagement/overview.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import { NotificationModalComponent } from '../shared/modal/notification-modal'
import { DeleteApplicationModal } from './modals/delete-member-application-modal/delete-application-modal.component'
import { AddUserModalComponent } from './modals/add-user-modal/add-user-modal.component'
import { UserApplicationsModalComponent } from './modals/user-applications-modal/user-applications-modal.component'
import { ConfirmationActions } from 'app/shared/modal/confirmation_actions'
import { ConfirmationModalComponent } from 'app/shared/modal/confirmation-modal.component'

/**
* Projectoverview component.
Expand All @@ -59,6 +61,8 @@ import { UserApplicationsModalComponent } from './modals/user-applications-modal
})
export class OverviewComponent extends ApplicationBaseClassComponent implements OnInit, OnDestroy {
bsModalRef: BsModalRef
protected readonly ConfirmationActions = ConfirmationActions

modificationRequestDisabled: boolean = false
lifetimeExtensionDisabled: boolean = false
creditsExtensionDisabled: boolean = false
Expand Down Expand Up @@ -105,7 +109,7 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements
simple_vm_logo: string = 'static/webapp/assets/img/simpleVM_Logo.svg'
openstack_logo: string = 'static/webapp/assets/img/openstack_plain_red.svg'
kubernetes_logo: string = 'static/webapp/assets/img/kubernetes_logo.svg'
checked_member_list: number[] = []
checked_member_list: ProjectMember[] = []
// modal variables for User list
public project_members: ProjectMember[] = []
public isLoaded: boolean = false
Expand Down Expand Up @@ -722,10 +726,11 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements
if (!this.allSet) {
this.project_members.forEach((member: ProjectMember): void => {
if (
!this.isMemberChecked(parseInt(member.memberId.toString(), 10)) &&
this.userinfo.MemberId.toString() !== member.memberId.toString()
!this.isMemberChecked(member) &&
this.userinfo.MemberId.toString() !== member.memberId.toString() &&
!member.isPi
) {
this.checked_member_list.push(parseInt(member.memberId.toString(), 10))
this.checked_member_list.push(member)
}
})
this.allSet = true
Expand All @@ -734,52 +739,101 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements
this.allSet = false
}
}

isMemberChecked(id: number): boolean {
return this.checked_member_list.indexOf(id) > -1
isMemberChecked(member: ProjectMember): boolean {
return this.checked_member_list.some(checked_member => checked_member.memberId === member.memberId)
}
indexOfMemberChecked(member_id): number {
return this.checked_member_list.findIndex(member => member.memberId === member_id)
}

checkIfAllMembersChecked(): void {
let all_set: boolean = true
this.project_members.forEach((member: ProjectMember): void => {
if (
!this.isMemberChecked(parseInt(member.memberId.toString(), 10)) &&
this.userinfo.MemberId !== member.memberId
) {
if (!this.isMemberChecked(member) && this.userinfo.MemberId !== member.memberId && !member.isPi) {
all_set = false
}
})

this.allSet = all_set
}

checkUnCheckMember(id: number): void {
const indexOf: number = this.checked_member_list.indexOf(id)
checkUnCheckMember(member: ProjectMember): void {
const indexOf: number = this.indexOfMemberChecked(member.memberId)
if (indexOf !== -1) {
this.checked_member_list.splice(indexOf, 1)
this.allSet = false
} else {
this.checked_member_list.push(id)
this.checked_member_list.push(member)
this.checkIfAllMembersChecked()
}
}

showConfirmationModalRemoveMembers(): void {
const action = this.ConfirmationActions.REMOVE_MEMBERS
const member_names_as_string = this.checked_member_list
.map(member => `${member.firstName} ${member.lastName}`)
.join('<br>')
const initialState = {
application: this.project_application,
action,
additional_msg: member_names_as_string
}

this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' })
this.subscribeToBsModalRef()
}

showConfirmationModalRemoveMember(member: ProjectMember): void {
const action = this.ConfirmationActions.REMOVE_MEMBER
const initialState = {
application: this.project_application,
action,
additional_msg: `${member.firstName} ${member.lastName}`
}

this.bsModalRef = this.modalService.show(ConfirmationModalComponent, { initialState, class: 'modal-lg' })
this.subscription.add(
this.bsModalRef.content.event.subscribe((event: any) => {
const action: ConfirmationActions = event.action
if (action === ConfirmationActions.REMOVE_MEMBER) {
this.removeMember(member)
}
})
)
}

subscribeToBsModalRef(): void {
this.subscription.add(
this.bsModalRef.content.event.subscribe((event: any) => {
const action: ConfirmationActions = event.action
switch (action) {
case ConfirmationActions.REMOVE_MEMBERS: {
this.removeCheckedMembers()
break
}
default:
break
}
})
)
}

removeCheckedMembers(): void {
this.remove_members_clicked = true

const members_in: ProjectMember[] = []

const observables: Observable<number>[] = this.checked_member_list.map(
(id: number): Observable<any> =>
(member: ProjectMember): Observable<any> =>
this.groupService.removeMember(
Number(this.project_application.project_application_perun_id),
id,
member.memberId,
this.project_application.project_application_compute_center.FacilityId
)
)
forkJoin(observables).subscribe((): void => {
this.project_members.forEach((member: ProjectMember): void => {
if (!this.isMemberChecked(parseInt(member.memberId.toString(), 10))) {
if (!this.isMemberChecked(member)) {
members_in.push(member)
}
})
Expand Down Expand Up @@ -814,14 +868,15 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements
.toPromise()
.then((result: any): void => {
if (result.status === 200) {
this.updateNotificationModal('Success', `${username} promoted to Admin`, true, 'success')
this.notificationModal.showSuccessFullNotificationModal('Success', `${username} promoted to Admin`)

this.getMembersOfTheProject()
} else {
this.updateNotificationModal('Failed', `${username} could not be promoted to Admin!`, true, 'danger')
this.notificationModal.showDangerNotificationModal('Failed', `${username} could not be promoted to Admin!`)
}
})
.catch((): void => {
this.updateNotificationModal('Failed', `${username} could not be promoted to Admin!`, true, 'danger')
this.notificationModal.showDangerNotificationModal('Failed', `${username} could not be promoted to Admin!`)
})
}

Expand All @@ -839,50 +894,60 @@ export class OverviewComponent extends ApplicationBaseClassComponent implements
.toPromise()
.then((result: any): void => {
if (result.status === 200) {
this.updateNotificationModal('Success', `${name} was removed as Admin`, true, 'success')
this.notificationModal.showSuccessFullNotificationModal('Success', `${name} was removed as Admin`)

this.getMembersOfTheProject()
} else {
this.updateNotificationModal('Failed', `${name} could not be removed as Admin!`, true, 'danger')
this.notificationModal.showDangerNotificationModal('Failed', `${name} could not be removed as Admin!`)
}
})
.catch((): void => {
this.updateNotificationModal('Failed', `${name} could not be removed as Admin!`, true, 'danger')
this.notificationModal.showDangerNotificationModal('Failed', `${name} could not be removed as Admin!`)
})
}

/**
* Remove a member from a group.
*
* @param memberid of the member
* @param name of the member
*/
public removeMember(memberid: number, name: string): void {
if (this.userinfo.MemberId.toString() === memberid.toString()) {
public removeMember(member: ProjectMember): void {
if (this.userinfo.MemberId.toString() === member.memberId.toString()) {
return
}
const indexOf: number = this.checked_member_list.indexOf(memberid)
const indexOf: number = this.indexOfMemberChecked(member.memberId)
if (indexOf !== -1) {
this.checked_member_list.splice(indexOf, 1)
this.allSet = false
}

this.subscription.add(
this.groupService
.removeMember(
this.project_application.project_application_perun_id,
memberid,
member.memberId,
this.project_application.project_application_compute_center.FacilityId
)
.subscribe(
(result: any): void => {
if (result.status === 200) {
this.updateNotificationModal('Success', `Member ${name} removed from the group`, true, 'success')
this.notificationModal.showSuccessFullNotificationModal(
'Success',
`Member ${member.firstName} ${member.lastName} removed from the group`
)
this.getMembersOfTheProject()
} else {
this.updateNotificationModal('Failed', `Member ${name} could not be removed !`, true, 'danger')
this.notificationModal.showDangerNotificationModal(
'Failed',
`Member ${member.firstName} ${member.lastName} could not be removed !`
)
}
},
(): void => {
this.updateNotificationModal('Failed', `Member ${name} could not be removed !`, true, 'danger')
this.notificationModal.showDangerNotificationModal(
'Failed',
`Member ${member.firstName} ${member.lastName} could not be removed !`
)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export abstract class AbstractBaseModalComponent {

async hide(): Promise<void> {
console.log('close modal abstract')
this.modalService.hide()
this.modalService.hide(this.modalId)

//Fix when calling hide and show form within a modal -- if it is called directly after another the new modal won't open
await this.sleep(200)
await this.sleep(300)
}

private async sleep(ms: number): Promise<void> {
Expand Down
7 changes: 6 additions & 1 deletion src/app/shared/modal/confirmation-modal.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ <h4 class="modal-title text-dark" data-test-id="confirmation_modal_title">{{ mod
id="confirmation_modal_message"
>
<p data-test-id="confirmation_modal_message">
{{ modalMessage }} for {{ application.project_application_shortname }}?
{{ modalMessage }}: {{ application.project_application_shortname }}?
</p>
@if (additional_msg) {
<div class="alert alert-warning" role="alert">
<span [innerHTML]="additional_msg"></span>
</div>
}
</div>
</div>
<div class="modal-footer">
Expand Down
26 changes: 18 additions & 8 deletions src/app/shared/modal/confirmation-modal.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, EventEmitter, Injectable, OnDestroy, OnInit } from '@angular/core'
import { Component, EventEmitter, Injectable, OnInit } from '@angular/core'
import { BsModalService } from 'ngx-bootstrap/modal'
import { Application } from '../../applications/application.model/application.model'
import { ConfirmationTypes } from './confirmation_types'
Expand All @@ -13,13 +13,14 @@ import { AbstractBaseModalComponent } from './abstract-base-modal/abstract-base-
templateUrl: './confirmation-modal.component.html',
providers: []
})
export class ConfirmationModalComponent extends AbstractBaseModalComponent implements OnDestroy, OnInit {
export class ConfirmationModalComponent extends AbstractBaseModalComponent implements OnInit {
protected readonly ConfirmationTypes = ConfirmationTypes

application: Application = null
modalTitle: string = ''
modalMessage: string = ''
application_center: string = ''
additional_msg: string = ''
action: ConfirmationActions
type: ConfirmationTypes
request_failed: boolean = false
Expand Down Expand Up @@ -56,7 +57,9 @@ export class ConfirmationModalComponent extends AbstractBaseModalComponent imple
selectedCenter: this.application_center
},
[ConfirmationActions.DISABLE_APPLICATION]: { action: ConfirmationActions.DISABLE_APPLICATION },
[ConfirmationActions.ENABLE_APPLICATION]: { action: ConfirmationActions.ENABLE_APPLICATION }
[ConfirmationActions.ENABLE_APPLICATION]: { action: ConfirmationActions.ENABLE_APPLICATION },
[ConfirmationActions.REMOVE_MEMBERS]: { action: ConfirmationActions.REMOVE_MEMBERS },
[ConfirmationActions.REMOVE_MEMBER]: { action: ConfirmationActions.REMOVE_MEMBER }
}

const selectedAction = actionsMap[this.action]
Expand Down Expand Up @@ -92,7 +95,8 @@ export class ConfirmationModalComponent extends AbstractBaseModalComponent imple
return 'Declination'
case ConfirmationTypes.RESET_PI:
return 'Reset PI'

case ConfirmationTypes.REMOVE:
return 'Removal'
default:
break
}
Expand Down Expand Up @@ -172,6 +176,16 @@ export class ConfirmationModalComponent extends AbstractBaseModalComponent imple
title: 'Decline Termination',
type: ConfirmationTypes.DECLINE,
message: 'Do you really want to decline the termination of this project'
},
[ConfirmationActions.REMOVE_MEMBERS]: {
title: 'Remove Members',
type: ConfirmationTypes.REMOVE,
message: `Do you really want to remove the member(s) from the project`
},
[ConfirmationActions.REMOVE_MEMBER]: {
title: 'Remove Member',
type: ConfirmationTypes.REMOVE,
message: `Do you really want to remove the member from the project`
}
}

Expand All @@ -183,8 +197,4 @@ export class ConfirmationModalComponent extends AbstractBaseModalComponent imple
this.modalMessage = data.message
}
}

ngOnDestroy(): void {
this.bsModalRef.hide()
}
}
Loading

0 comments on commit d6b0fac

Please sign in to comment.