Updated Sparky to add ECOMP functionality Browse, Specialized Search, BYOQ, and the...
[aai/sparky-fe.git] / src / app / byoq / PathFilterDslBuilder.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 Modal from 'react-bootstrap/lib/Modal';
23 import Grid from 'react-bootstrap/lib/Grid';
24 import FormGroup from 'react-bootstrap/lib/FormGroup';
25 import FormControl from 'react-bootstrap/lib/FormControl';
26 import ControlLabel from 'react-bootstrap/lib/ControlLabel';
27 import Button from 'react-bootstrap/lib/Button';
28 import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
29 import Spinner from 'utils/SpinnerContainer.jsx';
30 import Row from 'react-bootstrap/lib/Row';
31 import Col from 'react-bootstrap/lib/Col';
32 import Panel from 'react-bootstrap/lib/Panel';
33 import Tooltip from 'react-bootstrap/lib/Tooltip';
34 import FilterTypes from 'generic-components/filter/components/FilterTypes.jsx';
35 import BootstrapSwitchButton from 'bootstrap-switch-button-react';
36 import {GeneralCommonFunctions} from 'utils/GeneralCommonFunctions.js';
37 import * as d3 from "d3";
38 import 'd3-selection-multi';
39
40
41 let EDGERULES = GlobalExtConstants.EDGERULES;
42 let OXM = GlobalExtConstants.OXM;
43 let INVLIST = GlobalExtConstants.INVLIST;
44 let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT;
45 let APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
46
47 let nodeTypes = [];
48 let properties = null;
49 let traverseRulesDsl = [];
50
51 const settings = {
52         'NODESERVER': INVLIST.NODESERVER,
53         'PROXY': INVLIST.PROXY,
54         'PREFIX': INVLIST.PREFIX,
55         'VERSION': INVLIST.VERSION,
56     'USESTUBS': INVLIST.useStubs
57 };
58 class PathFilterDslBuilder extends Component {
59         constructor(props) {
60                 console.log('PathFilter props>>>>',props);
61         super(props);
62         APERTURE_SERVICE=JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
63                 this.state = {edgeRules : null,
64                               showNodeModal: false,
65                               treemap: null,
66                               root: null,
67                               svg: null,
68                               duration: null,
69                               g: null,
70                               selectedNode: null,
71                               traverseToNodes:[],
72                               nodeDetails: [],
73                       dslQuery: '',
74                       dslQueryTree:'',
75                               editModel:'',
76                               showEditModal: false,
77                               zoomFit: null,
78                               autoZoomEnabled: true,
79                               aggregateObjects: false,
80                               init: true,
81                               filterTypeDisplay: 'Filter Type',
82                       selectedfilterType:[],
83                       oxmMapping:null,
84                       closePathNodeModal:true,
85                       submitPathNodeModal:false,
86                       parentNodeType:'',
87                       parentAttrDetails:'',
88                       showPathFilterDslBuilder:false,
89                       dslPath:'',
90                       dslPathTree:null,
91                       isInitialize:true,
92                       treeData:'',
93                       showEditNodeModal:false,
94                       enableRealTime: JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'ENABLE_ANALYSIS'))
95                       }
96         }
97
98   componentDidMount () {
99     console.log('Path Filter componentDidMount',JSON.stringify(this.props));
100     //this.buildSQLStatementsFromSchema();
101     this.processEdgeRules(EDGERULES);    
102   }
103   componentDidUpdate (nextProps) {
104       console.log('Path  Filter componentDidUpdate>>>>>>>',nextProps);
105       if(this.state.isInitialize){
106         this.props=nextProps;
107         console.log('this.props>>>>>>>>>>>>>',this.props);
108         this.setState({submitPathNodeModal:this.props.submitPathNodeModal,
109                 closePathNodeModal:this.props.closePathNodeModal,
110                 parentNodeType:this.props.nodeType,
111                 parentAttrDetails:this.props.attrDetails,
112                 showPathFilterDslBuilder:this.props.showPathFilterDslBuilder,
113                 dslPath:this.props.dslPath,
114                 dslPathTree:this.props.dslPathTree,
115                 isInitialize: false},()=>{
116                     if(this.props.dslPathTree){ 
117                         this.build(this.props.nodeType,null,this.props.attrDetails,this.props.dslPathTree);
118                     }else{
119                         //this.initialize(this.props.nodeName);
120                         this.setState({showNodeModal: true,isInitialize:false},()=>{this.populateEdgeRules(this.props.nodeName,this.state.edgeRules)});
121                     }
122                 });
123     }
124     console.log('this.state under Update>>>>>',this.state);
125   }
126   componentWillReceiveProps(nextProps) {      
127     console.log('path Filter componentWillReceiveProps>>>>');    
128   }
129   initialize = () => {
130     var nodeDetails = [];
131     var node = null;
132     console.log('initializing');
133     var id = GeneralCommonFunctions.generateID();
134     var nodeTypes = GeneralCommonFunctions.getNodeTypes();
135     for (var i = 0; i < nodeTypes.length; i++) {
136         node = nodeTypes[i] + id;
137         if(this.props.nodeName === nodeTypes[i]){
138             var attributes = GeneralCommonFunctions.getFilteringOptions(nodeTypes[i]);
139             if(!nodeDetails[node] && Object.keys(attributes).length > 0){
140                 nodeDetails[node] = {};
141                 nodeDetails[node].nodeType = nodeTypes[i];
142                 nodeDetails[node].isSelected = false;
143                 nodeDetails[node].attrDetails = attributes;
144                 nodeDetails[node].parentContainer = GeneralCommonFunctions.populateContainer(nodeTypes[i]);
145             }
146         }
147     }
148     let nodesSorted = nodeDetails.sort(function (filter1, filter2) {
149         if (filter1.nodeType < filter2.nodeType) {
150                 return -1;
151         } else if (filter1.nodeType > filter2.nodeType) {
152                 return 1;
153         } else {
154                 return 0;
155         }
156     });
157     console.log('Node Types List' + JSON.stringify(nodesSorted));
158     nodeDetails = nodesSorted;
159     this.setState({
160         nodeDetails: nodeDetails,
161         showNodeModal: true,
162         isInitialize:false
163     });
164   }
165   initialLoadWhileClose= ()=>{
166     this.setState({showNodeModal: true,isInitialize:false},()=>{this.populateEdgeRules(this.props.nodeName,this.state.edgeRules)});                   
167   }
168   processEdgeRules = (data) => {
169         this.setState({
170                 edgeRules: data.rules
171         });
172   }
173   closeNodeModal = () =>{
174     this.setState({
175         showNodeModal: false,
176         traverseToNodes: [],
177         selectedNode: null
178     });
179   }
180   onNodeCheckbox(e) {
181       var nodeDetails = this.state.nodeDetails;
182       if (e.target.checked) {
183         nodeDetails[e.target.value].isSelected = true;
184         this.selectAll(e.target.value);
185       }else {
186         nodeDetails[e.target.value].isSelected = false;
187         this.deselectAll(e.target.value);
188       }
189       // update the state with the new array of traverse to nodes
190       this.setState({ nodeDetails: nodeDetails });
191   }
192   onNodeRadio(e) {
193       var nodeDetails = this.state.nodeDetails;
194       if (e.target.checked) {
195         nodeDetails[e.target.value].isSelected = true;
196         this.selectAll(e.target.value);
197       }
198       for (var key in nodeDetails) {
199           if(key != e.target.value && nodeDetails[key].isSelected ){
200             nodeDetails[key].isSelected = false;
201             this.deselectAll(key);
202           }
203       }
204       // update the state with the new array of traverse to nodes
205       this.setState({ nodeDetails: nodeDetails });
206   }
207   onAutoZoomCheckbox(e) {
208       var cbValue = false;
209       if (e.target.checked) {
210         cbValue = true;
211       }else {
212         cbValue = false;
213       }
214       this.setState({ autoZoomEnabled: cbValue });
215   }
216   
217   onAttributeCheckbox(e){//delete
218         let splitVal = e.target.value.split("|");
219         let nodeKey = splitVal[0];
220         let attrValue = splitVal[1];
221         let nodeDetails = this.state.nodeDetails;
222         let node = nodeDetails[nodeKey];
223         let attribute = null;
224         if(!node.attrDetails){
225             node.attrDetails = [];
226         }
227         if(!node.attrDetails[attrValue]){
228             node.attrDetails[attrValue] = {};
229             node.attrDetails[attrValue].isSelected = true;
230             node.attrDetails[attrValue].filterValue = [];
231             node.attrDetails[attrValue].filterType = [];
232         }
233
234         // check if the check box is checked or unchecked
235         if (e.target.checked) {
236           // add the value of the checkbox to nodes array
237           node.attrDetails[attrValue].isSelected = true;
238           node.attrDetails[attrValue].filterType[0]='EQ';
239         } else {
240           // or remove the value from the unchecked checkbox from the array
241           node.attrDetails[attrValue].isSelected = false;
242           node.attrDetails[attrValue].filterType = [''];
243           node.attrDetails[attrValue].filterValue = [''];
244         }
245         nodeDetails[nodeKey] = node;
246         // update the state with the new array of traverse to nodes
247         this.setState({ nodeDetails: nodeDetails });
248   }
249   onFilterValueChange(e, nodeKey, attrKey, indx){
250         let nodeDetails = this.state.nodeDetails;
251         let node = nodeDetails[nodeKey];
252         if(!node.attrDetails){
253             node.attrDetails = [];
254         }
255         if(!node.attrDetails[attrKey]){
256             node.attrDetails[attrKey] = {};
257             node.attrDetails[attrKey].isSelected = true;
258             node.attrDetails[attrKey].filterValue = [];
259             node.attrDetails[attrKey].filterType = [];
260         }
261         // add the value of the checkbox to nodes array
262         //node.attrDetails[attrKey].filterValue.push(e.target.value);
263         let filterValArr=node.attrDetails[attrKey].filterValue;
264         filterValArr[indx]=e.target.value;
265         node.attrDetails[attrKey].filterValue=filterValArr;
266         nodeDetails[nodeKey] = node;
267         // update the state with the new array of traverse to nodes
268         this.setState({ nodeDetails: nodeDetails });
269   }
270   submitPathNodeModal= () =>{
271       console.log('PathFinder submitPathNodeModal>>>>>',this.props);
272       this.props.submitPathNodeModal(this.state.dslQuery,this.props.nodeType,this.state.dslQueryTree,this.props.isEditEnable,this.props.pathFilterIndex);
273   }
274   submitNodeModal = () =>{
275     if(this.state.selectedNode){
276         var treeData=this.state.dslQueryTree;
277         var updatedTreeData='';
278         var d = this.state.selectedNode;
279         for(var node in this.state.nodeDetails){
280             if(this.state.nodeDetails[node].isSelected){
281                 var newNodeObj = {
282                                 type: 'node',
283                             name: this.state.nodeDetails[node].nodeType,
284                             id: node,
285                             details: {}
286                           };
287                  //Creates new Node
288                  Object.assign(newNodeObj.details, this.state.nodeDetails[node]);
289                  var newNode = d3.hierarchy(newNodeObj);
290                  newNode.depth = d.depth + 1;
291                  newNode.height = d.height - 1;
292                  newNode.parent = d;
293                  newNode.id = node;
294                  if(!d.children){
295                     d.children = [];
296                  }
297                 if(newNodeObj.details){
298                    var selectedAttributeCount = 0;
299                    for (var key in newNodeObj.details.attrDetails){
300                         if (newNodeObj.details.attrDetails[key].isSelected){
301                             selectedAttributeCount++;
302                         }
303                         if(selectedAttributeCount === Object.keys(newNodeObj.details.attrDetails).length){
304                            newNodeObj.details.includeInOutput = true;
305                         }
306                    }
307                 }
308                 console.log('submit node newNodeObj>>>>>',newNodeObj);
309                 treeData=(updatedTreeData==='')?treeData:updatedTreeData;
310                 updatedTreeData=this.handlingTreeDataWhileAddRemove(treeData,newNodeObj,d.data.id,d.data.name);
311                  d.children.push(newNode);
312                  this.setState({ nodeDetails: [] });
313         }
314       }
315       this.setState({
316                 showNodeModal: false,
317                 traverseToNodes: [],
318             selectedNode: null,
319             dslQueryTree:updatedTreeData
320        }, ()=>{this.update(this, d)});
321     }else{
322         var nodeType = "";
323         var attrDetails = null;
324         for (var key in this.state.nodeDetails) {
325             if(this.state.nodeDetails[key].isSelected){
326               nodeType = this.state.nodeDetails[key].nodeType;
327               attrDetails = this.state.nodeDetails[key].attrDetails;
328             }
329         }
330        this.build(nodeType, null, attrDetails);
331        this.setState({ nodeDetails: [], showNodeModal: false, traverseToNodes: [], selectedNode: null });
332     }
333   }
334   handlingTreeDataWhileAddRemove = (treeData,addObject,id,name)=>{ 
335     if(addObject===''){
336        if(treeData.children && treeData.children.length>0){            
337             for(var y=0;y<treeData.children.length;y++){   
338                 if(treeData.children[y].id=== id  && treeData.children[y].name===name){                                
339                     treeData.children.splice(y,1);                    
340                 }else{
341                     treeData.children[y]=this.handlingTreeDataWhileAddRemove(treeData.children[y],'',id,name);
342                 }               
343             }
344         } 
345     }else{
346         if(treeData.id === id && treeData.name===name){
347             if(!treeData.children){
348                 treeData.children=[];                    
349             }                
350             treeData.children.push(addObject); 
351         }else if(treeData.children && treeData.children.length>0){            
352             for(var y=0;y<treeData.children.length;y++){   
353                 if(treeData.children[y].id=== id  && treeData.children[y].name===name){
354                     if(!treeData.children[y].children){
355                         treeData.children[y].children=[];                    
356                     }                
357                     treeData.children[y].children.push(addObject);                    
358                 }else{
359                     treeData.children[y]=this.handlingTreeDataWhileAddRemove(treeData.children[y],addObject,id,name);
360                 }               
361             }
362         } 
363     }
364     return treeData;
365   }
366
367   populateEdgeRules = (nodeType) => {
368         let  nodeDetails=GeneralCommonFunctions.populateEdgeRules(nodeType,this.state.edgeRules);
369             this.setState({
370                 nodeDetails: nodeDetails
371         });
372   }
373   
374   
375   closeEditDSLModal = () => {
376     console.log("closing DSL edit modal");
377     this.setState({ showEditModal: false });
378   }
379   submitEditNodeModal  = () =>{
380     this.update(this, this.state.selectedNode);
381     this.setState({showEditNodeModal: false});
382   }
383   closeEditNodeModal = () =>{
384     this.setState({
385         showEditNodeModal: false,
386         selectedNode: null
387     });
388   }
389   bindEdits = (e) => {
390     this.setState({ editModel: e.target.value });
391   }
392   
393   update = (base, source, isInit) => {
394
395         // Assigns the x and y position for the nodes
396         var treeData = base.state.treemap(base.state.root);
397
398         var DSL = GeneralCommonFunctions.populatePathDSL(treeData,true,false,this.state.enableRealTime);
399         console.log(JSON.stringify("DSL :" + DSL));
400
401         this.setState({ dslQuery: DSL });
402
403         // Compute the new tree layout.
404         var nodes = treeData.descendants(),
405             links = treeData.descendants().slice(1);
406
407         var list1 = d3.selectAll(".fa")
408             .filter(".fa-plus")
409             .style("display","block");
410
411         // Normalize for fixed-depth.
412         nodes.forEach(function(d){ d.y = d.depth * 100});
413
414         // ****************** Nodes section ***************************
415
416         // Update the nodes...
417         var node = base.state.g.selectAll('g.node')
418             .data(nodes, function(d) {return d.id });
419
420         // Enter any new modes at the parent's previous position.
421         var nodeEnter = node.enter().append('g')
422             .attr('class', 'node')
423             .attr("transform", function(d) {
424               return "translate(" + source.y0 + "," + source.x0 + ")";
425           })
426          // .on('click', click)
427           .on('dblclick', doubleClick);
428
429         // Add Circle for the nodes
430         nodeEnter.append('circle')
431             .attr('class', 'node')
432             .attr('r', 1e-6)
433             .style("fill", function(d) {
434                 return d.data.details && d.data.details.includeInOutput ? "lightsteelblue" : "#fff";
435             });
436         nodeEnter.append("svg:foreignObject")
437                 .attr("width", 20)
438                 .attr("height", 25)
439                 .attr("y", -14)
440                 .attr("x", -10)
441             .append("xhtml:span")
442                      .attr("class", function (d) {
443                                     let icon = '';
444                                 if(!INVLIST.IS_ONAP){
445                                     icon = 'icon-datanetwork-serverL';
446                                 }else{
447                                     icon = 'browse-fa fa fa-server';
448                                 }
449                                     if(d.data.details && d.data.details.parentContainer){
450                                         var iconKey = ((d.data.details.parentContainer).replace(/-/g, '')).toUpperCase();
451                                         if(INVLIST.INVENTORYLIST[iconKey] && INVLIST.INVENTORYLIST[iconKey].icon){
452                                             return INVLIST.INVENTORYLIST[iconKey].icon;
453                                         }else{
454                                             return icon;
455                                         }
456                                     }else{
457                                         return icon;
458                                     }
459                       })
460                   .style("font-size", function (d) {
461                                       if (!INVLIST.IS_ONAP){
462                                          return "20px";
463                                       } else {
464                                          return "16px";
465                                       }
466                   })
467                  .attr("id", function (d) {return "nodeIcon" + d.id})
468                  .style("color", '#387dff')
469                  .style("display", "block")
470                  .style("padding-top",function(d){
471                                       if (!INVLIST.IS_ONAP){
472                                         return "0px";
473                                       } else {
474                                         return "8px";
475                                       }
476                  });
477
478         nodeEnter.append("svg:foreignObject")
479                 .attr("width", 6)
480                 .attr("height", 6)
481                 .attr("y", 10)
482                 .attr("x", -10)
483                 .on('click', function (d) {
484                     if(d.data.details.isRootNode){
485                         d = null;
486                         base.state.svg.selectAll("*").remove();
487                         base.setState({init: true, dslQuery: '',dslQueryTree:''});
488                     }else{
489                         let dslQueryTree=base.state.dslQueryTree; 
490                         for(var i = 0; d.parent.children && i < d.parent.children.length; i++){
491                             if (d.parent.children.length > 1 && d.data.name === d.parent.children[i].data.name){
492                                 d.parent.children.splice(i, 1);
493                                 dslQueryTree=base.handlingTreeDataWhileAddRemove(dslQueryTree,'',d.data.id,d.data.name);
494                                 base.setState({dslQueryTree:dslQueryTree});
495                             }else if (d.parent.children.length === 1 && d.data.name === d.parent.children[i].data.name){
496                                 d.parent.children = null;
497                             }
498                         }
499                         base.update(base, d);
500                     }
501                 })
502             .append("xhtml:span")
503                      .attr("class", "fa fa-minus")
504                      .style("padding-top", "1px")
505                  .style("font-size", function (d){ return "5px";})
506                  .attr("id", function (d) {return "nodeDelete" + d.id})
507                  .style("color", '#387dff')
508                  .style("display", function (d) {return "block";});
509         nodeEnter.append("svg:foreignObject")
510                          .attr("width", 6)
511                          .attr("height", 6)
512                          .attr("y", 10)
513                          .attr("x", 5)
514                          .on('click', function (d) { add(d)})
515                      .append("xhtml:span")
516                               .attr("class", "fa fa-plus")
517                           .style("font-size", function (d){ return "5px";})
518                           .style("padding-top", "1px")
519                           .attr("id", function (d) {return "nodeAdd" + d.id})
520                           .style("color", '#387dff');
521         nodeEnter.append("svg:foreignObject")
522                                  .attr("width", 6)
523                                  .attr("height", 6)
524                                  .attr("y", -17)
525                                  .attr("x", -10)
526                                  .on('click', function (d) { edit(d)})
527                              .append("xhtml:span")
528                                       .attr("class", "fa fa-pencil-square")
529                                       .style("padding-top", "1px")
530                                   .style("font-size", function (d){ return "5px";})
531                                   .attr("id", function (d) {return "nodeEdit" + d.id})
532                                   .style("color", '#387dff');
533         // Add labels for the nodes
534         nodeEnter.append('text')
535             .attr("dy", ".35em")
536             .attr("x", function(d) {
537                 return d.children ? -13 : 13;
538             })
539             .attr("text-anchor", function(d) {
540                 return d.children ? "end" : "start";
541             })
542             .text(function(d) { return d.data.name; });
543
544         // UPDATE
545         var nodeUpdate = nodeEnter.merge(node);
546         var postNodeDrawnCallBack = function (d){
547           if(!isInit && base.state.autoZoomEnabled  || d.data.details.isRootNode){
548              base.state.zoomFit();
549           }
550         }
551         // Transition to the proper position for the node
552         nodeUpdate.transition()
553           .duration(base.state.duration)
554           .attr("transform", function(d) {
555               return "translate(" + d.y + "," + d.x + ")"
556            }).on("end", postNodeDrawnCallBack);
557
558         // Update the node attributes and style
559         nodeUpdate.select('circle.node')
560           .attr('r', 11)
561           .style("fill", function(d) {
562               return d.data.details && d.data.details.includeInOutput ? "lightsteelblue" : "#fff";
563           })
564           .attr('cursor', 'pointer');
565
566
567         // Remove any exiting nodes
568         var nodeExit = node.exit().transition()
569             .duration(base.state.duration)
570             .attr("transform", function(d) {
571                 return "translate(" + source.y + "," + source.x + ")";
572             })
573             .remove();
574
575         // On exit reduce the node circles size to 0
576         nodeExit.select('circle')
577           .attr('r', 1e-6);
578
579         // On exit reduce the opacity of text labels
580         nodeExit.select('text')
581           .style('fill-opacity', 1e-6);
582
583         // ****************** links section ***************************
584
585         // Update the links...
586         var link = base.state.g.selectAll('path.link')
587             .data(links, function(d) { return d.id; });
588
589         // Enter any new links at the parent's previous position.
590         var linkEnter = link.enter().insert('path', "g")
591             .attr("class", "link")
592             .attr('d', function(d){
593               var o = {x: source.x0, y: source.y0}
594               return diagonal(o, o)
595             });
596
597         // UPDATE
598         var linkUpdate = linkEnter.merge(link);
599
600         // Transition back to the parent element position
601         linkUpdate.transition()
602             .duration(base.state.duration)
603             .attr('d', function(d){ return diagonal(d, d.parent) });
604
605         // Remove any exiting links
606         var linkExit = link.exit().transition()
607             .duration(base.state.duration)
608             .attr('d', function(d) {
609               var o = {x: source.x, y: source.y}
610               return diagonal(o, o)
611             })
612             .remove();
613
614         // Store the old positions for transition.
615         nodes.forEach(function(d){
616           d.x0 = d.x;
617           d.y0 = d.y;
618         });
619
620         // Creates a curved (diagonal) path from parent to the child nodes
621         function diagonal(s, d) {
622           var path = 'M ' + s.y + ' ' + s.x + ' C ' + ((s.y + d.y) / 2) + ' ' + s.x + ' ' +  (s.y + d.y) / 2 + ' ' + d.x + ' ' + d.y + ' ' + d.x;
623           return path
624         }
625         base.state.svg.on("dblclick.zoom", null);
626         // Toggle children on click.
627         function add(d){
628             base.populateEdgeRules(d.data.name,base.state.edgeRules);
629             if(!d.children){
630               d.children = [];
631               d.data.children = [];
632             }
633             base.setState({
634               selectedNode: d,
635               showNodeModal: true
636             });
637
638         }
639         function edit(d){
640             console.log("object editing: " + d);
641             var nodeDetails = base.state.nodeDetails;
642             //set up node details to have the node to edit
643             nodeDetails[0] = d.data.details;
644             base.setState({
645               selectedNode: d,
646               showEditNodeModal: true
647             });
648         }
649         function doubleClick(d) {
650             edit(d);
651         }
652       }
653   selectAll = (nodeKey) =>{//delete
654     var nodeDetails = this.state.nodeDetails;
655     for (var key in nodeDetails[nodeKey].attrDetails) {
656         nodeDetails[nodeKey].attrDetails[key].isSelected = true;
657     }
658     this.setState({nodeDetails: nodeDetails});
659   }
660   deselectAll = (nodeKey) =>{//delete
661     var nodeDetails = this.state.nodeDetails;
662     for (var key in nodeDetails[nodeKey].attrDetails) {
663         nodeDetails[nodeKey].attrDetails[key].isSelected = false;
664     }
665     this.setState({nodeDetails: nodeDetails});
666   }
667   build = (type, propID, attrDetails,preBuiltTree) =>{
668     console.log('build>>>>>>>>',type);
669     var selected = null;
670     var treeData =
671       {
672         "name": "complex",
673         "id": "complex",
674         "children": []
675       };
676     if(!preBuiltTree  && type && (propID || attrDetails)){
677         let nodeType =  type;
678         treeData = {
679             "name": nodeType,
680             "id": nodeType,
681             "children": [],
682             "details":{}
683         }
684         treeData.details.includeInOutput = true;
685         treeData.details.isSelected = true;
686         treeData.details.isRootNode = true;
687         treeData.details.nodeType = nodeType;
688         if(attrDetails){
689             treeData.details.attrDetails = attrDetails;
690         } else{
691             treeData.details.attrDetails = {};
692         }
693         if(propID){
694             let propIds = (propID) ? propID.split(';') : '';
695             let propertyValue = '';
696             for(var i  in propIds){
697                 let propValue = propIds[i].split(':');
698                 console.log(propValue[0] + '....' + propValue[1]);
699                 treeData.details.attrDetails[propValue[0]] = {};
700                 treeData.details.attrDetails[propValue[0]].filterValue=[];
701                 treeData.details.attrDetails[propValue[0]].filterValue.push(atob(propValue[1]).replace('<pre>','').replace('</pre>',''));
702                 treeData.details.attrDetails[propValue[0]].attributeName = propValue[0];
703                 treeData.details.attrDetails[propValue[0]].isSelected = true;
704             }
705         }
706     }else if (preBuiltTree){
707         treeData = preBuiltTree;
708     }
709
710     // append the svg object to the body of the page
711     // appends a 'group' element to 'svg'
712     // moves the 'group' element to the top left margin
713     var svg = d3.select("#PathDSLBuilder");
714     // Set the dimensions and margins of the diagram
715     var margin = {top: 20, right: 120, bottom: 20, left: 120},
716            width = +svg.attr("width") - margin.right - margin.left,
717            height = +svg.attr("height") - margin.top - margin.bottom;
718
719     var g = svg.append("g")
720         .attr("transform", "translate("
721               + margin.left + "," + margin.top + ")");
722
723     var duration = 750,
724         root;
725
726     // declares a tree layout and assigns the size
727     var treemap = d3.tree().size([height - 200, width]);
728     // Assigns parent, children, height, depth
729     root = d3.hierarchy(treeData, function(d) { return d.children; });
730     root.x0 = height / 2;
731     root.y0 = 0;
732
733     //Zoom functions
734     function zoom_actions(){
735         g.attr("transform", d3.event.transform)
736     }
737     //add zoom capabilities
738     var zoom_handler = d3.zoom()
739         .on("zoom", zoom_actions);
740
741     zoom_handler(svg);
742
743     function zoomFit() {
744       var bounds = g.node().getBBox();
745       var parent = g.node().parentElement;
746       var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
747           fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
748       var width = bounds.width,
749           height = bounds.height;
750       var midX = bounds.x + width / 2,
751           midY = bounds.y + height / 2;
752       if (width == 0 || height == 0) return; // nothing to fit
753       var scale = Math.min((0.95 / Math.max(width / fullWidth, height / fullHeight)), 2);
754       var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
755
756       var transform = d3.zoomIdentity
757           .translate(80, translate[1])
758           .scale(scale);
759      svg.transition().duration(350)
760         .call(zoom_handler.transform, transform);
761
762     }
763
764     //Set Default zoom
765     svg.call(zoom_handler)
766     .call(zoom_handler.transform, d3.zoomIdentity.translate(80, -500).scale(2));
767     this.setState({
768             init: false,
769                 svg: svg,
770                 g: g,
771                 treemap: treemap,
772                 root: root,
773                 duration: duration,
774             zoomFit: zoomFit,
775             dslQueryTree: treeData
776         }, ()=>{this.update(this, root, true);})
777
778     // Collapse the node and all it's children
779     function collapse(d) {
780       if(d.children) {
781         d.children.forEach(collapse)
782         d.children = null
783       }
784     }
785
786
787   }
788   onTargetMenuOfFilterTypes=(listname,id)=>{
789     console.log(listname+'onTargetMenuOfFilterTypes',id);
790     let keysOfArray=id.split('#');
791     let nodekey=keysOfArray[0];
792     let attrKey=keysOfArray[1];
793     let indx=parseInt(keysOfArray[2]);
794     let nodeDetails = this.state.nodeDetails;
795     let node = nodeDetails[nodekey];
796     if(!node.attrDetails){
797         node.attrDetails = [];
798     }
799     if(!node.attrDetails[attrKey]){
800         node.attrDetails[attrKey] = {};
801         node.attrDetails[attrKey].isSelected = true;
802         node.attrDetails[attrKey].filterValue = [];
803         node.attrDetails[attrKey].filterType = [];   
804     }else{
805         let filterTypes=node.attrDetails[attrKey].filterType;
806         filterTypes[indx]=listname;
807         node.attrDetails[attrKey].filterType=filterTypes;
808     }    
809     nodeDetails[nodekey] = node;
810     // update the state with the new array of traverse to nodes
811     this.setState({ nodeDetails: nodeDetails });
812   };
813   filterTags = (key,property,state) =>{
814     let filterTags ='';
815     let filters='';
816     state=true;//always enable, in future if wants to disable remove this line
817     if(APERTURE_SERVICE && this.state.enableRealTime){
818         let nodeDetails = this.state.nodeDetails;
819         let node = nodeDetails[key];
820         filterTags= Object.keys(Object.keys(node.attrDetails[property].filterType)).map((indx) =>{
821                     let selectedFilter=(node.attrDetails[property].filterType[indx]!=='')?node.attrDetails[property].filterType[indx]:this.state.filterTypeDisplay;
822                     return <div style={{margin:'0px 0px 0px 5px'}}>
823                         <label>
824                             <FilterTypes param={this.state}
825                             selectedFilter={selectedFilter}
826                             id={key+'#'+property+'#'+indx}
827                             onMenuSelect={this.onTargetMenuOfFilterTypes}
828                             state={!state}/>
829                         </label>
830                         </div>
831                     });
832         filters= <Col md={4} className='removeLeftPadding'>{filterTags}</Col>;
833     }
834     return filters;
835   };
836   addOrTemplate=(nodeKey,attrKey,indx)=>{
837     let nodeDetails = this.state.nodeDetails;
838     let node = nodeDetails[nodeKey];
839     node.attrDetails[attrKey].filterValue.push('');
840     node.attrDetails[attrKey].filterType.push('EQ');
841     nodeDetails[nodeKey] = node;
842     // update the state with the new array of traverse to nodes
843     this.setState({ nodeDetails: nodeDetails });    
844   };
845   deleteOrTemplate=(nodeKey,attrKey,index)=>{
846     let nodeDetails = this.state.nodeDetails;
847     let node = nodeDetails[nodeKey];
848     let filterValuesArray=node.attrDetails[attrKey].filterValue;
849     let filterTypeArray=node.attrDetails[attrKey].filterType;
850     filterValuesArray.splice(index,1);
851     filterTypeArray.splice(index,1);
852     node.attrDetails[attrKey].filterValue=filterValuesArray;
853     node.attrDetails[attrKey].filterType=filterTypeArray;
854     nodeDetails[nodeKey] = node;
855     this.setState({ nodeDetails: nodeDetails });
856   }
857   render(){   
858     return(
859         <div id='pathFilterDSLModel'>            
860             <div className="addPadding">                
861                 <div className={'row ' + (!this.state.init ? 'show' : 'hidden')}>
862                     <div className="checkbox" style={{float:'left',width:'70%'}}>
863                         <label>
864                             <input type="checkbox" checked={this.state.autoZoomEnabled} onChange={this.onAutoZoomCheckbox.bind(this)}/>
865                             Auto Zoom Enabled
866                         </label>
867                     </div>
868                     <div style={{float:'right'}}> 
869                         <Button onClick={this.props.closePathNodeModal}>Close</Button>
870                         <Button onClick={this.submitPathNodeModal} disabled={(this.state.dslQuery === '')}>Submit</Button> 
871                     </div> 
872                 </div>
873                 <div className={'row ' + (!this.state.init ? 'show' : 'hidden')}>
874                     <div style={{fontWeight:'bold'}}>
875                         <span>DSL PATH Query :</span> {this.state.dslQuery}
876                     </div>                                       
877                 </div>
878                 <div className={'row ' + ((this.state.dslQuery != '') ? 'hidden' : 'show')}>
879                     <div style={{float:'left'}}>
880                         <button className='btn btn-primary' type='button' onClick={this.initialLoadWhileClose}>Start Building (+)</button>
881                     </div>
882                     <div style={{float:'right'}}> 
883                         <Button onClick={this.props.closePathNodeModal}>Close</Button>
884                         <Button onClick={this.submitPathNodeModal} disabled={(this.state.dslQuery === '')}>Submit</Button> 
885                     </div> 
886                 </div>                                
887             </div>
888             <svg id='PathDSLBuilder' width='1800' height='800'></svg>     
889             <div className='static-modal' id='customDslPathBuilderModel'>
890                         <Modal show={this.state.showNodeModal} onHide={this.closeNodeModal}>
891                                 <Modal.Header>
892                                         <Modal.Title>Modify Dsl Path Query</Modal.Title>
893                                 </Modal.Header>
894                                 <Modal.Body>
895                           <form>
896                                {Object.keys(this.state.nodeDetails).sort().map((key, node) => (
897                                     <div className="dsl-panel">
898                                        <Panel>
899                                          <Panel.Heading>
900                                            <Panel.Title>
901                                              <div className={'checkbox ' + (!this.state.init ? 'show' : 'hidden')}>
902                                                 <label>
903                                                   <input type="checkbox" checked={this.state.nodeDetails[key].isSelected} value={key} onChange={this.onNodeCheckbox.bind(this)} />
904                                                   {this.state.nodeDetails[key].nodeType}
905                                                 </label>
906                                                 <Panel.Toggle>
907                                                   <div className="pull-right">Options</div>
908                                                 </Panel.Toggle>
909                                              </div>
910                                              <div className={'form-check ' + (this.state.init ? 'show' : 'hidden')}>
911                                                 <label className="form-check-label">
912                                                   <input className="form-check-input" type="radio" value={key} checked={this.state.nodeDetails[key].isSelected} onChange={this.onNodeRadio.bind(this)} />
913                                                   {" " + this.state.nodeDetails[key].nodeType}
914                                                 </label>
915                                                 <Panel.Toggle>
916                                                   <div className="pull-right">Options</div>
917                                                 </Panel.Toggle>
918                                              </div>
919                                            </Panel.Title>
920                                          </Panel.Heading>
921                                          <Panel.Collapse>
922                                            <Panel.Body className='cardwrap'>                                                                                                                                                                               
923                                              <Grid fluid={true} className='addPaddingTop'>
924                                                 <Row className='show-grid addPaddingTop'>
925                                                    <Col md={(this.state.enableRealTime)?4:6}>
926                                                      <strong>PROPERTIES</strong>
927                                                    </Col>
928                                                    {this.state.enableRealTime && <Col md={4} className='removeLeftPadding'>
929                                                      <strong>Filter Types</strong>
930                                                    </Col>}
931                                                    <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
932                                                       <strong>Filter By (Optional)</strong>
933                                                    </Col>
934                                                 </Row>
935                                              {Object.keys(this.state.nodeDetails[key].attrDetails).sort().map((attrKey, attr) => {
936                                                 return(
937                                                        <Row className='show-grid'>
938                                                           <Col md={(this.state.enableRealTime)?4:6}>
939                                                            <div className="checkbox">
940                                                                <label>
941                                                                  {attrKey}
942                                                                </label>
943                                                             </div>
944                                                           </Col>
945                                                           {this.filterTags(key,attrKey,this.state.nodeDetails[key].attrDetails[attrKey].isSelected)}
946                                                           <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
947                                                           {Object.keys(this.state.nodeDetails[key].attrDetails[attrKey].filterValue).map((indx) =>{
948                                                             return(
949                                                                 <div>
950                                                                                                         {this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] ==='' && <input type="text" 
951                                                                         placeholder={"Enter " + attrKey }
952                                                                         className='inputFilter'
953                                                                         onBlur={(e)=>{this.onFilterValueChange(e, key, attrKey,indx);}}
954                                                                         />
955                                                                     }
956                                                                     {this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] !=='' && <input type="text" 
957                                                                         onChange={(e)=>{this.onFilterValueChange(e, key, attrKey,indx);}} 
958                                                                         placeholder={"Enter " + attrKey }
959                                                                         className='inputFilter'
960                                                                         value={this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx]}
961                                                                         />
962                                                                     }
963                                                                     {indx == 0 && <button 
964                                                                         className={(this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] !=='')?'btn btn-primary':'btn btn-secondary'} 
965                                                                         style={{padding:'2px',margin:'0px 0px 7px 3px'}} 
966                                                                         disabled={this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx]===''} 
967                                                                         type='button' 
968                                                                         onClick={e => {this.addOrTemplate(key,attrKey,indx)}}>+</button>}
969                                                                     {indx > 0 && <button
970                                                                         style={{padding:'2px',margin:'0px 0px 7px 3px'}}
971                                                                         id={'delete-'+indx}
972                                                                         className='btn btn-danger'
973                                                                         type='button'
974                                                                         onClick={e => {this.deleteOrTemplate(key,attrKey,indx)}}>x</button>}
975
976                                                                 </div>
977                                                             )
978                                                           })}
979                                                           </Col>
980                                                        </Row>
981                                                 );
982                                               }
983                                              )}
984                                              </Grid>                                                                                         
985                                            </Panel.Body>
986                                          </Panel.Collapse>
987                                        </Panel>
988                                     </div>
989                                ))}
990                              </form>
991                                 </Modal.Body>
992                                 <Modal.Footer>
993                                         <Button onClick={this.closeNodeModal}>Close</Button>
994                                         <Button onClick={this.submitNodeModal}>Submit</Button>
995                                 </Modal.Footer>
996                         </Modal>
997                 </div>
998                 <div className='static-modal' id='editNodeModel'>
999                         <Modal show={this.state.showEditNodeModal} onHide={this.closeEditNodeModal}>
1000                                 <Modal.Header>
1001                                         <Modal.Title>Modify Node</Modal.Title>
1002                                 </Modal.Header>
1003                                 <Modal.Body>
1004                           <form>
1005                             <div className="dsl-panel">
1006                                <Panel>
1007                                  <Panel.Heading>
1008                                    <Panel.Title>
1009                                      <div>
1010                                         <label>{this.state.selectedNode
1011                                                 && this.state.selectedNode.data
1012                                                 && this.state.selectedNode.data.details ?
1013                                                 this.state.selectedNode.data.details.nodeType
1014                                                 : ""
1015                                                }
1016                                         </label>
1017                                      </div>
1018                                    </Panel.Title>
1019                                  </Panel.Heading>
1020                                  <Panel.Body className='cardwrap'>                                  
1021                                    <Grid fluid={true} className='addPaddingTop'>
1022                                       <Row className='show-grid addPaddingTop'>
1023                                          <Col md={(this.state.enableRealTime)?4:6}>
1024                                            <strong>Include in Output</strong>
1025                                          </Col>
1026                                          {this.state.enableRealTime && <Col md={4} className='removeLeftPadding'>
1027                                            <strong>Filter Types</strong>
1028                                          </Col>}
1029                                          <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1030                                             <strong>Filter By (Optional)</strong>
1031                                          </Col>
1032                                       </Row>
1033                                    {this.state.selectedNode
1034                                         && this.state.selectedNode.data
1035                                         && this.state.selectedNode.data.details
1036                                         && this.state.nodeDetails[0]
1037                                         && Object.keys(this.state.nodeDetails[0].attrDetails).sort().map((attrKey, attr) => {
1038                                       return(
1039                                              <Row className='show-grid'>
1040                                                 <Col md={(this.state.enableRealTime)?4:6}>
1041                                                  <div className="checkbox">
1042                                                      <label>                                                      
1043                                                        {attrKey}
1044                                                      </label>
1045                                                   </div>
1046                                                 </Col>
1047                                                 {this.filterTags(0,attrKey, this.state.nodeDetails[0].attrDetails[attrKey].isSelected)}
1048                                                 <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1049                                                 {Object.keys(this.state.nodeDetails[0].attrDetails[attrKey].filterValue).map((indx) =>{
1050                                                   return(
1051                                                       <div>
1052                                                           
1053                                                           {this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] ==='' && <input type="text"
1054                                                               placeholder={"Enter " + attrKey }
1055                                                               className='inputFilter'
1056                                                               onBlur={(e)=>{this.onFilterValueChange(e, 0, attrKey, indx);}}
1057                                                               />
1058                                                           }
1059                                                           {this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] !=='' && <input type="text"
1060                                                               onChange={(e)=>{this.onFilterValueChange(e, 0, attrKey,indx);}}
1061                                                               placeholder={"Enter " + attrKey }
1062                                                               className='inputFilter'
1063                                                               value={this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]}
1064                                                               />
1065                                                           }
1066                                                           {indx == 0 && <button
1067                                                               className={(this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]!=='')?'btn btn-primary':'btn btn-secondary'}
1068                                                               style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1069                                                               disabled={this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]===''}
1070                                                               type='button'
1071                                                               onClick={e => {this.addOrTemplate(0 ,attrKey,indx)}}>+</button>}
1072                                                           {indx > 0 && <button
1073                                                               style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1074                                                               id={'delete-'+indx}
1075                                                               className='btn btn-danger'
1076                                                               type='button'
1077                                                               onClick={e => {this.deleteOrTemplate(0 ,attrKey,indx)}}>x</button>}
1078
1079                                                       </div>
1080                                                   )
1081                                                 })}
1082
1083                                                 </Col>
1084                                              </Row>
1085                                       );
1086                                     }
1087                                    )}
1088                                    </Grid>
1089                                  </Panel.Body>
1090                                </Panel>
1091                             </div>
1092                           </form>                          
1093                                 </Modal.Body>
1094                                 <Modal.Footer>
1095                                         <Button onClick={this.closeEditNodeModal}>Close</Button>
1096                                         <Button onClick={this.submitEditNodeModal}>Submit</Button>
1097                                 </Modal.Footer>
1098                         </Modal>
1099                 </div>                  
1100         </div>
1101         );
1102   }
1103 }
1104
1105 export default PathFilterDslBuilder;