383 lines
16 KiB
TypeScript
383 lines
16 KiB
TypeScript
import {ChangeDetectorRef, Component, OnInit, ViewChild} from "@angular/core";
|
|
import {StakeholderBaseComponent} from "../utils/stakeholder-base.component";
|
|
import {ActivatedRoute, Router} from "@angular/router";
|
|
import {Title} from "@angular/platform-browser";
|
|
import {StakeholderService} from "../../monitor/services/stakeholder.service";
|
|
import {ManageStakeholders, Stakeholder, StakeholderType, Umbrella} from "../../monitor/entities/stakeholder";
|
|
import {Session, User} from "../../login/utils/helper.class";
|
|
import {UserManagementService} from "../../services/user-management.service";
|
|
import {FormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
|
|
import {AlertModal} from "../../utils/modal/alert";
|
|
import {NotificationHandler} from "../../utils/notification-handler";
|
|
import {Option} from "../../sharedComponents/input/input.component";
|
|
import {IDeactivateComponent} from "../../utils/can-exit.guard";
|
|
import {FullScreenModalComponent} from "../../utils/modal/full-screen-modal/full-screen-modal.component";
|
|
import {map} from "rxjs/operators";
|
|
import {StakeholderCategory} from "../utils/indicator-utils";
|
|
import {HelperFunctions} from "../../utils/HelperFunctions.class";
|
|
import {properties} from "../../../../environments/environment";
|
|
import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component";
|
|
|
|
declare var UIkit;
|
|
|
|
@Component({
|
|
selector: 'umbrella',
|
|
template: `
|
|
<div page-content>
|
|
<div header class="uk-margin-medium-top">
|
|
<ul #typesGroup *ngIf="umbrella" class="uk-tab uk-margin-xsmall-top" transition-group>
|
|
<ng-container *ngFor="let type of umbrella.types; let i=index">
|
|
<li class="uk-visible-toggle uk-flex" [class.uk-active]="activeIndex === i" transition-group-item>
|
|
<a (click)="chooseType(i)">
|
|
<span class="uk-text-uppercase">{{ stakeholderUtils.entities[type] }}</span>
|
|
</a>
|
|
<div class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left"
|
|
[class.uk-invisible-hover]="activeIndex !== i"
|
|
(click)="$event.stopPropagation();$event.preventDefault()">
|
|
<a class="uk-link-reset uk-flex uk-flex-middle">
|
|
<icon [flex]="true" name="more_vert"></icon>
|
|
</a>
|
|
<div #element
|
|
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: body">
|
|
<ul class="uk-nav uk-dropdown-nav">
|
|
<li *ngIf="i > 0">
|
|
<a (click)="hide(element);moveType(i)">
|
|
<div class="uk-flex uk-flex-middle">
|
|
<icon [flex]="true" name="west" ratio="0.6"></icon>
|
|
<span class="uk-margin-small-left uk-width-expand">Move Left</span>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
<li *ngIf="i < umbrella.types.length - 1">
|
|
<a (click)="hide(element);moveType(i, i + 1)">
|
|
<div class="uk-flex uk-flex-middle">
|
|
<icon [flex]="true" name="east" ratio="0.6"></icon>
|
|
<span class="uk-margin-small-left uk-width-expand">Move Right</span>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
<li *ngIf="i > 0 || i < umbrella.types.length - 1" class="uk-nav-divider"></li>
|
|
<li>
|
|
<a (click)="deleteTypeOpen(i); hide(element)">
|
|
<div class="uk-flex uk-flex-middle">
|
|
<icon [flex]="true" name="delete" ratio="0.6"></icon>
|
|
<span class="uk-margin-small-left uk-width-expand">Remove</span>
|
|
</div>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ng-container>
|
|
<li *ngIf="isCurator && types.length > 0">
|
|
<a (click)="addTypeOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle">
|
|
<icon name="add" [flex]="true"></icon>
|
|
<span class="uk-text-uppercase">Add type</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div actions class="uk-flex uk-flex-right@m uk-flex-center">
|
|
<button *ngIf="activeType" class="uk-button uk-button-primary" (click)="manageStakeholdersOpen()">
|
|
Manage {{ entities.stakeholders }}
|
|
</button>
|
|
</div>
|
|
<div inner class="uk-section">
|
|
<div *ngIf="children == null" class="message">
|
|
<h6>No types yet. Add a type to start.</h6>
|
|
</div>
|
|
<div *ngIf="children != null" uk-height-match="target: .titleContainer; row: false">
|
|
<div uk-height-match="target: .logoContainer; row: false">
|
|
<filtered-stakeholders [remove]="true" (removed)="removeStakeholder($event)"
|
|
[keyword]="keyword" [stakeholders]="children">
|
|
</filtered-stakeholders>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<modal-alert #deleteTypeModal classTitle="uk-background-primary uk-light" (alertOutput)="deleteType()"
|
|
[overflowBody]="false">
|
|
<div [class.uk-invisible]="loading" class="uk-position-relative">
|
|
<div *ngIf="loading">
|
|
<loading class="uk-position-center"></loading>
|
|
</div>
|
|
You are about to remove <span class="uk-text-bold">{{ entities[umbrella.types[index]] }}</span> from the
|
|
umbrella of {{ stakeholder.name }}.
|
|
All the profiles added to this type will be removed too.
|
|
Are you sure you want to proceed?
|
|
</div>
|
|
</modal-alert>
|
|
<modal-alert #addTypeModal classTitle="uk-background-primary uk-light" (alertOutput)="addType()"
|
|
[okDisabled]="updateFb && (updateFb.invalid || updateFb.pristine)">
|
|
<div *ngIf="loading" class="uk-position-relative uk-height-large">
|
|
<loading class="uk-position-center"></loading>
|
|
</div>
|
|
<div *ngIf="updateFb" [class.uk-hidden]="loading"
|
|
class="uk-grid uk-padding uk-padding-remove-horizontal uk-child-width-1-1" [formGroup]="updateFb"
|
|
uk-grid>
|
|
<div input [formInput]="updateFb.get('type')" class="uk-width-1-1"
|
|
placeholder="Type" [options]="types" type="select"></div>
|
|
</div>
|
|
</modal-alert>
|
|
<fs-modal #manageStakeholdersModal>
|
|
<div *ngIf="loading" class="uk-position-relative uk-height-large">
|
|
<loading class="uk-position-center"></loading>
|
|
</div>
|
|
<ng-container *ngIf="!loading && manageStakeholders">
|
|
<div class="uk-section-xsmall">
|
|
<div class="uk-flex uk-flex-center uk-flex-wrap uk-flex-middle uk-flex-right@m">
|
|
<div search-input [(value)]="keyword" [expandable]="true"
|
|
[disabled]="loading" [placeholder]="'Search ' + entities.stakeholders"
|
|
searchInputClass="outer"
|
|
class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1 uk-flex uk-flex-right"></div>
|
|
</div>
|
|
</div>
|
|
<div uk-height-match="target: .titleContainer; row: false">
|
|
<div uk-height-match="target: .logoContainer; row: false">
|
|
<filtered-stakeholders *ngFor="let category of categories" [add]="true"
|
|
(added)="addStakeholder($event)"
|
|
[stakeholderCategory]="category" [remove]="true"
|
|
(removed)="removeStakeholder($event)"
|
|
[keyword]="keyword" [(stakeholders)]="manageStakeholders[category.value]">
|
|
</filtered-stakeholders>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
</fs-modal>
|
|
`
|
|
})
|
|
export class UmbrellaComponent extends StakeholderBaseComponent implements OnInit, IDeactivateComponent {
|
|
public loading: boolean = false;
|
|
public stakeholder: Stakeholder;
|
|
public user: User;
|
|
public types: Option[] = [];
|
|
public manageStakeholders: ManageStakeholders;
|
|
public activeIndex: number = 0;
|
|
public index: number;
|
|
public updateFb: UntypedFormGroup;
|
|
public keyword: string;
|
|
@ViewChild('addTypeModal', {static: true}) addTypeModal: AlertModal;
|
|
@ViewChild('deleteTypeModal', {static: true}) deleteTypeModal: AlertModal;
|
|
@ViewChild('manageStakeholdersModal', {static: true}) manageStakeholdersModal: FullScreenModalComponent;
|
|
@ViewChild('typesGroup') typesGroup: TransitionGroupComponent;
|
|
|
|
constructor(protected _route: ActivatedRoute,
|
|
protected _router: Router,
|
|
protected _title: Title,
|
|
private fb: FormBuilder,
|
|
private userManagementService: UserManagementService,
|
|
private stakeholderService: StakeholderService,
|
|
private cdr: ChangeDetectorRef) {
|
|
super();
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
|
|
this.user = user;
|
|
}));
|
|
this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => {
|
|
if (stakeholder) {
|
|
this.stakeholder = stakeholder;
|
|
if (!this.stakeholder.umbrella) {
|
|
this.navigateToError();
|
|
} else {
|
|
this.umbrella = stakeholder.umbrella;
|
|
}
|
|
this.title = stakeholder.name + " | Manage Umbrella";
|
|
this.setMetadata();
|
|
}
|
|
}));
|
|
}
|
|
|
|
canExit(): boolean {
|
|
this.stakeholderService.setStakeholder(this.stakeholder);
|
|
return true;
|
|
}
|
|
|
|
resetUpdateForm(action: "ADD" | "REMOVE" | "UPDATE" = "ADD", type: StakeholderType = null, child: string = null): void {
|
|
this.updateFb = this.fb.group({
|
|
type: this.fb.control(type, Validators.required),
|
|
action: this.fb.control(action, Validators.required),
|
|
});
|
|
if (child) {
|
|
this.updateFb.addControl("child", this.fb.control(child, Validators.required));
|
|
}
|
|
}
|
|
|
|
resetUpdateFormForReorder(index: number, newIndex: number = index - 1) {
|
|
let types = HelperFunctions.copy(this.umbrella.types);
|
|
HelperFunctions.swap(types, index, newIndex);
|
|
this.updateFb = this.fb.group({
|
|
types: this.fb.control(types, Validators.required),
|
|
action: this.fb.control("UPDATE", Validators.required)
|
|
});
|
|
}
|
|
|
|
addTypeOpen(): void {
|
|
this.resetUpdateForm();
|
|
this.addTypeModal.cancelButtonText = 'Cancel';
|
|
this.addTypeModal.okButtonLeft = false;
|
|
this.addTypeModal.alertMessage = false;
|
|
this.addTypeModal.alertTitle = 'Add a type';
|
|
this.addTypeModal.stayOpen = true;
|
|
this.addTypeModal.open();
|
|
}
|
|
|
|
deleteTypeOpen(index: number): void {
|
|
this.index = index;
|
|
this.resetUpdateForm("REMOVE", this.umbrella.types[this.index]);
|
|
this.deleteTypeModal.cancelButtonText = 'No';
|
|
this.deleteTypeModal.okButtonText = 'Yes';
|
|
this.deleteTypeModal.alertTitle = 'Remove ' + this.umbrella.types[this.index];
|
|
this.deleteTypeModal.stayOpen = true;
|
|
this.deleteTypeModal.open();
|
|
}
|
|
|
|
addType() {
|
|
this.loading = true;
|
|
this.updateUmbrella((umbrella: Umbrella) => {
|
|
this.addTypeModal.cancel();
|
|
this.umbrella = umbrella;
|
|
}, () => {
|
|
this.addTypeModal.cancel();
|
|
});
|
|
}
|
|
|
|
deleteType() {
|
|
this.loading = true;
|
|
this.updateUmbrella((umbrella: Umbrella) => {
|
|
this.deleteTypeModal.cancel();
|
|
this.umbrella = umbrella;
|
|
}, () => {
|
|
this.deleteTypeModal.cancel();
|
|
});
|
|
}
|
|
|
|
addStakeholder(id: string) {
|
|
this.resetUpdateForm('ADD', this.activeType, id);
|
|
this.updateUmbrella((umbrella: Umbrella) => {
|
|
this.umbrella = umbrella;
|
|
});
|
|
}
|
|
|
|
removeStakeholder(id: string) {
|
|
this.resetUpdateForm('REMOVE', this.activeType, id);
|
|
this.updateUmbrella((umbrella: Umbrella) => {
|
|
this.umbrella = umbrella;
|
|
});
|
|
}
|
|
|
|
public moveType(index: number, newIndex: number = index - 1): void {
|
|
this.resetUpdateFormForReorder(index, newIndex);
|
|
this.typesGroup.init();
|
|
this.updateUmbrella( () => {
|
|
HelperFunctions.swap(this.umbrella.types, index, newIndex);
|
|
});
|
|
}
|
|
|
|
public manageStakeholdersOpen() {
|
|
this.manageStakeholdersModal.title = 'Manage ' + this.entities.stakeholders;
|
|
this.manageStakeholdersModal.okButtonText = "Done";
|
|
this.manageStakeholdersModal.okButton = true;
|
|
this.setManageStakeholders();
|
|
this.manageStakeholdersModal.open();
|
|
}
|
|
|
|
setManageStakeholders() {
|
|
this.loading = true;
|
|
this.subscriptions.push(this.stakeholderService.getMyStakeholders(this.properties.monitorServiceAPIURL, this.activeType).pipe(map(manageStakeholders => {
|
|
delete manageStakeholders.templates;
|
|
delete manageStakeholders.umbrella;
|
|
return manageStakeholders;
|
|
})).subscribe(manageStakeholders => {
|
|
this.filterManagedStakeholders(manageStakeholders);
|
|
this.manageStakeholders.standalone.sort(this.sort);
|
|
this.manageStakeholders.dependent.sort(this.sort);
|
|
this.loading = false;
|
|
}));
|
|
}
|
|
|
|
filterManagedStakeholders(manageStakeholders: ManageStakeholders) {
|
|
manageStakeholders.standalone.forEach(stakeholder => {
|
|
stakeholder['added'] = this.children.findIndex(child => child._id === stakeholder._id) !== -1;
|
|
});
|
|
manageStakeholders.dependent.forEach(stakeholder => {
|
|
stakeholder['added'] = this.children.findIndex(child => child._id === stakeholder._id) !== -1;
|
|
});
|
|
this.manageStakeholders = manageStakeholders;
|
|
}
|
|
|
|
sort(a: any, b: any): number {
|
|
if (a['added'] && !b['added']) {
|
|
return -1;
|
|
} else if (!a['added'] && b['added']) {
|
|
return 1;
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
updateUmbrella(successFn: Function = null, errorFn: Function = null): void {
|
|
this.subscriptions.push(this.stakeholderService.updateUmbrella(this.properties.monitorServiceAPIURL, this.stakeholder._id, this.updateFb.getRawValue())
|
|
.subscribe(umbrella => {
|
|
this.loading = false;
|
|
if(!this.activeType) {
|
|
this.activeIndex = 0;
|
|
}
|
|
if(successFn) {
|
|
successFn(umbrella);
|
|
}
|
|
if(this.manageStakeholders) {
|
|
this.filterManagedStakeholders(this.manageStakeholders);
|
|
}
|
|
this.cdr.detectChanges();
|
|
}, error => {
|
|
this.loading = false;
|
|
if(errorFn) {
|
|
errorFn();
|
|
}
|
|
NotificationHandler.rise(error.error.message, 'danger');
|
|
}));
|
|
}
|
|
|
|
hide(element: any) {
|
|
UIkit.dropdown(element).hide();
|
|
}
|
|
|
|
chooseType(index: number) {
|
|
this.activeIndex = index;
|
|
}
|
|
|
|
get umbrella() {
|
|
return this.stakeholder.umbrella;
|
|
}
|
|
|
|
get activeType(): StakeholderType {
|
|
return this.umbrella.types[this.activeIndex];
|
|
}
|
|
|
|
set umbrella(umbrella) {
|
|
this.stakeholder.umbrella = HelperFunctions.copy(umbrella);
|
|
this.types = this.stakeholderUtils.types.filter(type => !umbrella.types.includes(type.value));
|
|
}
|
|
|
|
get isCurator(): boolean {
|
|
return Session.isPortalAdministrator(this.user) || Session.isCurator(this.stakeholder.type, this.user);
|
|
}
|
|
|
|
get children(): Stakeholder[] {
|
|
if (this.activeType) {
|
|
return this.umbrella.children[this.activeType].map(stakeholder => {
|
|
stakeholder['added'] = true;
|
|
return stakeholder;
|
|
});
|
|
}
|
|
return null;
|
|
}
|
|
|
|
get categories(): StakeholderCategory[] {
|
|
return this.stakeholderUtils.stakeholderCategories.filter(category => category.value === 'standalone' || category.value === 'dependent');
|
|
}
|
|
}
|