2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2019 AT&T Intellectual Property. All rights reserved.
6 * ===================================================================
8 * Unless otherwise specified, all software contained herein is licensed
9 * under the Apache License, Version 2.0 (the "License");
10 * you may not use this software except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * Unless otherwise specified, all documentation contained herein is licensed
22 * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
23 * you may not use this documentation except in compliance with the License.
24 * You may obtain a copy of the License at
26 * https://creativecommons.org/licenses/by/4.0/
28 * Unless required by applicable law or agreed to in writing, documentation
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 * ============LICENSE_END============================================
38 import { Component, OnInit, Input } from '@angular/core';
39 import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
40 import { SchedulerService } from 'src/app/shared/services/scheduler/scheduler.service';
41 import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component';
42 import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component';
43 import { UserProfileService } from 'src/app/shared/services';
44 import { analyzeAndValidateNgModules } from '@angular/compiler';
47 selector: 'app-scheduler',
48 templateUrl: './scheduler.component.html',
49 styleUrls: ['./scheduler.component.scss']
51 export class SchedulerComponent implements OnInit {
54 /*Assign the data that's passed to scheduler UI*/
55 hasParentData: boolean = true;
59 @Input() payload: any;
62 { id: 'now', value: 'true', labelValue: 'Now' },
63 { id: 'range', value: 'false', labelValue: 'Range' }
66 range = this.ranges[0].labelValue;
76 changeManagement = {};
79 checkboxSelection : 'false',
95 approvalSubmitStatus : '',
96 approvalRejectStatus : '',
107 schedulingInfo: null,
122 durationEmpty: boolean = false;
123 concurrencyLimitEmpty: boolean = false;
124 fallBackDurationEmpty: boolean = false;
125 fromDateEmpty: boolean = false;
126 toDateEmpty: boolean = false;
128 /*interval values for getting time slots*/
129 hasvaluereturnd: boolean = true;
130 hasthresholdreached: boolean = false;
131 thresholdvalue =10; // interval threshold value
132 selectedTimeUint: any;
133 showSpinner: boolean = false;
135 fromDateGreater: any;
143 constructor(public schedulerService : SchedulerService, public userProfileService: UserProfileService, public activeModal: NgbActiveModal,
144 public ngbModal: NgbModal) { }
147 this.tomorrow = new Date();
148 this.tomorrow.setDate(this.tomorrow.getDate() + 1);
149 this.minDate = this.tomorrow.toISOString().substring(0, 10);
153 /***** Functions for modal popup ******/
155 if( this.schedulerForm.checkboxSelection=="true"){
156 this.schedulerForm.fromDate='';
157 this.schedulerForm.toDate=''
161 /*Dropdown update: everytime values in dropdown chagnes, update the selected value*/
162 onChangeUpdatePolicyName(newVal, oldVal){
163 for (var i = 0; i < this.policys.length; i++){
164 if (this.policys[i].policyName == newVal) {
165 this.selectedPolicy = this.policys[i];
170 onChangeUpdateTimeUnit(newVal, oldVal){
171 for (var i = 0; i < this.timeUnit.length; i++){
172 if (this.timeUnit[i].text == newVal){
173 this.selectedTimeUint = this.timeUnit[i];
179 * This function is to validate and check if the input is a valid date.
180 * There are two checkers in this function:
181 * Check 1: the input is a valid date object,return true, return false otherwise.
182 * Check 2: check if the input has the format of MM/DD/YYYY or M/D/YYYY and is a valid date value.
186 isDateValid(dateInput){
187 /*Check 1: see if the input is able to convert into date object*/
188 if ( Object.prototype.toString.call(dateInput) === "[object Date]" )
190 /*Check 2: see if the input is the date format MM/DD/YYYY */
191 var isDateStrFormat = false;
193 /*check the format of MM/DD/YYYY or M/D/YYYY */
194 let startDateformat = dateInput.split('/');
195 if (startDateformat.length != 3)
197 let day = startDateformat[1];
198 let month = parseInt(startDateformat[0])-1;
199 let year = startDateformat[2];
200 if (year.length != 4)
202 /*check the input value and see if it's a valid date*/
203 let composedDate = new Date(year, month, day);
204 if(composedDate.getDate() == day && composedDate.getMonth() == month && composedDate.getFullYear() == year)
205 isDateStrFormat = true
207 isDateStrFormat =false;
211 return isDateStrFormat;
215 * This function is to check whether the input date is greater than current date or not.
219 isStartDateValidFromToday(date){
220 if(!this.isDateValid(date))
222 let startDate = new Date(date);
223 let currentDate = new Date();
224 if(startDate<=currentDate)
231 * This function is to check whether the input to date is greater than input from date.
232 * @param fromDate , toDate
235 isToDateGreaterFromDate(fromDate,toDate){
236 if(!this.isDateValid(fromDate) || !this.isDateValid(toDate))
238 var fromDateObj = new Date(fromDate);
239 var toDateObj = new Date(toDate);
240 if(toDateObj<=fromDateObj)
246 * This function is to get error message from the input json response object.
247 * @param response , method
251 parseErrorMsg(response, method){
255 var entityJson = JSON.parse(response.entity);
257 errorMsg = entityJson.requestError.text;
260 console.log('SchedulerCtrl::' + method +' error: ' + err);
266 /***** Scheduler UI functions *****/
268 /* This function is to send scheduler task approval to scheduler microservice. */
271 this.showSpinner =true;
272 let approvalDateTime = new Date(this.timeSlots[0].startTime);
273 this.schedulingInfo={
274 scheduleId: this.schedulerID,
275 approvalDateTime:approvalDateTime.toISOString(),
276 approvalUserId:this.orgUserId,
277 approvalStatus:this.schedulerObjConst.approvalSubmitStatus,
278 approvalType: this.schedulerObjConst.approvalType
280 let approvalObj= JSON.stringify(this.schedulingInfo)
282 this.schedulerService.postSubmitForApprovedTimeslots(approvalObj)
283 .subscribe( _data => {
284 let response = _data;
285 if(response.status>=200 && response.status<=204){
286 this.openConfirmationModal("Successfully Sent for Approval",'');
288 var errorMsg = this.parseErrorMsg(response, 'postSubmitForApprovedTimeslots');
289 this.openConfirmationModal("Failed to Send for Approval ", errorMsg);
291 this.showSpinner = false;
293 console.log('SchedulerCtrl::postSubmitForApprovedTimeslots error: ' + error);
296 errorMsg = this.parseErrorMsg(error.data, 'postSubmitForApprovedTimeslots');
300 this.openConfirmationModal("There was a problem sending Schedule request.", errorMsg);
301 this.showSpinner = false;
305 /* This function is to send scheduler task rejection to scheduler microservice. */
308 this.showSpinner =true;
309 let approvalDateTime = new Date(this.timeSlots[0].startTime);
310 this.schedulingInfo={
311 scheduleId: this.schedulerID,
312 approvalDateTime:approvalDateTime.toISOString(),
313 approvalUserId: this.orgUserId,
314 approvalStatus: this.schedulerObjConst.approvalRejectStatus,
315 approvalType: this.schedulerObjConst.approvalType
317 let approvalObj= JSON.stringify(this.schedulingInfo);
318 this.schedulerService.postSubmitForApprovedTimeslots(approvalObj)
319 .subscribe( _data => {
320 let response = _data;
321 if(response.status>=200 && response.status<=299){
322 this.openConfirmationModal("Successfully Sent for Reject",'');
324 var errorMsg = this.parseErrorMsg(response, 'postSubmitForApprovedTimeslots');
325 this.openConfirmationModal("Failed to Send for Approval ", errorMsg);
327 this.showSpinner = false;
329 console.log('SchedulerCtrl::postSubmitForApprovedTimeslots error: ' + error);
332 errorMsg = this.parseErrorMsg(error.data, 'postSubmitForApprovedTimeslots');
336 this.openConfirmationModal("There was a problem rejecting Schedule request. .", errorMsg);
337 this.showSpinner = false;
341 /* This function is to send policy config and receive scheduler Id. */
345 this.timeSlots.length=0;
346 this.schedulerObj.userId = this.orgUserId;
347 this.schedulerObj.domainData[0].WorkflowName= this.vnfObject.workflow;
348 this.schedulerObj.schedulingInfo.normalDurationInSeconds= this.convertToSecs(this.schedulerForm.duration);
349 this.schedulerObj.schedulingInfo.additionalDurationInSeconds= this.convertToSecs(this.schedulerForm.fallbackDuration);
350 this.schedulerObj.schedulingInfo.concurrencyLimit=parseInt(this.schedulerForm.concurrencyLimit);
351 this.schedulerObj.schedulingInfo['vnfDetails'][0].groupId=this.schedulerObjConst.groupId;
352 this.schedulerObj.schedulingInfo['vnfDetails'][0].node = this.getVnfData(this.vnfObject.vnfNames);
354 for(var i=0;i<this.policys.length;i++){
355 if(this.policys[i].policyName == this.schedulerForm.policyName){
357 var config = this.policys[i].config;
358 var configJson = JSON.parse(config);
359 this.selectedPolicy.policyConfig = configJson.policyName;
361 this.openConfirmationModal("There was a problem setting Policy config. Please try again later.", err);
368 this.schedulerObj.schedulingInfo.policyId = this.selectedPolicy.policyConfig;
370 startTime: new Date(this.schedulerForm.fromDate),
371 endTime: new Date(this.schedulerForm.toDate)
372 //startTime: $filter('date')(new Date(this.schedulerForm.fromDate), "yyyy-MM-ddTHH:mmZ", "UTC"),
373 //endTime: $filter('date')(new Date(this.schedulerForm.toDate), "yyyy-MM-ddTHH:mmZ", "UTC")
375 this.schedulerObj.schedulingInfo['vnfDetails'][0].changeWindow=changeWindow;
376 if(this.schedulerForm.checkboxSelection=="true"){//When Scheduled now we remove the changeWindow
377 delete this.schedulerObj.schedulingInfo['vnfDetails'][0].changeWindow;
379 let requestScheduler= JSON.stringify(this.schedulerObj)
380 this.showSpinner = true;
381 this.schedulerService.getStatusSchedulerId(requestScheduler)
382 .subscribe( _data => {
383 let response = _data;
385 if(response && response.entity!=null){
386 this.openConfirmationModal("There was a problem retrieving scheduler ID. Please try again later. ",'');
388 if(response && response.uuid){
389 this.schedulerID = response.uuid;
390 let scheduledID= JSON.stringify({scheduleId:this.schedulerID});
391 this.seviceCallToGetTimeSlots();
393 this.openConfirmationModal("There was a problem retrieving scheduler ID. Please try again later ", errorMsg);
396 this.showSpinner = false;
398 this.showSpinner = false;
399 console.log('SchedulerCtrl::getStatusSchedulerId error: ' + error);
402 errorMsg = this.parseErrorMsg(error.data, 'postSubmitForApprovedTimeslots');
405 this.openConfirmationModal("There was a problem retrieving scheduler ID. Please try again later.", errorMsg);
409 seviceCallToGetTimeSlots(){
410 this.showSpinner = true;
411 this.schedulerService.getTimeslotsForScheduler(this.schedulerID)
412 .subscribe( _data => {
413 let response = _data;
414 if(this.schedulerForm.checkboxSelection=="false"){
415 if(response.entity && JSON.parse(response.entity).schedule){ //received the timeslots
416 let entityJson = JSON.parse(response.entity);
417 let scheduleColl=JSON.parse(entityJson.schedule);
418 if(scheduleColl.length>0){
419 this.timeSlots =scheduleColl;
420 let hasvaluereturnd = false;
421 this.showSpinner = false;
423 this.openConfirmationModal(entityJson.scheduleId +" Successfully Returned TimeSlots.",'');
425 this.openConfirmationModal("No time slot available",'');
428 if(this.timeSlots.length==0 && this.hasthresholdreached==false){
429 let polltime = this.schedulerObjConst.getTimeslotRate*1000;
430 let pollpromise= this.poll(polltime, function () {
431 if(this.timeSlots.length==0){
432 this.hasvaluereturnd = true;
433 this.seviceCallToGetTimeSlots()
435 this.hasvaluereturnd = false;
438 if(this.showSpinner === true){
439 this.showSpinner = false;
440 this.hasthresholdreached = false;
441 this.openConfirmationModal("Failed to get time slot - Timeout error. Please try again later",'');
447 this.showSpinner = false;
448 if(this.schedulerForm.checkboxSelection=="false"){
449 this.openConfirmationModal("Schedule ID :" + response.entity.scheduleId +" is ready to schedule.",'');
451 var entityObj = JSON.parse(response.entity);
452 this.openConfirmationModal("ID :" + entityObj.scheduleId +" is successfully sent for Approval",'');
457 this.showSpinner = false;
458 console.log('SchedulerCtrl::seviceCallToGetTimeSlots error: ' + error);
459 this.openConfirmationModal("There was a problem retrieving time slows. Please try again later.", '');
465 this.schedulerService.getPolicyInfo()
466 .subscribe( _data => {
468 if(res==null || res=='' || res.status==null || !(res.status>=200 && res.status<=299)){
469 console.log('SchedulerWidgetCtrl::getPolicyInfo caught error', res);
470 var errorMsg = this.parseErrorMsg(res, 'getPolicy');
471 this.openConfirmationModal("There was a problem retrieving ploicy. Please try again later. ", errorMsg);
473 this.policys = res.entity;
476 console.log('SchedulerCtrl::getStatusSchedulerId error: ' + error);
480 removeXMLExtension(str:any){
481 return str.replace(".xml","");
486 if(this.formValidation()){
487 this.sendSchedulerReq();
491 extractChangeManagementCallbackDataStr(changeManagement) {
492 console.log(changeManagement);
497 result.requestType = changeManagement.workflow;
498 var workflowType = changeManagement.workflow;
499 result.requestDetails = [];
500 changeManagement.vnfNames.forEach(function (vnf: any) {
503 var requestInfoData ={};
504 var requestParametersData ={
507 if (vnf.availableVersions && vnf.availableVersions.length!=0){
510 source: vnf.availableVersions[0].requestInfo.source,
511 suppressRollback: vnf.availableVersions[0].requestInfo.suppressRollback,
512 requestorId: vnf.availableVersions[0].requestInfo.requestorId
515 if(workflowType=='Update'){
516 requestParametersData = {
517 usePreload: vnf.availableVersions[0].requestParameters.usePreload
519 }else if(workflowType=="Replace"){
520 requestParametersData = {
521 rebuildVolumeGroups: vnf.availableVersions[0].requestParameters.usePreload
523 }else if(workflowType=="VNF In Place Software Update"){
525 'existing_software_version':changeManagement.existingSoftwareVersion,
526 'new_software_version':changeManagement.newSoftwareVersion,
527 'operations_timeout':changeManagement.operationTimeout
529 requestParametersData = {
530 payload: JSON.stringify(payloadObj)
532 }else if(workflowType=="VNF Config Update"){
533 requestParametersData = {
534 payload: changeManagement.configUpdateFile
537 }else if(workflowType=="VNF In Place Software Update"){
539 'existing_software_version':changeManagement.existingSoftwareVersion,
540 'new_software_version':changeManagement.newSoftwareVersion,
541 'operations_timeout':changeManagement.operationTimeout
543 requestParametersData = {
544 payload: JSON.stringify(payloadObj)
546 }else if(workflowType=="VNF Config Update"){
547 requestParametersData = {
548 payload: changeManagement.configUpdateFile
552 if(changeManagement.testApi){
553 requestParametersData['testApi'] = changeManagement.testApi;
560 vnfInstanceId: vnf.id,
563 modelInvariantId: vnf.properties['model-invariant-id'],
564 modelVersionId: vnf.modelVersionId,
565 modelName: vnf.properties['vnf-name'],
566 modelVersion: vnf.version,
567 modelCustomizationName: vnf.properties['model-customization-name'],
568 modelCustomizationId: vnf.properties['model-customization-id']
570 cloudConfiguration: vnf.cloudConfiguration,
571 requestInfo: requestInfoData,
572 relatedInstanceList: [],
573 requestParameters:requestParametersData
576 var serviceInstanceId = '';
577 vnf['service-instance-node'].forEach( function (instanceNode:any) {
578 if(instanceNode['node-type'] === 'service-instance'){
579 serviceInstanceId = instanceNode.properties['service-instance-id'];
583 if (vnf.availableVersions && vnf.availableVersions.length!=0){
584 vnf.availableVersions[0].relatedInstanceList.forEach( function (related:any) {
585 var rel = related.relatedInstance;
586 var relatedInstance = {
587 instanceId: serviceInstanceId,
589 modelType: rel.modelInfo.modelType,
590 modelInvariantId: rel.modelInfo.modelInvariantId,
591 modelVersionId: rel.modelInfo.modelVersionId,
592 modelName: rel.modelInfo.modelName,
593 modelVersion: rel.modelInfo.modelVersion,
594 modelCustomizationName: rel.modelInfo.modelCustomizationName,
595 modelCustomizationId: rel.modelInfo.modelCustomizationId
598 if (rel.vnfInstanceId)
599 relatedInstance.instanceId = rel.vnfInstanceId;
601 data.relatedInstanceList.push({relatedInstance: relatedInstance});
605 console.log('SchedulerCtrl::extractChangeManagementCallbackDataStr error: ' + err);
608 result.requestDetails.push(data);
610 return JSON.stringify(result);
613 constructScheduleInfo(){
614 let callbackData = this.extractChangeManagementCallbackDataStr(this.vnfObject);
615 this.schedulerObj = {
616 domain: this.schedulerObjConst.domain,
618 scheduleName: this.schedulerObjConst.scheduleName,
621 'WorkflowName': this.schedulerObjConst.WorkflowName,
622 'CallbackUrl': this.schedulerObjConst.CallbackUrl,
623 'CallbackData': callbackData
626 normalDurationInSeconds: '',
627 additionalDurationInSeconds: '',
628 concurrencyLimit: '',
645 this.durationEmpty=false;
646 this.concurrencyLimitEmpty = false;
647 this.fallBackDurationEmpty=false;
648 this.fromDateGreater=false;
649 this.fromDateEmpty=false;
650 this.toDateEmpty=false;
651 if(this.schedulerForm.duration=='')
652 this.durationEmpty=true;
653 if(this.schedulerForm.fallbackDuration=='')
654 this.fallBackDurationEmpty=true;
655 if(this.schedulerForm.concurrencyLimit=='')
656 this.concurrencyLimitEmpty = true;
657 if(!(this.schedulerForm.fromDate instanceof Date))
658 this.fromDateEmpty=true;
659 if(!(this.schedulerForm.toDate instanceof Date ))
660 this.toDateEmpty=true;
661 var fromDateObj = new Date(this.schedulerForm.fromDate);
662 var toDateObj = new Date(this.schedulerForm.toDate);
663 if(fromDateObj>toDateObj)
664 this.fromDateGreater = true;
665 if(this.durationEmpty|| this.fallBackDurationEmpty || this.concurrencyLimitEmpty || ((this.fromDateEmpty ||
666 this.toDateEmpty) && this.schedulerForm.checkboxSelection=='false' ) ||this.fromDateGreater)
668 if(this.schedulerForm.checkboxSelection == 'false' && (!this.isDateValid(this.schedulerForm.toDate)
669 || !this.isDateValid(this.schedulerForm.fromDate)))
671 if(this.selectedPolicy.policyName=='' || this.selectedPolicy.policyName=='Select Policy'){
672 this.openConfirmationModal("Policy is required", '');
678 /*************utility functions**************/
680 convertToSecs(number){
681 this.selectedTimeUint = this.schedulerForm.durationType;
683 if(this.selectedTimeUint.text === 'HOURS'){
684 totalSecs=number * 3600;
685 } else if(this.selectedOption === 'MINUTES') {
686 totalSecs=number * 60;
693 poll(interval, callback) {
694 return setTimeout(function () {
695 if (this.hasvaluereturnd) //check flag before start new call
696 callback(this.hasvaluereturnd);
697 this.thresholdvalue = this.thresholdvalue - 1; //Decrease threshold value
698 if (this.thresholdvalue == 0)
699 this.stopPoll(); // Stop $interval if it reaches to threshold
704 //this.interval.cancel(pollpromise);
705 this.thresholdvalue = 0; //reset all flags.
706 this.hasvaluereturnd = false;
707 this.hasthresholdreached=true;
708 this.showSpinner = false;
713 for(var i=0;i<arrColl.length;i++)
714 vnfcolletion.push(arrColl[i].name);
718 getScheduleConstant(){
719 this.schedulerService.getSchedulerConstants()
720 .subscribe( _data => {
722 if(res==null || res=='' || res.status==null || res.status!="OK"){
723 console.log('SchedulerWidgetCtrl::getSchedulerConstants caught error', res);
724 this.openConfirmationModal('There is a problem about the Scheduler UI. Please try again later.', '');
726 let response = res.response;
727 this.schedulerObjConst= {
728 domain: response.domainName,
729 scheduleName : response.scheduleName,
730 WorkflowName : response.workflowName,
731 CallbackUrl : response.callbackUrl,
732 approvalType : response.approvalType,
733 approvalSubmitStatus : response.approvalSubmitStatus,
734 approvalRejectStatus : response.approvalRejectStatus,
735 getTimeslotRate : response.intervalRate,
736 policyName : response.policyName,
737 groupId : response.groupId
739 this.constructScheduleInfo();
743 console.log('SchedulerCtrl::getStatusSchedulerId error: ' + error);
747 /*This function is to get the current logged in user id*/
749 this.showSpinner = true;
750 this.userProfileService.getUserProfile()
751 .subscribe( _data => {
753 this.orgUserId = res['orgUserId'];
754 this.showSpinner = false;
756 this.showSpinner = false;
757 console.log('SchedulerCtrl::getStatusSchedulerId error: ' + error);
762 this.showSpinner = false;
763 this.selectedTimeUint=this.timeUnit[0].text;
764 this.vnfObject = this.payload['widgetData'];
766 this.getScheduleConstant();
769 openConfirmationModal(_title: string, _message: string) {
770 const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent);
771 modalInfoRef.componentInstance.title = _title;
772 modalInfoRef.componentInstance.message = _message;
775 openInformationModal(_title: string, _message: string){
776 const modalInfoRef = this.ngbModal.open(InformationModalComponent);
777 modalInfoRef.componentInstance.title = _title;
778 modalInfoRef.componentInstance.message = _message;