ChangeCalendar/frontend/src/ntt-gantt/ntt-gantt.component.ts

853 lines
26 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

import { FilterDialogComponent } from './../app/filter-dialog/filter-dialog.component';
import { filteredData } from './../data';
import { ImplementerDialogComponent } from './../app/implementer-dialog/implementer-dialog.component';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { GanttComponent } from '@syncfusion/ej2-angular-gantt';
import { DataService } from 'src/app/data.service';
import { projectNewData } from 'src/data';
import {FormGroup, FormControl} from '@angular/forms';
import {MatDialog} from '@angular/material/dialog';
import * as $ from 'jquery';
import { StateDialogComponent } from 'src/app/state-dialog/state-dialog.component';
import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarVerticalPosition } from '@angular/material/snack-bar';
@Component({
selector: 'ntt-gantt',
templateUrl: './ntt-gantt.component.html',
styleUrls: ['./ntt-gantt.component.css']
})
export class NttGanttComponent implements OnInit {
@ViewChild('ganttObject')
public ganttDefault!: GanttComponent;
@ViewChild(MatPaginator) paginator: MatPaginator;
public range = new FormGroup({
start: new FormControl<Date | null>(new Date('12/01/2022')),
end: new FormControl<Date | null>(new Date('01/31/2024')),
});
public data: any[] = [];
public allResources: any[] = [];
public resources: any[] = [];
public taskSettings: object = {};
public labelSettings: object = {};
public projectStartDate: Date = new Date('12/01/2022');
public projectEndDate: Date = new Date('01/31/2024');
public resourceFields: object ={};
public editSettings: object = {};
public columns: object[] = [];
public toolbar: any[] = [];
public timelineSettings: object ={};
public rendering: boolean = true;
public blockedTaskIDs : number [] = [8];
public selectionSettings : object = {};
public spin:boolean = true;
public sliceStart: number;
public sliceEnd: number;
public filterSettings: object;
public renderGantt: boolean;
public firstLoad: boolean;
public selectedScalar: string = 'Monat-Woche';
public scalars: string[] = ['Woche-Tag', 'Monat-Woche', 'Jahr-Monat'];
public showDetails: boolean = true;
public panelOpenState:boolean;
public attributes: any[] = [
//{value: 'vertrag', viewValue: 'WI Vertrag'},
{value: 'resourceName', viewValue: 'Name'},
{value: 'status', viewValue: 'Status'},
//{value: 'implementer', viewValue: 'Implementer'},
{value: 'changeid', viewValue: 'Change Id'},
];
public paketTypeList: any[] = [
{name: 'Paket Typ A', checked: false},
{name: 'Paket Typ B', checked: false},
{name: 'Paket Typ C', checked: false},
];
public stateList: any[] = [];
public vertragList: any[] = [
{name: 'Vertrag A', checked: false},
{name: 'Vertrag B', checked: false},
{name: 'Vertrag C', checked: false},
];
public supportGroupList: any[] = [
{name: 'SM ITSM', id: 'SG0001' },
{name: 'Support Group B', id: 'SG0002' },
{name: 'Support Group C', id: 'SG0003' },
];
public selectedSupportGroup: any = this.supportGroupList[0];
public filterStartDate: Date;
public filterEndDate: Date;
public selectedAttribute: string;
public showFilters: boolean = false;
// ["=",">","<","beinhaltet"];
public selectedFilter: string;
public showCriterea: boolean = false;
public criteria: string = '';
public filterEnabled: boolean = false;
public filters:any = null;
public sortEnabled: boolean = false;
public sortedData: any[] = [];
private selectedRescourceIds : any[] = [];
private selectedrowindex: number[] = [];
private selectedrecords: any[] = [];
private selRecs: any[] = [];
public states : any[] = [];
private approvalPending: boolean;
public sort = null;
public oldSort = null;
/**
* The constructor injects required dependencies
* @param dataService injects the dataService for data management and backend communication
* @param matDialog injects the matDialog
*/
constructor(public dataService: DataService, public matDialog : MatDialog, private _snackBar: MatSnackBar ) {
}
/**
* The function ngOnInit sets values which are required for rendering the gantt Chart. Furthermore it trims the resources (Changes Array) and sets the paginator to the first page.
*/
public ngOnInit(): void {
var WebFont = require('webfontloader');
WebFont.load({
google: {
families: [
'Material Icons',
],
},
});
this.renderGantt = false;
this.firstLoad = true;
this.sliceStart = 0;
this.sliceEnd = 20;
// this.dataService.fetchChanges().then((res: any[])=>{
// console.log(res);
// this.allResources = res;
// this.mapTasksToResources(0,20);
// this.range = new FormGroup({
// start: new FormControl<Date | null>(new Date('12/01/'+(new Date().getFullYear()-1))),
// end: new FormControl<Date | null>(new Date('01/31/'+(new Date().getFullYear()+1))),
// });
// this.renderGantt = true;
// });
this.refreshData()
this.states = this.dataService.getStates();
this.dataService.fetchStates().then((res: any [])=>{
this.states = res;
this.stateList = res;
console.log(this.states);
});
this.filterSettings = {
ignoreAccent: true
// columns: [
// { field: 'vertrag', matchCase: false, operator: 'startswith', predicate: 'and', value: 'WV' },
// ]
};
this.taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
endDate: 'EndDate',
duration: 'Duration',
progress: 'Progress',
dependency: 'Predecessor',
resourceInfo: 'resources',
work: 'work',
expandState: 'isExpand',
child: 'subtasks',
isFixed: 'isFixed',
vertrag: 'vertrag'
};
this.resourceFields = {
id: 'resourceId',
name: 'resourceName',
unit: 'Unit',
group: 'resourceGroup',
state: 'state',
stateName: 'stateName',
isRes: 'isRes',
vertrag: 'vertrag',
vertragName: 'vertragName',
supportGroup: 'supportGroup',
supportGroupId: 'supportGroupId',
implementerEdit: 'implementerEdit'
};
this.editSettings = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
allowTaskbarEditing: true,
showDeleteConfirmDialog: true
};
this.selectionSettings = {
mode: 'Row',
type: 'Multiple',
};
this.columns = [
{ field: 'TaskName', headerText: 'Kurzbeschreibung', width: 250 },
{ field: 'stateName', headerText: 'Status', width: 250},
{ field: 'vertragName', headerText: 'Vertrag / Provider Cluster', width: 150 },
{ field: 'supportGroup', headerText: 'Gewählte Support Gruppe' },
{ field: 'StartDate', headerText: 'Geplantes Start-Datum'},
// { field: 'approvalStatus', headerText: 'Active Approval', width: 100 },
// { field: 'supportGroupId' },
//{ field: 'Duration' },
//{ field: 'TaskID', headerText: 'Taks ID', width: 250 },
//{ field: 'work', headerText: 'Work' },
//{ field: 'Progress' },
//{ field: 'resourceGroup', headerText: 'Group' },
];
this.toolbar = ['Cancel'];
this.labelSettings = {
rightLabel: 'resources',
taskLabel: 'TaskName'
};
this.timelineSettings= {
topTier: {
//format: 'YYYY',
unit: 'Month'
},
bottomTier: {
format: 'WW',
unit: 'Week',
count: 1
}
};
this.projectStartDate = this.range.controls.start.value;
this.projectEndDate = this.range.controls.end.value;
}
/**
* The function taskbarEditing catches the corresponding syncfsuions event and cancels the user action if the isFixed flag of a task (Date) is set true
* @param args event arguments from the syncfusion gantt chart
*/
public taskbarEditing(args: any) {
if(args.data.taskData.isFixed !== false ) {
args.cancel = true;
}
}
public renderDetails(){
// console.log(this.showDetails);
if(this.showDetails == false){
this.refreshData();
}else{
this.refreshData();
}
}
public changeScalar(){
if(this.selectedScalar == "Woche-Tag"){
this.timelineSettings= {
topTier: {
//format: 'WW',
unit: 'Week'
},
bottomTier: {
format: 'dd',
unit: 'Day',
count: 1
}
};
}
if(this.selectedScalar == "Monat-Woche"){
this.timelineSettings= {
topTier: {
//format: 'YYYY',
unit: 'Month'
},
bottomTier: {
format: 'WW',
unit: 'Week',
count: 1
}
};
}
if(this.selectedScalar == "Jahr-Monat"){
this.timelineSettings= {
topTier: {
//format: 'YYYY',
unit: 'Year'
},
bottomTier: {
format: 'MM',
unit: 'Month',
count: 1
}
};
}
}
/**
* The function taskbarEdited catches the corresponding syncfsuions event and cancels the user action if the isFixed flag of a task (Date) is set true
* If the isFixed flag is false, it triggers the dataService to update the moved date
* @param args event arguments from the syncfusion gantt chart
*/
public taskbarEdited(args: any){
if(args.data.taskData.isFixed !== false ) {
args.cancel = true;
}else{
const found = this.allResources.find((resource) => {
return resource.resourceId == args.data.taskData.resources[0].resourceId;
});
this.dataService.updateDatePerChange(found);
}
}
/**
* The function queryTaskbarInfo catches the corresponding syncfsuions event and colors the respective diamond depending on the status
* @param args event arguments from the syncfusion gantt chart
*/
public queryTaskbarInfo(args: any) {
if(args.data.taskData.isRes == false){
if(args.data.taskData.TaskID.includes("D2")){
if (args.data.taskData.resources[0].state == 0 ) {
args.milestoneColor = "red";
}
if (args.data.taskData.resources[0].state == 1 ) {
args.milestoneColor = "orange";
}
if (args.data.taskData.resources[0].state == 3 ) {
args.milestoneColor = "yellow";
}
if (args.data.taskData.resources[0].state == 6 ) {
args.milestoneColor = "lightgreen";
}
if (args.data.taskData.resources[0].state >= 10 ) {
args.milestoneColor = "lightgrey";
}
}else{
if (args.data.taskData.TaskID.includes("D1")||args.data.taskData.TaskID.includes("D4")){
if(this.showDetails == false){
args.taskbarElement.innerHTML = "";
}
}
}
}
}
/**
* The function onExpand catches the corresponding syncfsuions event and avoids a chart row from beeing expanded by the user
* @param args event arguments from the syncfusion gantt chart
*/
public onExpand(args: any){
args.cancel = true;
}
/**
* The function actionBegin catches the corresponding syncfsuions event
* @param event event arguments from the syncfusion gantt chart
*/
/**
* The function mapTasksToResources slices the allResources array to the resources array according the actual page conditions maps the actual tasks (Dates) to the actual resources (Changes)
* This function is triggered when a pageEvent is thrown respectively a user changes the page on the paginator
* @param start begin of slice
* @param end end of slice
*/
public mapTasksToResources(start : number, end : number){
this.data = [];
this.resources = this.allResources; //.slice(start, end);
for (const resource of this.resources) {
for (const task of resource.tasks) {
this.data.push(task);
}
}
}
/**
* The function load catches the corresponding syncfsuions event and triggers the loading spinner to start while the gantt chart is refrehshing
* @param args event arguments from the syncfusion gantt chart
*/
public load(args: any) {
this.spin = true;
}
/**
* The function dataBound catches the corresponding syncfsuions event and stops the loading spinner
* @param args event arguments from the syncfusion gantt chart
*/
public dataBound(args: any) {
this.spin = false;
}
/**
* The function created catches the corresponding syncfsuions event and stops the internal loading spinner
* @param args event arguments from the syncfusion gantt chart
*/
public created(args: any) {
this.ganttDefault.hideSpinner();
this.ganttDefault.treeGrid.grid.hideSpinner();
}
/**
* The function onChange catches the corresponding syncfsuions event
* @param args event arguments from the syncfusion gantt chart
*/
public onChange(args: any){
}
/**
* The function handlePageEvent catches the corresponding matpaginator event and slices the gantt chart, that it fits to the actual page
* @param e pageEvent from the matpaginator
*/
public handlePageEvent(e: PageEvent):void {
let start = e.pageSize*e.pageIndex;
let end = start+ e.pageSize;
this.sliceStart = start;
this.sliceEnd = end;
//this.mapTasksToResources(start, end);
//this.quickRefresh();
this.refreshData();
// this.ganttDefault.dataSource = this.data;
// this.ganttDefault.resources = this.resources;
// this.ganttDefault.refresh();
}
/**
* The function startDateChanged catches the corresponding date-range-picker event
* @param startDate new startDate from date-range-picker
*/
public startDateChanged(startDate: any){
}
/**
* The function endDateChanged catches the corresponding date-range-picker event and validates the selected start- and enddate bacause the gantt chart needs a valid Date to be displayed
* @param endDate new endDate from date-range-picker
*/
public endDateChanged(endDate: any){
if(this.range.status == 'VALID' && this.range.controls.start.value && this.range.controls.end.value){ //event for Requesting new Records based on the Dates
}
}
/**
* The function rowSelected catches the corresponding syncfsuions event and checks if all selected resources (changes) have the same status, then it displays the corresponding buttons
* @param args event arguments from the syncfusion gantt chart
*/
public rowSelected(args: any) {
this.approvalPending = false;
this.selectedrowindex = this.ganttDefault.selectionModule.getSelectedRowIndexes(); // get the selected row indexes.
this.selectedrecords = this.ganttDefault.selectionModule.getSelectedRecords(); // get the selected records.
this.selRecs=[];
if(this.selectedrowindex.length>this.resources.length-1){
for (const record of this.selectedrecords) {
if(record.taskData.isRes == true){
this.selRecs.push(record);
}
}
}else{
this.selRecs = this.selectedrecords;
}
let allStates: boolean = true;
this.selectedRescourceIds = [];
for (const change of this.selRecs) {
if(change.taskData.approvalStatus == 1){
this.approvalPending = true;
}
if(change.taskData.state == this.selRecs[0].taskData.state){
if(allStates){
allStates = true;
}
this.selectedRescourceIds.push(change.taskData.resourceId);
}else{
allStates = false;
}
}
if(allStates){
if(this.approvalPending == true){
this.toolbar = ['Cancel',{text: "Genehmigen", id: "7"},{text: "Ablehnen", id: "8"}];
}
else{
if(this.selRecs[0].taskData.state > 0 &&this.selRecs[0].taskData.state < 4){
this.toolbar = ['Cancel',{text: "Statusübergang", id: "6"} ,{text: "Implementer eintragen", id: "10"}];
}else{
this.toolbar = ['Cancel',{text: "Statusübergang", id: "6"}];
if(this.selRecs[0].taskData.state == 0){
this.toolbar = [{text: "stornieren", id: "11"},{text: "Statusübergang", id: "6"} ,{text: "Implementer eintragen", id: "10"}];
}
}
}
}else{
this.toolbar = ['Cancel'];
}
this.approvalPending = false;
this.selRecs = [];
this.selectedrecords = [];
this.selectedrowindex = [];
}
/**
* The function rowDeselected catches the corresponding syncfsuions event
* When a line is deselected, it is checked if all resource states are equal after deselecting a resource, if they are equal then the respective buttons are displayed
* @param args event arguments from the syncfusion gantt chart
*/
public rowDeselected(args: any){
this.selectedRescourceIds.forEach((element,index)=>{
if(element == args.data.taskData.resourceId) delete this.selectedRescourceIds[index]; //TODO: auf memoryLeak prüfen
});
this.selectedrowindex= this.ganttDefault.selectionModule.getSelectedRowIndexes(); // get the selected row indexes.
this.selectedrecords= this.ganttDefault.selectionModule.getSelectedRecords(); // get the selected records.
this.selRecs = [];
if(this.selectedrowindex.length>this.resources.length-1){
for (const record of this.selectedrecords) {
if(record.taskData.isRes == true){
this.selRecs.push(record);
}
}
}else{
this.selRecs = this.selectedrecords;
}
let allStates: boolean = true;
this.selectedRescourceIds = [];
for (const change of this.selRecs) {
if(change.taskData.state == this.selRecs[0].taskData.state){
if(change.taskData.approvalStatus == 1){
this.approvalPending = true;
}
if(allStates){
allStates = true;
}
this.selectedRescourceIds.push(change.taskData.resourceId);
}else{
allStates = false;
}
}
if(allStates){
if(this.approvalPending == true){
this.toolbar = ['Cancel',{text: "Genehmigen", id: "7"},{text: "Ablehnen", id: "8"}];
}
else{
if(this.selRecs[0].taskData.state > 0 &&this.selRecs[0].taskData.state < 4){
this.toolbar = ['Cancel',{text: "Statusübergang", id: "6"} ,{text: "Implementer eintragen", id: "10"}];
}else{
this.toolbar = ['Cancel',{text: "Statusübergang", id: "6"}];
if(this.selRecs[0].taskData.state == 0){
this.toolbar = [{text: "stornieren", id: "11"},{text: "Statusübergang", id: "6"} ,{text: "Implementer eintragen", id: "10"}];
}
}
}
}else{
this.toolbar = ['Cancel'];
}
this.selRecs = [];
this.selectedrecords = [];
this.selectedrowindex = [];
this.approvalPending = false;
}
/**
* The function toolbarBtnClicked catches the corresponding syncfsuions event and executes the button logic when a button is clicked
* @param args
*/
public toolbarBtnClicked(args :any){
if(args.item.text === "Statusübergang"){
let data = {changes: [], states: this.states};
for (const selectedRescourceId of this.selectedRescourceIds) {
for (const iterator of this.resources) {
if(iterator.resourceId == selectedRescourceId){
data.changes.push({resourceId: iterator.resourceId, changeNr: iterator.changeNr, currentState: iterator.state});
}
}
}
let dialogRef = StateDialogComponent;
this.matDialog.open(dialogRef,
{
data : data,
}).afterClosed().subscribe((res)=>{
if(res=="Success"){
this.refreshData();
}
});
}
if(args.item.text === "Implementer eintragen"){
let data = {changes: []};
for (const selectedRescourceId of this.selectedRescourceIds) {
for (const change of this.resources) {
if(change.resourceId == selectedRescourceId){
// console.log(change);
data.changes.push({resourceId: change.resourceId, pkgId: change.changeNr, supportGroupId: change.supportGroupId});
}
}
}
this.matDialog.open(ImplementerDialogComponent,
{
data : data,
});
}
if(args.item.text === "Genehmigen"){
for (const selectedRescourceId of this.selectedRescourceIds) {
for (const change of this.resources) {
if(change.resourceId == selectedRescourceId){
this.dataService.updateApproval(change, 1);
}
}
}
//this.ganttDefault.refresh();
}
if(args.item.text === "ablehnen"){
for (const selectedRescourceId of this.selectedRescourceIds) {
for (const change of this.resources) {
if(change.resourceId == selectedRescourceId){
this.dataService.updateApproval(change, 2);
}
}
}
//this.ganttDefault.refresh();
}
if(args.item.text === "stornieren"){
for (const selectedRescourceId of this.selectedRescourceIds) {
for (const change of this.resources) {
if(change.resourceId == selectedRescourceId){
this.dataService.updateApproval(change, 3);
}
}
}
//this.ganttDefault.refresh();
}
}
quickRefresh(){
this.renderGantt = false;
let newData = [];
for (const dat of this.data) {
newData.push(dat);
}
this.data = newData;
this.renderGantt = true;
}
refreshData(){
this.renderGantt = false;
this.dataService.fetchChanges(this.mapRequestJSON()).then((res: any[])=>{
this.allResources = res;
this.mapTasksToResources(this.sliceStart,this.sliceEnd);
// console.log(this.allResources)
this.renderGantt = true;
});
// this.mapTasksToResources(this.sliceStart, this.sliceEnd);
// this.data = [];
// this.resources = this.allResources.slice(this.sliceStart, this.sliceEnd);
// for (const resource of this.resources) {
// for (const task of resource.tasks) {
// this.data.push(task);
// }
// }
}
mapRequestJSON(){
let request =
{
'sliceStart': this.sliceStart,
'sliceEnd': this.sliceEnd,
filter: this.filterEnabled ? this.filters : null,
sort: this.sortEnabled ? this.sort : {
'column': 'ChangeNr',
        'mode': 'asc'
},
}
return request;
}
private oldFilters:{};
applyFilter(){
if(this.filterEnabled){
this.oldFilters = this.filters
this.filters = null;
this.refreshData();
}else{
this.filters = this.oldFilters;
this.refreshData();
}
}
openFilterDialog(){
let dialogRef = FilterDialogComponent;
this.matDialog.open(dialogRef,
{
data : [],
height: '70%',
width: '80%'
}).afterClosed().subscribe((res)=>{
if(res){
// console.log(res);
this.filters = res;
this.filterEnabled = true;
this.refreshData();
}
});
}
public buildFilterObject(){
this.filterEnabled = true;
let filter = []
let critPaketTypeFilter = [];
let critStateTypeFilter = [];
let critVertragTypeFilter = [];
let critSupportGroupfilter = {};
let critDateFilter = {};
let critTextFilter = {};
for (const paketType of this.paketTypeList) {
if(paketType.checked == true){
critPaketTypeFilter.push(paketType.name);
}
}
if(critPaketTypeFilter.length > 0){
filter.push({
"column": "paketType",
       "filter": "equals",
       "criteria": critPaketTypeFilter
});
}
for (const state of this.stateList) {
if(state.checked == true){
critStateTypeFilter.push(state.stateNameEN);
}
}
if(critStateTypeFilter.length > 0){
filter.push({
"column": "State",
       "filter": "equals",
       "criteria": critStateTypeFilter
});
}
for (const vertrag of this.vertragList) {
if(vertrag.checked == true){
critVertragTypeFilter.push(vertrag.name);
}
}
if(critVertragTypeFilter.length > 0){
filter.push({
"column": "Contract",
      "filter": "equals",
      "criteria": critVertragTypeFilter
});
}
// filter.push({
// "column": "supportGroup",
//       "filter": "equals",
//       "criteria": [this.selectedSupportGroup.id]
// });
if(this.filterStartDate != null && this.filterEndDate != null){
filter.push({
"column": "D2",
      "filter": "dateRange",
      "criteria": [this.filterStartDate, this.filterEndDate]
});
}
if(this.criteria != null && this.criteria != ""){
filter.push({
"column": "ResourceName",
      "filter": "contains",
      "criteria": [this.criteria]
});
}
this.filters = filter;
this.refreshData();
}
public actionBegin(args: any) {
// console.log(args); //custom Action
if(args.requestType=='sorting'){
let colName = "";
let mode = "asc";
args.cancel = true;
switch (args.columnName) {
case 'TaskName':
colName = 'ResourceName';
break;
case 'stateName':
colName = 'State';
break;
case 'supportGroup':
colName = 'SupportGroup';
break;
case 'approvalStatus':
colName = 'ApprovalStatus';
break;
default:
break;
}
if(colName != ''){
this.sortEnabled = true;
if(this.oldSort != null && this.oldSort.column == this.sort.column){
mode = 'dsc'
}
this.oldSort = this.sort;
this.sort = {
'column': colName,
'mode': mode
}
this.refreshData();
}
}
}
}