/* Copyright (c) 2019 AT&T Intellectual Property. # # # # Licensed under the Apache License, Version 2.0 (the "License"); # # you may not use this file except in compliance with the License. # # You may obtain a copy of the License at # # # # http://www.apache.org/licenses/LICENSE-2.0 # # # # Unless required by applicable law or agreed to in writing, software # # distributed under the License is distributed on an "AS IS" BASIS, # # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # # See the License for the specific language governing permissions and # # limitations under the License. # ##############################################################################*/ import { Component, OnInit, OnDestroy, HostListener, ViewChild, ElementRef } from '@angular/core'; import { routerTransition } from 'app/router.animations'; import { ActivatedRoute } from '@angular/router'; import { TestExecutionService } from 'app/shared/services/test-execution.service'; import { TestDefinitionService } from 'app/shared/services/test-definition.service'; import BpmnJS from 'bpmn-js/lib/NavigatedViewer'; import beautify from 'json-beautify'; import { trigger, state, style, transition, animate } from '@angular/animations'; import { interval } from 'rxjs'; import { FileTransferService } from 'app/shared/services/file-transfer.service'; import { Buffer } from 'buffer'; import 'codemirror/mode/javascript/javascript.js'; import { toInteger } from '@ng-bootstrap/ng-bootstrap/util/util'; import { RequiredValidator } from '@angular/forms'; import { UserService } from 'app/shared/services/user.service'; import { ExecuteService } from 'app/shared/services/execute.service'; import { BpmnFactoryService } from 'app/shared/factories/bpmn-factory.service'; import { Bpmn } from 'app/shared/models/bpmn.model'; //import 'datatables.net'; @Component({ selector: 'app-control-panel', templateUrl: './control-panel.component.pug', styleUrls: ['./control-panel.component.scss'], animations: [routerTransition(), trigger('detailExpand', [ state('collapsed', style({ height: '0px', minHeight: '0', display: 'none' })), state('expanded', style({ height: '*' })), transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), ]) ] }) export class ControlPanelComponent implements OnInit, OnDestroy { @ViewChild('canvas-card') canvas: ElementRef; public params; public displayedColumns = ['startTime', 'endTime', 'totalTime']; public dataSource = {}; public instanceDataSource = {}; public data = {}; public testHeads = []; public testResult; public expandedElement; public selectedTestHead; public selectedTestInstance; public objectKeys = Object.keys; private pullData = true; public showFireworks = false; public refreshData = false; public spin = false; public lastVTHResultsLength = 0; // Create an Observable that will publish a value on an interval public refreshCounter = interval(5000); public isResizing = false; public lastDownY; public viewer: Bpmn; public taskLog = ''; public executionJobLog = []; public executionExternalTaskLog = []; public executionVariables = []; public executionJobLogDataSource; public executionExternalTaskLogDataSource; public executionVariablesDataSource; public selectedExecutionJobLog; public selectedExecutionExternalTaskLog; public selectedExecutionVariable; public codeConfig = { mode: "application/json", theme: "eclipse", readonly: true, lineNumbers: true }; public taskLogConfig = { mode: "Shell", theme: "3024-night", readonly: true }; private processInstanceId; public processState; constructor( private route: ActivatedRoute, private executionService: ExecuteService, private user: UserService, private testExecution: TestExecutionService, private fileTransfer: FileTransferService, private bpmnFactory: BpmnFactoryService ) { } ngOnInit() { this.route.queryParams.subscribe(params => { this.params = params; if(params.id){ this.refreshData = false; this.populateData(); this.refreshCounter.subscribe(n => { if (this.pullData){ this.populateData(n + 1); this.updateFlowData(); } }); } }); $('#canvas-card').on('mousedown', (e) => { this.isResizing = true; this.lastDownY = $('#canvas-card').position().top + $('#canvas-card').outerHeight(true); }) $(document).on('mousemove', (e) => { if(!this.isResizing){ return; } var bottom = $('#canvas-card').position().top + $('#canvas-card').outerHeight(true);//$('#canvas-card').height() - (e.clientY - $('#canvas-card').offset().top); if(bottom != this.lastDownY){ this.lastDownY = $('#canvas-card').position().top + $('#canvas-card').outerHeight(true); this.onResize(null); } }).on('mouseup', () => { this.isResizing = false; }) } ngOnDestroy() { this.pullData = false; } refreshAllData() { this.spin = true; this.refreshData = true; this.populateData(); this.updateFlowData(); } populateData(loopNum = 0) { this.testExecution.get(this.params.id).subscribe( data => { console.log(data); let result = JSON.parse(JSON.stringify(data)); this.processInstanceId = result['processInstanceId']; this.calcTime(result); if(result['testInstanceResults']){ this.instanceDataSource = {}; for(var val = 0; val < result['testInstanceResults'].length; val++){ var elem = result['testInstanceResults'][val]; this.calcTime(elem); let exists = false; Object.keys(this.instanceDataSource).forEach((e, val) => { if(e == elem.historicTestInstance._id){ exists = true; return; } }); if(!exists){ this.instanceDataSource[elem.historicTestInstance._id] = [elem]; } else{ var found = false; this.instanceDataSource[elem.historicTestInstance._id].forEach( (value, index) => { if(this.instanceDataSource[elem.historicTestInstance._id][index]._id == elem._id){ this.instanceDataSource[elem.historicTestInstance._id][index] = elem; found = true; } }) if(!found){ this.instanceDataSource[elem.historicTestInstance._id].push(elem); } } if(val == 0){ this.selectTestInstance(elem.historicTestInstance._id); } }; } if (result['testHeadResults']) { for (var i = 0 + this.lastVTHResultsLength; i < result['testHeadResults'].length; i++) { var exists = false; this.testHeads.forEach(elem => { if (elem.testHeadId == result['testHeadResults'][i].testHeadId && elem.bpmnVthTaskId == result['testHeadResults'][i].bpmnVthTaskId) { exists = true; } }); if (!exists) { this.testHeads.push(result['testHeadResults'][i]); this.dataSource[result['testHeadResults'][i].testHeadId + result['testHeadResults'][i].bpmnVthTaskId] = []; } let sDate = new Date(result['testHeadResults'][i].startTime); let eDate = new Date(result['testHeadResults'][i].endTime); let tDate = (eDate.getTime() - sDate.getTime()) / 1000; result['testHeadResults'][i].startTime = sDate.getHours() + ":" + sDate.getMinutes() + ":" + sDate.getSeconds(); // + " " + sDate.getMonth() + "/" + sDate.getDate() + "/" + sDate.getFullYear(); result['testHeadResults'][i].endTime = eDate.getHours() + ":" + eDate.getMinutes() + ":" + eDate.getSeconds(); // + " " + eDate.getMonth() + "/" + eDate.getDate() + "/" + eDate.getFullYear(); result['testHeadResults'][i].totalTime = tDate + " secs"; result['testHeadResults'][i].testHeadRequestResponse = { "testHeadRequest": result['testHeadResults'][i].testHeadRequest, "testHeadResponse": result['testHeadResults'][i].testHeadResponse, "statusCode": result['testHeadResults'][i].statusCode }; //result['testHeadResults'][i].testHeadResponse = beautify(result['testHeadResults'][i].testHeadResponse, null, 2, 50); this.dataSource[result['testHeadResults'][i].testHeadId + result['testHeadResults'][i].bpmnVthTaskId].push(result['testHeadResults'][i]); if (i == 0) { this.selectTestHead(result['testHeadResults'][i].testHeadId + result['testHeadResults'][i].bpmnVthTaskId); } } //keep track of previous results so you don't reload them this.lastVTHResultsLength = result['testHeadResults'].length; this.testResult = Object.assign({}, result); // this.user.get(result['executor']).subscribe(res => { // this.testResult['executor'] = res; // }); // this.spin = false; } //only gets called once if (!this.refreshData && loopNum == 0 && (result['historicTestDefinition'] && result['historicTestDefinition']['bpmnInstances'][0])) { let id = result['historicTestDefinition']['bpmnInstances'][0]['bpmnFileId'] if(!this.viewer){ this.bpmnFactory.setup({ mode: 'viewer', options: { container: '#canvas' }, fileId: id }).then(res => { this.viewer = res; this.updateFlowData(); }); }else{ this.bpmnFactory.getXml({ fileId: id }).then(res => { this.viewer.setBpmnXml(res); this.updateFlowData(); }) } } } ); } updateExecutionData(){ if(this.executionJobLog){ this.executionJobLogDataSource = {}; for(var val = 0; val < this.executionJobLog.length; val++){ var elem = this.executionJobLog[val]; let exists = false; Object.keys(this.executionJobLogDataSource).forEach((e, val) => { if(e == elem.activityId){ exists = true; return; } }); if(!exists){ this.executionJobLogDataSource[elem.activityId] = [elem]; } else{ var found = false; this.executionJobLogDataSource[elem.activityId].forEach( (value, index) => { if(this.executionJobLogDataSource[elem.activityId][index].id == elem.id){ this.executionJobLogDataSource[elem.activityId][index] = elem; found = true; } }) if(!found){ this.executionJobLogDataSource[elem.activityId].push(elem); } } if(val == 0){ this.selectExecutionJobLog(elem.activityId); } }; } if(this.executionExternalTaskLog){ this.executionExternalTaskLogDataSource = {}; for(var val = 0; val < this.executionExternalTaskLog.length; val++){ var elem = this.executionExternalTaskLog[val]; let exists = false; Object.keys(this.executionExternalTaskLogDataSource).forEach((e, val) => { if(e == elem.activityId){ exists = true; return; } }); if(!exists){ this.executionExternalTaskLogDataSource[elem.activityId] = [elem]; } else{ var found = false; this.executionExternalTaskLogDataSource[elem.activityId].forEach( (value, index) => { if(this.executionExternalTaskLogDataSource[elem.activityId][index].id == elem.id){ this.executionExternalTaskLogDataSource[elem.activityId][index] = elem; found = true; } }) if(!found){ this.executionExternalTaskLogDataSource[elem.activityId].push(elem); } } if(val == 0){ this.selectExecutionExternalTaskLog(elem.activityId); } }; } if(this.executionVariables){ this.executionVariablesDataSource = {}; for(var val = 0; val < this.executionVariables.length; val++){ var elem = this.executionVariables[val]; let exists = false; Object.keys(this.executionVariablesDataSource).forEach((e, val) => { if(e == elem.variableName){ exists = true; return; } }); if(!exists){ this.executionVariablesDataSource[elem.variableName] = [elem]; } else{ var found = false; this.executionVariablesDataSource[elem.variableName].forEach( (value, index) => { if(this.executionVariablesDataSource[elem.variableName][index].id == elem.id){ this.executionVariablesDataSource[elem.variableName][index] = elem; found = true; } }) if(!found){ this.executionVariablesDataSource[elem.variableName].push(elem); } } if(val == 0){ this.selectExecutionVariable(elem.variableName); } }; } } calcTime(result) { let tsDate = new Date(result['startTime']); let teDate = new Date(result['endTime']); let ttDate = (teDate.getTime() - tsDate.getTime()) / 1000; result['date'] = tsDate.getMonth() + 1 + "/" + tsDate.getDate() + "/" + tsDate.getFullYear(); result['startTime'] = tsDate.getHours() + ":" + tsDate.getMinutes() + ":" + tsDate.getSeconds(); result['endTime'] = teDate.getHours() + ":" + teDate.getMinutes() + ":" + teDate.getSeconds(); result['totalTime'] = ttDate + ' secs'; } updateFlowData() { console.log(this.processInstanceId); this.testExecution.status(this.processInstanceId).subscribe( result => { if (result) { let data = result['body']; //check process state if (data.historicProcessInstance.state == 'COMPLETED') { this.processState = 'Completed'; this.pullData = false; } else if (data.historicProcessInstance.state == 'ACTIVE') { this.processState = 'Running'; } else { this.processState = 'Failed'; this.pullData = false; } if(data.historicJobLog){ this.executionJobLog = data.historicJobLog; } if(data.historicExternalTaskLog){ this.executionExternalTaskLog = data.historicExternalTaskLog; } if(data.historicVariableInstance){ this.executionVariables = data.historicVariableInstance; } //update execution tabs -- job log, external task log, variables this.updateExecutionData(); //loop through processes to get their info for (let i = 0; i < data.historicActivityInstance.length; i++) { let p = data.historicActivityInstance[i]; let state = null; if (p.startTime && p.endTime && !p.canceled) { // process completed successfully state = 'completed'; } else if (p.startTime && !p.endTime) { // process is still running state = 'running'; } else if (p.canceled) { state = 'failed'; } //get task id //highlight task boxes based on their state this.viewer.getModel().get('canvas').addMarker(p.activityId, 'highlight-task-' + state); } for (let i = 0; i < data.historicIncident.length; i++) { let p = data.historicIncident[i]; if (p.incidentMessage) { this.taskLog += p.activityId + ': ' + p.incidentMessage + '\n'; } this.viewer.getModel().get('canvas').addMarker(p.activityId, 'highlight-task-failed'); } } }, err => { } ); } cancelExecution() { this.executionService.delete(this.testResult._id).subscribe(result => { this.updateFlowData(); }); } expand(element) { if (this.expandedElement == element) this.expandedElement = null; else this.expandedElement = element; } beauty(json) { return beautify(json, null, 2, 50); } @HostListener('window:resize', ['$event']) onResize(event){ // console.log("hi") if(this.viewer) this.viewer.resize(); } json2html(json: any = [{ }], tabs = 0) { var html = ''; var tabHtml = ''; if (typeof json === 'string') { json = JSON.parse(json); } for (let i = 0; i < tabs; i++) { tabHtml += '    '; } for (let key in json) { if (json.hasOwnProperty(key)) { if (typeof json[key] === "object") { html += tabHtml + '' + key + ':
'; if (json.constructor === Array && toInteger(key) > 0) { tabs--; } html += this.json2html(json[key], ++tabs); } else { html += tabHtml + '' + key + ':' + '
'; if (typeof json[key] === 'string') { json[key] = json[key].replace(/\\n/g, '
' + tabHtml); } html += tabHtml + json[key] + '
'; html += '
'; } } } return html; } selectTestHead(key) { this.selectedTestHead = key; } selectTestInstance(key){ this.selectedTestInstance = key; } selectExecutionJobLog(key){ this.selectedExecutionJobLog = key; } selectExecutionExternalTaskLog(key){ this.selectedExecutionExternalTaskLog = key; } selectExecutionVariable(key){ this.selectedExecutionVariable = key; } call() { // } }