Updated Sparky to add ECOMP functionality Browse, Specialized Search, BYOQ, and the...
[aai/sparky-fe.git] / src / app / model / modelSearch / Model.jsx
1 /*
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *       http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 import React, { Component } from 'react';
22 import { connect } from 'react-redux';
23 import Filter from 'generic-components/filter/Filter.jsx';
24 import OutputToggle from 'generic-components/OutputToggle.jsx';
25 import {ExportExcel} from 'utils/ExportExcel.js';
26 import commonApi from 'utils/CommonAPIService.js';
27 import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
28 import Spinner from 'utils/SpinnerContainer.jsx';
29 import ModelGallery from './components/ModelGallery.jsx';
30 import DatePicker from 'react-datepicker';
31 import moment from "moment";
32 import ModelBreadcrumb from './components/ModelBreadcrumb.jsx';
33 import Grid from 'react-bootstrap/lib/Grid';
34 import Row from 'react-bootstrap/lib/Row';
35 import Col from 'react-bootstrap/lib/Col';
36 import Button from 'react-bootstrap/lib/Button';
37 import Modal from 'react-bootstrap/lib/Modal';
38 import Pagination from 'react-js-pagination';
39 import { ModelConstants } from './ModelConstants';
40 import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
41 import Tooltip from 'react-bootstrap/lib/Tooltip';
42 import DownloadRangeModel from 'generic-components/DownloadRangeModel.jsx';
43 import BootstrapSwitchButton from 'bootstrap-switch-button-react';
44
45 let INVLIST = GlobalExtConstants.INVLIST;
46 let DOWNLOAD_ALL = GlobalExtConstants.DOWNLOAD_ALL;
47 let generateExcels = ExportExcel.generateExcels;
48 let buildAttrList = ExportExcel.buildAttrList;
49 let DOWNLOAD_TOOLTIP = GlobalExtConstants.DOWNLOAD_TOOLTIP;
50 let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT;
51 let APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
52 let filterTypeList = GlobalExtConstants.FILTER_TYPES;
53 let TABULAR_FILTER_TYPE = GlobalExtConstants.TABULAR_FILTER_TYPE;
54 let URI_DELIMITCHAR = GlobalExtConstants.URI_DELIMITCHAR;
55 /*const mapStateToProps = ({extensibility: {extModelReducer} }) => {
56       let {inventoryData} = extModelReducer;
57   return {
58         inventoryData
59       };
60 };*/
61
62  const mapStateToProps = (state) => {
63   return {
64     currState: state.modelReducer
65   };
66 };
67
68 const mapActionToProps = (dispatch) => {
69   return {
70     onInventoryDataReceived: (data) => {
71       dispatch({ type: 'UPDATE_INVENTORY_DATA', data: data });
72     }
73   };
74 };
75
76 /**
77  * This class is used to handle any url interactions for models.
78  * When a user selects a inventory item in browse or special search,
79  * this model class should be used to handle the url + params and query
80  * the proxy server.
81  */
82
83 export class model extends Component {
84
85   elements = [];
86   filterQuery = '';
87   pageTitle = '';
88   nodeType = '';
89   historyStackString = '';
90   typeOfCall = true;
91   nodeResults = '';
92   downloadTooltip = DOWNLOAD_TOOLTIP;
93   downloadAllTooltip = 'Downloads First ' + DOWNLOAD_ALL + ' Results';
94   downloadRangeTooltip= 'Downloads Results By Custom Range Selection';
95   initialFilterSelectedList = [];
96   initialFilterMessage = [];
97   initialNonDisplay = true;
98   constructor(props) {
99     console.log(props);
100     APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
101     super(props);
102     var filterSelectedList = [];
103     var seletedFilter = [];
104     var filterMessage = [];
105     var nonDisplay = true;
106     var enableToggle= JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'ENABLE_ANALYSIS'));
107     TABULAR_FILTER_TYPE=(APERTURE_SERVICE && enableToggle)?'CONTAINS':'='; 
108     if (this.props.match.params.type) {
109       seletedFilter = this.props.match.params.type.split(';');
110       seletedFilter.map((param) => {
111         console.log('param', param);
112         console.log('param.indexOf(=)', param.indexOf('='));
113         if (param.indexOf(URI_DELIMITCHAR+'='+URI_DELIMITCHAR) !== -1) {
114           let id = param.split(URI_DELIMITCHAR+'='+URI_DELIMITCHAR)[0];
115           let value = param.split(URI_DELIMITCHAR+'='+URI_DELIMITCHAR)[1];
116           filterSelectedList.push({ 'id': id, 'value': value, 'type':'='});
117           filterMessage.push(id+'='+value);
118           enableToggle=false;
119         }else{
120           for(var x in  filterTypeList){
121             if (param.indexOf(URI_DELIMITCHAR+filterTypeList[x]+URI_DELIMITCHAR) !== -1) {
122               let paramArray=param.split(URI_DELIMITCHAR+filterTypeList[x]+URI_DELIMITCHAR); 
123               let id = paramArray[0];
124               let value = paramArray[1];
125               filterSelectedList.push({ 'id': id, 'value': value, 'type': filterTypeList[x]});
126               filterMessage.push(id+filterTypeList[x]+value);
127               enableToggle=true;
128             }
129           }          
130         }
131       });
132     }
133     if (this.props.match.params.nodeId) {
134       nonDisplay = false;
135     }
136     if(this.props.match.params.page==='false'){
137       enableToggle=false;
138     }
139     if(!this.props.location.historyStackString){
140         this.props.location.historyStackString = this.props.location.pathname + ',,Origin||';
141     }else{
142         this.historyStackString = this.props.location.historyStackString;
143     }
144     this.state = {
145       activePage: 1,
146       totalResults: 0,
147       enableBusyFeedback: true,
148       data: [],
149       filterList: [],
150       nodes: [],
151       filterSelected: (this.props.match.params.type) ? this.props.match.params.type.split(';')[0] : '',
152       filterDisplay: 'Select Filter',
153       filterTypeDisplay: 'Filter Type',
154       filterMessage: filterMessage,
155       filterSelectedList: filterSelectedList,
156       isRunEnable: false,
157       isFilterEnable: nonDisplay,
158       isPaginationEnable: nonDisplay,
159       showHistoryModal: false,
160       nodeDisplay: 'test',
161       startDate: moment(),
162       historyType: 'nodeState',
163       enableCalendar: true,
164       focusedNodeUri: 0,
165       viewName: localStorage.getItem(GlobalExtConstants.ENVIRONMENT + '_' + sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'userId') + '_viewPreference')  || 'CardLayout',
166       errorResults: false,
167       errorMessage: '',
168       showResults: false,
169       resetColumnFilters: true,
170       defaultViewName: localStorage.getItem(GlobalExtConstants.ENVIRONMENT + '_' + sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'userId') + '_viewPreference')  || 'CardLayout',
171       isPageNumberChange: false,
172       totalPages: 0,
173       pageRange: 1,
174       showDownloadResultsModal: false,
175       errorDownloadResults:false,
176       downloadErrorMsg: '',      
177       enableModelBusyFeedback:false,
178       downloadCount:DOWNLOAD_ALL,
179       enableRealTime: enableToggle
180     };
181     this.baseState=this.state;
182   }
183   resultsMessage = '';
184   componentDidMount = () => {
185     console.log('[Model.jsx] componentDidMount props available are', JSON.stringify(this.props));
186     if (this.state.isFilterEnable) {
187       this.populateFilteringOptions();
188     }
189     this.initialFilterSelectedList = this.state.filterSelectedList;
190     this.initialFilterMessage = this.state.filterMessage;
191     this.initialNonDisplay = this.state.isFilterEnable;
192     this.beforefetchInventoryData();
193   };
194   handleDateChange = (newDate) =>{
195     this.setState({ startDate: moment(+newDate) });
196     console.log('[Model.jsx] handleDateChange date is ', this.state.startDate);
197     console.log('[Model.jsx] handleDateChange date is in millis ', +this.state.startDate);
198   }
199   openHistory = (nodeDisplay, nodeUri, nodeType) => { // open modal
200     console.log('history >> showModal');
201     let historyNodeUri = (nodeUri)?nodeUri.replace('/aperture/','/'):nodeUri;//replace always first occurence
202     if(nodeDisplay){
203        this.setState({
204           nodeDisplay: nodeDisplay,
205           focusedNodeUri: historyNodeUri,
206           focusedNodeType: nodeType,
207           showHistoryModal:true
208        });
209     }else{
210         this.setState({
211               showHistoryModal:true
212         });
213     }
214   }
215   closeHistory = () => {
216         this.setState({
217                 showHistoryModal: false
218         });
219   }
220   submitHistory = () => {
221     //do some logic in history
222     console.log("submitting history");
223     let epochStartTime = (this.state.startDate).unix();
224     this.props.history.push('/history/' + this.state.historyType+'/' + this.nodeType + '/' + btoa(this.state.focusedNodeUri) + '/' + epochStartTime * 1000);
225   }
226   setHistoryType(event) {
227     console.log(event.target.value);
228     let enableCalendar = false;
229     if(event.target.value === 'nodeLifeCycle'){
230         enableCalendar = false;
231     }else{
232         enableCalendar = true;
233     }
234     this.setState({
235                 historyType: event.target.value,
236                 enableCalendar: enableCalendar
237     });
238     console.log(this.state.enableCalendar);
239   }
240   setViewName(event) {
241     console.log(event.currentTarget.value);
242     this.setState({
243                 viewName: event.currentTarget.value
244     });
245   }
246   setDefaultViewName = (event) =>{
247     let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT;
248     let layout =  event.target.value;
249
250     if(sessionStorage.getItem(ENVIRONMENT + 'userId')) {
251       if (event.target.checked) {
252         localStorage.setItem(ENVIRONMENT + '_' + sessionStorage.getItem(ENVIRONMENT + 'userId') + '_viewPreference', layout);
253       } else {
254         localStorage.removeItem(ENVIRONMENT + '_' + sessionStorage.getItem(ENVIRONMENT + 'userId') + '_viewPreference');
255       }
256     }
257
258     this.setState({
259       defaultViewName: event.target.value
260     });
261     this.baseState.viewName=event.target.value;
262     this.baseState.defaultViewName=event.target.value;
263   }
264   componentWillUnmount  = () => {
265     console.log('[Model.jsx] componentWillUnMount');
266     this.props.onInventoryDataReceived([]);
267   }
268   beforefetchInventoryData = (param) => {
269     this.typeOfCall = true;
270     if (param) {
271       this.props.onInventoryDataReceived([]);
272       this.formFilterQuery(param.filterMessage);
273       this.setState(
274         { enableBusyFeedback: true, activePage: 1, totalResults: 0, totalPages: 0,filterMessage: param.filterMessage, filterSelectedList: param.filterSelectedList},
275         function () { this.fetchInventoryData(param); }.bind(this)
276       );
277     } else {
278       this.formFilterQuery(this.state.filterMessage);
279       this.fetchInventoryData();
280     }
281   };
282
283   formFilterQuery = (filterMessage) => {
284     let filterQuery = filterMessage.join('&');
285     this.filterQuery = (filterMessage.length > 0) ? '&' + filterQuery : '';
286   };
287
288   fetchInventoryData = (param) => {
289     console.log('fetchInventoryData', param);
290     this.resultsMessage = '';    
291     const inventory = INVLIST.INVENTORYLIST;
292     let url = '';
293     console.log('[Model.jsx] fetchInventoryData nodeId= ', this.props.match.params.nodeId);
294     if (this.props.match.params.type !== undefined && this.props.match.params.type !== null) {
295       this.nodeType = this.props.match.params.type;
296     }
297     console.log('[Model.jsx] nodeType: ' + this.nodeType);
298     let pageName = this.nodeType.split(';')[0].replace(/\s/g, '').toUpperCase();
299     console.log('[Model.jsx] pageName: ' + pageName);
300     if (inventory[pageName] && inventory[pageName].display) {
301       this.pageTitle = inventory[pageName].display;
302     } else {
303       this.pageTitle = pageName;
304     }
305     var nonRelationshipState = false;
306     if (this.props.match.params.nodeId) {
307       this.setUri(this.props.location.uri);
308       this.setBreadcrumb(this.props.location.uri);
309       url = sessionStorage.getItem(ENVIRONMENT + 'URI');
310       if(this.state.enableRealTime){
311         let versionPattern="^"+INVLIST.VERSION+"\\/";
312         var versionRegularExp = new RegExp(versionPattern, 'g');
313         let matchVersion = url.match(versionRegularExp,'g');
314         if(!matchVersion){
315           url= INVLIST.VERSION+'/'+url;
316         } 
317       } 
318     } else {
319       url = inventory[pageName].apiPath;
320       this.setBreadcrumb(url);
321       nonRelationshipState=true;
322     }
323     console.log('[Model.jsx] active page', this.state.activePage);
324     console.log('this.state.filterSelectedList', this.state.filterSelectedList);
325     console.log('filterQuery', this.filterQuery);
326     //Aperture with Diff Filter types Operater  
327     this.nodeResults = '';
328     var method = 'GET';
329     var payload = {};
330     const settings = {
331       'NODESERVER': INVLIST.NODESERVER,
332       'PROXY': INVLIST.PROXY,
333       'PREFIX': INVLIST.PREFIX,
334       'VERSION': INVLIST.VERSION,
335       'USESTUBS': INVLIST.useStubs,
336       'APERTURE': INVLIST.APERTURE,
337       'APERTURE_SERVICENAME':INVLIST.APERTURE_SERVICENAME
338     };
339     if(this.state.enableRealTime){
340       settings['ISAPERTURE'] = (nonRelationshipState)? true : false;
341     }else{
342       if(!(this.state.enableRealTime && nonRelationshipState)){
343         url = (url)?url.replace(INVLIST.VERSION+'/',''):url;
344       }
345     } 
346     if(this.state.enableRealTime && nonRelationshipState){
347       var filterList=this.state.filterSelectedList;
348       var filters = [];
349       for(var k in filterList){
350         if(filterList.hasOwnProperty(k)){
351           let filter ={}
352           filter['filter']= filterList[k].type;
353           filter['key'] = filterList[k].id;
354           filter['value'] = filterList[k].value;
355           filters.push(filter);
356         }
357       }
358       method= 'POST';
359       payload['node-type'] = url.split('/')[1];
360       payload['filter-version'] = 'v1';
361       payload['filters'] = filters;
362     }else{
363       payload = null;
364     }
365     
366     var path = '?format=simple&resultIndex=' + this.state.activePage + '&resultSize=';      
367     if(this.typeOfCall){  
368       path = path + ModelConstants.RESULTS_PER_PAGE;
369       url=(this.state.enableRealTime && nonRelationshipState)? path: url + path + this.filterQuery;
370       this.commonApiServiceCall(settings,url,param,method,payload);
371     }else{
372       let pagerange=this.state.pageRange.toString();
373       pagerange=pagerange.split('-');
374       if(pagerange.length > 1){
375         path = '?format=simple&resultIndex=' + parseInt(pagerange[0]) + '&resultSize='+ ModelConstants.RESULTS_PER_PAGE + '&resultRangeEnd=' + parseInt(pagerange[1]);
376       }else{
377         path = '?format=simple&resultIndex=' + 1 + '&resultSize=' + parseInt(pagerange);
378       }
379       url=(this.state.enableRealTime && nonRelationshipState)? path: url + path + this.filterQuery; 
380       this.commonApiServiceCallForAllData(settings,url,method,payload);
381     }
382   };
383   commonApiServiceCall = (settings,url,param,method,payload) =>{
384     
385     commonApi(settings, url, method, payload, 'modelDefault')
386       .then(res => {
387         // Call dispatcher to update state
388         console.log('once before service call ......',this.state);
389         this.resultsMessage = '';
390         var totalResults = parseInt(res.headers['total-results']); 
391         let downloadCount = DOWNLOAD_ALL;   
392         if(totalResults > DOWNLOAD_ALL){
393           this.downloadAllTooltip = DOWNLOAD_ALL + ' results out of '+ totalResults +' will be downloaded, please filter results further to obtain full report';
394         }else{
395           this.downloadAllTooltip = (totalResults === 1) ? 'Downloads ' + totalResults + ' Results' : 'Downloads all ' + totalResults + ' Results'
396           downloadCount= totalResults;
397         }   
398         this.setState(
399           {
400             nodes : res.data.results,
401             totalResults : res.headers['total-results'],
402             totalPages: res.headers['total-results'],
403             enableBusyFeedback:false,
404             showResults: true,
405             errorResults: false,
406             downloadCount: downloadCount,
407             filterSelectedList:(param)?param.filterSelectedList:this.state.filterSelectedList
408           },function(){this.props.onInventoryDataReceived(res.data.results);});
409                        
410         console.log('After service call ......',this.state);
411         console.log('[Model.jsx] results : ', res);
412         }, error=>{
413            this.triggerError(error);
414         }).catch(error => {
415            this.triggerError(error);
416       });
417   };
418   commonApiServiceCallForAllData = (settings,url,method,payload) => {
419
420     commonApi(settings, url,method, payload, 'modelDefault')
421       .then(res => {
422         // Call dispatcher to update state        
423         console.log('once before service call ......',this.state);
424         this.resultsMessage = '';
425         this.nodeResults = res.data.results;
426         let totalResults = parseInt(res.headers['total-results']);
427         let totalPages = parseInt(res.headers['total-pages']);
428         this.setState({totalPages:totalPages,errorDownloadResults:false,downloadErrorMsg:''},() => {this.getAllExcels()});
429         console.log('[Model.jsx] results : ', res);
430       }).catch(error => {
431         console.log('[Model.jsx] error : ', error);
432         this.nodeResults = '';
433         let errMsg = this.renderErrorMsg(error);      
434         this.setState({ enableBusyFeedback: false,errorDownloadResults:true,downloadErrorMsg:errMsg,enableModelBusyFeedback:false});       
435       });     
436   };
437
438    triggerError = (error) => {
439       console.error('[Model.jsx] error : ', JSON.stringify(error));
440       this.props.onInventoryDataReceived([]);
441       this.resultsMessage = 'No Results Found';
442       this.downloadAllTooltip = 'Downloads First ' + DOWNLOAD_ALL + ' Results';
443       this.nodeResults = '';
444       this.setState({
445             enableBusyFeedback: false,
446             totalResults: 0,
447             totalPages: 0,
448                 showResults: false,
449                 errorResults: true
450         });
451       let errMsg = this.renderErrorMsg(error);
452       //Suppress Error Message when 404 results not found occur
453       if(error.response && error.response.status === 404){
454         this.setState({errorMessage:'', errorResults:false});
455       }else{
456             this.setState({errorMessage:errMsg});
457       }
458     };
459     renderErrorMsg = (error) =>{
460       let errMsg='';
461        if (error.response) {
462          // The request was made and the server responded with a status code
463          // that falls out of the range of 2xx
464          console.log(error.response.data);
465          console.log(error.response.status);
466          console.log(error.response.headers);
467          if(error.response.status){
468              errMsg += " Code: " + error.response.status;
469          }
470          if(error.response.data){
471              errMsg += " - " + JSON.stringify(error.response.data);
472          }
473        } else if (error.request) {
474          // The request was made but no response was received
475          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
476          // http.ClientRequest in node.js
477          console.log(error.request);
478          errMsg += " - Request was made but no response received";
479        } else {
480          // Something happened in setting up the request that triggered an Error
481          console.log('Error', error.message);
482          errMsg += " - Unknown error occurred " + error.message;
483        }
484       
485        console.log(error.config);
486        return errMsg;
487     }
488
489   componentWillReceiveProps(nextProps) {
490     console.log('[Model.jsx] componentWillReceiveProps');
491     console.log('[Model.jsx] next nodeId:', nextProps.match.params.nodeId);
492     console.log('[Model.jsx] this nodeId:', this.props.match.params.nodeId);
493
494     if(nextProps.match.params.nodeId !== undefined && this.props.match.params.nodeId !== undefined){
495       if (nextProps.match.params.nodeId && nextProps.match.params.nodeId
496         !== this.props.match.params.nodeId) {
497         this.props = nextProps;
498         this.beforefetchInventoryData();
499       }
500     }
501   };
502
503   setUri(uri) {
504     let delimiter = '\/';
505     let start = 3;
506     let tokens = uri.split(delimiter).slice(start);
507     let result = tokens.join(delimiter);
508     sessionStorage.setItem(ENVIRONMENT + 'URI', result);
509   };
510
511   setBreadcrumb(uri){
512       var nodeType = this.nodeType.split(';')[0];
513       var display = nodeType + ': ' + (uri).split(nodeType+'\/').pop();
514       var hsEntry = this.props.location.pathname + ',' + uri +  ','+ display + '||';
515       console.log("History Stack String: " + this.props.location.historyStackString);
516        if(this.historyStackString.indexOf(hsEntry) > -1){
517           var tempHistoryStack = this.historyStackString.split(hsEntry)[0];
518           var tempHistoryStackFormat = tempHistoryStack.replace(hsEntry, "");
519           this.historyStackString = tempHistoryStackFormat;
520        }
521       this.historyStackString += hsEntry;
522       this.props.location.historyStackString = this.historyStackString;
523       console.log('[Model.jsx] historyStack in model' + this.historyStackString);
524   }
525
526   handlePageChange = (pageNumber) => {
527     console.log('[Model.jsx] HandelPageChange active page is', pageNumber);
528     this.props.onInventoryDataReceived([]);
529     this.setState(
530       { activePage: pageNumber, enableBusyFeedback: true, resetColumnFilters: false, isPageNumberChange: true},
531       function () { this.beforefetchInventoryData(); }.bind(this)
532     );
533   };
534   openDownloadRange = () =>{    
535       this.setState({
536         showDownloadResultsModal: true,
537         errorDownloadResults: false,
538         downloadErrorMsg:''});    
539   }
540   closeDownloadResults = () =>{
541     this.setState({
542       showDownloadResultsModal: false,
543       enableModelBusyFeedback: false
544                 });   
545   }
546   getAllExcels = (pageRange,rangeState) =>{
547     console.log('getAllExcels>>>>>>>>>>>*',pageRange);
548     if(pageRange){
549       this.typeOfCall=false;
550       let rangeModelState=(rangeState)? rangeState: false;
551       this.setState(
552         { pageRange: pageRange,enableBusyFeedback: true, enableModelBusyFeedback:true,showDownloadResultsModal:rangeModelState},
553         function () { this.fetchInventoryData(); }.bind(this)
554       );
555     }else{
556       this.setState(
557         {errorDownloadResults: false, showDownloadResultsModal: false, downloadErrorMsg:'', enableBusyFeedback: false, enableModelBusyFeedback:false},
558         function () { generateExcels(this.nodeResults);this.nodeResults='';this.typeOfCall = true;}.bind(this)
559       );
560     }     
561   };
562   
563   populateFilteringOptions = () => {
564     let tempState = this.state;
565     tempState.filterList = buildAttrList(this.state.filterSelected, tempState.filterList);
566     this.setState(tempState);
567   };
568
569   // HELPER FUNCTIONS
570   isContaining = (nameKey, listArray) => {
571     let found = false;
572     listArray.map((lists) => {
573       if (lists.id === nameKey) {
574         found = true;
575       }
576     });
577     return found;
578   };
579   isTableFilterApply = (columnFilterList,nodeType,columnsList) => {
580     console.log('Model js ....columnFilterList:',columnFilterList);
581     console.log('Model js .... nodeType:',nodeType);
582     var columnFilter = columnFilterList[nodeType][0];
583     console.log('model js columnFilter:',columnFilter);    
584     var columns = columnsList[nodeType];
585     var applyState = false;
586     var filterSelectedList = [];
587     var filterMessage = [];
588     
589     for(var i=0;i<columnFilter.length;i++){
590       var colFilterValue = columnFilter[i][columns[i].value];      
591       if(colFilterValue != ""){        
592         filterSelectedList.push({ 'id': columns[i].value, 'value': colFilterValue, 'type': TABULAR_FILTER_TYPE});
593         let filterMsg = columns[i].value + TABULAR_FILTER_TYPE + colFilterValue;
594         filterMessage.push(filterMsg); 
595         applyState = true;         
596       }
597     }
598     console.log('isTableFilterApply filterSelectedList>>>>>',filterSelectedList);
599     console.log('isTableFilterApply filterMessage>>>>>>>>>>',filterMessage); 
600         
601     if(applyState){  
602       var tempState = this.state;
603       var state = true;
604       var stateFilterSelectedList = tempState.filterSelectedList;
605         var id = 'id';
606         var value = 'value';
607         if(stateFilterSelectedList.length > 0){
608           for(var j in filterSelectedList){
609             state = true;
610             for(var k in stateFilterSelectedList){
611               if(stateFilterSelectedList[k][id] === filterSelectedList[j][id]){ 
612                 state =false;                              
613                 tempState.filterSelectedList[k] = { 'id':filterSelectedList[j][id], 'value': filterSelectedList[j][value], 'type': TABULAR_FILTER_TYPE};
614               }
615             }
616             if(state){
617               tempState.filterSelectedList.push({ 'id':filterSelectedList[j][id], 'value': filterSelectedList[j][value],  'type': TABULAR_FILTER_TYPE});
618             }            
619           }
620           stateFilterSelectedList = tempState.filterSelectedList;
621           for(var k in stateFilterSelectedList){
622             tempState.filterMessage[k] = stateFilterSelectedList[k][id] + TABULAR_FILTER_TYPE + stateFilterSelectedList[k][value]
623           }
624         }else{
625           tempState.filterSelectedList = filterSelectedList;
626           tempState.filterMessage = filterMessage;
627         }
628
629         console.log('isTableFilterApply  tempState:',tempState);
630         this.beforefetchInventoryData(tempState);
631     }
632   };
633   prepareModelGalleryElement = () =>{
634     let modelGalleryElement='';
635     if(this.state.isFilterEnable){
636       modelGalleryElement = <ModelGallery nodes={this.props.currState.inventoryData}
637                                   viewName={this.state.viewName}
638                                   historyStackString={this.props.location.historyStackString}
639                                   openHistoryModal={this.openHistory}
640                                   isPageNumberChange={this.state.isPageNumberChange}
641                                   resetColumnInd={this.state.resetColumnFilters}
642                                   isTableFilterApply={this.isTableFilterApply}
643                                   enableRealTime={this.state.enableRealTime}
644                                 />;
645     }else{
646       modelGalleryElement = <ModelGallery nodes={this.props.currState.inventoryData}
647                                   viewName={this.state.viewName}
648                                   historyStackString={this.props.location.historyStackString}
649                                   openHistoryModal={this.openHistory}
650                                   isPageNumberChange={this.state.isPageNumberChange}
651                                   resetColumnInd={this.state.resetColumnFilters}
652                                   enableRealTime={this.state.enableRealTime}
653                                 />;
654     }
655     return modelGalleryElement;
656   }
657   prepareDownloadRangeModel = () =>{
658   
659     let downloadRangeModel =(this.state.showDownloadResultsModal)? <DownloadRangeModel 
660               showDownloadResultsModal={this.state.showDownloadResultsModal}
661               totalPages={this.state.totalPages}
662               totalResults={this.state.totalResults}
663               triggerDownload={this.getAllExcels}
664               errorDownloadResults={this.state.errorDownloadResults}
665               downloadErrorMsg={this.state.downloadErrorMsg}
666               triggerClose={this.closeDownloadResults}
667               enableModelBusyFeedback={this.state.enableModelBusyFeedback}
668           /> : '';
669     return downloadRangeModel;
670   }
671   toggleRealTimeAnalysisCallback=(checked)=>{
672     console.log('toggleRealTimeAnalysisCallback>>>>',checked);
673     sessionStorage.setItem(ENVIRONMENT + 'ENABLE_ANALYSIS', !checked);
674     TABULAR_FILTER_TYPE=(APERTURE_SERVICE && !checked)?'CONTAINS':'=';
675     this.baseState.enableRealTime = !checked;
676     this.baseState.filterMessage = [];
677     this.baseState.filterSelectedList = [];
678     this.setState({...this.baseState},()=>{this.beforefetchInventoryData(this.state)});
679   }
680   render() {
681     console.log('[Model Props] render: ', JSON.stringify(this.props) + 'elements : ', this.elements);
682     console.log('[Model nodeId] render: ', this.props.match.params.nodeId);
683     console.log('[Model nodeId] render this.state: ', this.state);
684     var toggelRealtimeAnalysis = '';
685           if(APERTURE_SERVICE){         
686                   toggelRealtimeAnalysis = <div className='toggleSwitch'><BootstrapSwitchButton
687                                 checked={!this.state.enableRealTime}
688                                 onlabel='Real Time'
689                                 onstyle='danger'
690                                 offlabel='Analysis'
691                                 offstyle='success'
692                                 style='w-100 mx-3'
693                                 onChange={(checked) => {
694                                   this.toggleRealTimeAnalysisCallback(checked);
695                                 }}
696                               /></div>             
697           }
698     const modelGalleryElement = this.prepareModelGalleryElement();
699     let downloadRangeModel = this.prepareDownloadRangeModel();
700     return (
701       <div>
702         {toggelRealtimeAnalysis}
703         <Grid fluid={true} className='model-container'>
704           <Row className='show-grid'>
705             <Col md={12}>
706               <h1>{this.pageTitle}</h1>
707               <Filter key='browseSearch'
708                 nodeType={this.state.filterSelected}
709                 filterList={this.state.filterList}
710                 filterDisplay={this.state.filterDisplay}
711                 filterTypeDisplay={this.state.filterTypeDisplay}
712                 isRunEnable={this.state.isRunEnable}
713                 filterMessage={this.state.filterMessage}
714                 loadInventory={this.beforefetchInventoryData}
715                 filterSelectedList={this.state.filterSelectedList}
716                 isFilterEnable={this.state.isFilterEnable} 
717                 enableRealTime={this.state.enableRealTime}/>
718             </Col>
719           </Row>
720           <Spinner loading={this.state.enableBusyFeedback}>
721             <Row className='show-grid'>
722               <Col md={8} className={this.state.isPaginationEnable && this.state.showResults ? 'show' : 'hidden'}>
723                 <Pagination
724                   activePage={this.state.activePage}
725                   itemsCountPerPage={ModelConstants.RESULTS_PER_PAGE}
726                   totalItemsCount={this.state.totalResults}
727                   pageRangeDisplayed={ModelConstants.PAGE_RANGE_DISPLAY}
728                   onChange={this.handlePageChange} />
729               </Col>
730               <Col md={2} className={this.state.isPaginationEnable && this.state.showResults ? 'text-right' : 'text-left'}>
731                 <OverlayTrigger  placement='top' overlay={<Tooltip id='tooltip-top'>{this.downloadAllTooltip}</Tooltip>}>
732                   <span className='d-inline-block' style={{display: 'inline-block'}}>
733                     <Button bsSize='small' onClick={() => {this.getAllExcels(this.state.downloadCount)}}>
734                       Download XLSX <i className='icon-documents-downloadablefile'></i>
735                     </Button>
736                   </span>
737                 </OverlayTrigger>
738               </Col>
739               <Col md={2} className={this.state.isPaginationEnable && this.state.showResults ? 'text-right' : 'text-left'}>
740                 <OverlayTrigger  placement='top' overlay={<Tooltip id='tooltip-top'>{this.downloadRangeTooltip}</Tooltip>}>
741                   <span className='d-inline-block' style={{display: 'inline-block'}}>
742                     <Button bsSize='small' onClick={this.openDownloadRange}>
743                       Download XLSX (Range)<i className='icon-documents-downloadablefile'></i>
744                     </Button>
745                   </span>
746                 </OverlayTrigger>
747               </Col>
748             </Row>
749             <Row className='show-grid'>
750                 <ModelBreadcrumb historyStackString={this.props.location.historyStackString}/>
751             </Row>
752             <Row>
753               <div className={'addPaddingTop alert alert-danger ' +(this.state.errorResults ? 'show' : 'hidden')} role="alert">
754                   An error occurred, please try again later. If this issue persists, please contact the system administrator. {this.state.errorMessage}
755               </div>
756             </Row>
757             <Row className='show-grid'>
758               { this.state.showResults && <div className='addPaddingTop'>
759                   <OutputToggle scope={this} visualDisabled={true}/>
760                 </div>
761               }
762             </Row>  
763             <Row className={'show-grid ' + this.state.showResults ? 'show' : 'hidden'}>
764               <Col md={12}>
765                 <hr />
766                 <h5>Total Results: <strong>{this.state.totalResults}</strong></h5>
767                 <span className='resultMessage'>{this.resultsMessage}</span>
768               </Col>
769             </Row>
770             <Row className='show-grid'>
771               {           
772                 modelGalleryElement            
773               }         
774             </Row>
775             <Row className='show-grid'>
776               <Col md={12} className={this.state.isPaginationEnable && this.state.showResults ? 'show' : 'hidden'}>
777                 <Pagination
778                   activePage={this.state.activePage}
779                   itemsCountPerPage={ModelConstants.RESULTS_PER_PAGE}
780                   totalItemsCount={this.state.totalResults}
781                   pageRangeDisplayed={ModelConstants.PAGE_RANGE_DISPLAY}
782                   onChange={this.handlePageChange} />
783               </Col>
784             </Row>
785             <div className='static-modal'>
786                 <Modal show={this.state.showHistoryModal} onHide={this.closeHistory}>
787                   <Modal.Header>
788                     <Modal.Title>Retrieve {this.state.nodeDisplay} History</Modal.Title>
789                   </Modal.Header>
790                   <Modal.Body>
791                     <form>
792                               <div className="radio">
793                                 <label>
794                                   <input type="radio" value="nodeState"
795                                                 checked={this.state.historyType === 'nodeState'}
796                                                 onChange={(e) => this.setHistoryType(e)} />
797                                   View state at
798                                 </label>
799                               </div>
800                               <div className="radio">
801                                 <label>
802                                   <input type="radio"  value="nodeLifeCycleSince"
803                                                 checked={this.state.historyType === 'nodeLifeCycleSince'}
804                                                 onChange={(e) => this.setHistoryType(e)} />
805                                   View updates since
806                                 </label>
807                               </div>
808                               <div className="radio">
809                                 <label>
810                                   <input type="radio" value="nodeLifeCycle"
811                                                 checked={this.state.historyType === 'nodeLifeCycle'}
812                                                 onChange={(e) => this.setHistoryType(e)} />
813                                   View all updates
814                                 </label>
815                               </div>
816                             </form>
817                     <div className={this.state.enableCalendar ? 'show' : 'hidden'}>
818                         <DatePicker
819                             inline
820                                   selected={this.state.startDate}
821                                   onChange={(newDate) => this.handleDateChange(newDate)}
822                                   showTimeSelect
823                                   timeFormat="HH:mm"
824                                   timeIntervals={15}
825                                   dateFormat="MMMM D, YYYY h:mm a"
826                                   timeCaption="time"
827                               />
828                           </div>
829                   </Modal.Body>
830                   <Modal.Footer>
831                     <Button onClick={this.closeHistory}>Close</Button>
832                     <Button onClick={this.submitHistory}>Submit</Button>
833                   </Modal.Footer>
834                 </Modal>
835             </div>
836           </Spinner>
837           <Spinner loading={this.state.enableModelBusyFeedback}>
838             {downloadRangeModel}
839           </Spinner>
840         </Grid>
841       </div>
842     );
843   }
844 }
845
846 export default connect(mapStateToProps, mapActionToProps)(model);