2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 import React, {Component} from 'react';
22 import commonApi from 'utils/CommonAPIService.js';
23 import {GeneralCommonFunctions} from 'utils/GeneralCommonFunctions.js';
24 import Modal from 'react-bootstrap/lib/Modal';
25 import Grid from 'react-bootstrap/lib/Grid';
26 import FormGroup from 'react-bootstrap/lib/FormGroup';
27 import FormControl from 'react-bootstrap/lib/FormControl';
28 import ControlLabel from 'react-bootstrap/lib/ControlLabel';
29 import Button from 'react-bootstrap/lib/Button';
30 import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
31 import Spinner from 'utils/SpinnerContainer.jsx';
32 import Row from 'react-bootstrap/lib/Row';
33 import Col from 'react-bootstrap/lib/Col';
34 import Panel from 'react-bootstrap/lib/Panel';
35 import Tooltip from 'react-bootstrap/lib/Tooltip';
36 import FilterTypes from 'generic-components/filter/components/FilterTypes.jsx';
37 import PathFilterDslBuilder from './PathFilterDslBuilder.jsx';
38 import CustomDSLSaveLoad from 'app/byoq/CustomDSLSaveLoad.jsx';
39 import BootstrapSwitchButton from 'bootstrap-switch-button-react';
40 import * as d3 from "d3";
41 import 'd3-selection-multi';
44 let EDGERULES = GlobalExtConstants.EDGERULES;
45 let OXM = GlobalExtConstants.OXM;
46 let INVLIST = GlobalExtConstants.INVLIST;
47 let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT;
48 let APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
52 let properties = null;
53 let traverseRulesDsl = [];
56 'NODESERVER': INVLIST.NODESERVER,
57 'PROXY': INVLIST.PROXY,
58 'PREFIX': INVLIST.PREFIX,
59 'VERSION': INVLIST.VERSION,
60 'APERTURE': INVLIST.APERTURE,
61 'USESTUBS': INVLIST.useStubs
63 class CustomDslBuilder extends Component {
65 console.log('props>>>>',props);
67 this.saveLoadComponent = React.createRef();
68 APERTURE_SERVICE=JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE'));
69 this.state = {edgeRules : null,
72 enableModalFeedback: false,
73 showEditNodeModal: false,
81 traverseToNodeAttributes: [],
87 autoZoomEnabled: true,
88 aggregateObjects: false,
90 filterTypeDisplay: 'Filter Type',
91 selectedfilterType:[],
93 initialRootEdit: true,
94 showPathFilterDslBuilder: false,
95 pathFilterNodeType: '',
96 pathFilterNodeName:'',
97 pathFIlterAttrDetails: [],
101 queryDescription: '',
108 isDataSteward: sessionStorage.getItem(ENVIRONMENT + 'roles') && sessionStorage.getItem(ENVIRONMENT + 'roles').indexOf('data_steward_ui_view') > -1,
109 isPublicChecked: sessionStorage.getItem(ENVIRONMENT + 'roles') && sessionStorage.getItem(ENVIRONMENT + 'roles').indexOf('data_steward_ui_view') > -1,
110 enableRealTime: JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'ENABLE_ANALYSIS'))
112 this.baseState=this.state;
114 componentDidMount () {
115 console.log('componentDidMount',JSON.stringify(this.props));
116 //this.buildSQLStatementsFromSchema();
117 this.processEdgeRules(EDGERULES);
118 if(this.props.match.params.type && this.props.match.params.propId) {
119 this.build(this.props.match.params.type, this.props.match.params.propId);
123 this.setState({enableModalFeedback: true}, function () {
124 //console.log("EnableModalFeedback: " + this.state.enableModalFeedback);
125 setTimeout(() => {this.postSpinner()},1);
129 postSpinner = () => {
131 var nodeDetails = [];
133 console.log('initializing');
134 var id = GeneralCommonFunctions.generateID();
135 var nodeTypes = GeneralCommonFunctions.getNodeTypes();
136 for (var i = 0; i < nodeTypes.length; i++) {
137 node = nodeTypes[i] + id;
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]);
147 let nodesSorted = nodeDetails.sort(function (filter1, filter2) {
148 if (filter1.nodeType < filter2.nodeType) {
150 } else if (filter1.nodeType > filter2.nodeType) {
156 //console.log('Node Types List' + JSON.stringify(nodesSorted));
157 nodeDetails = nodesSorted;
158 this.setState({nodeDetails: nodeDetails, showNodeModal: true, enableModalFeedback: false});
160 processEdgeRules = (data) => {
162 edgeRules: data.rules
163 },()=>{this.baseState=this.state});
165 closeNodeModal = () =>{
167 showNodeModal: false,
168 enableModalFeedback: false,
173 closeEditNodeModal = () =>{
175 showEditNodeModal: false,
177 showPathFilterDslBuilder: false
180 closePathNodeModal = () =>{
181 console.log('closePathNodeModal>>>>>>>');
183 showPathFilterDslBuilder: false,
184 pathFilterNodeType: '',
185 pathFilterNodeName:'',
186 pathFIlterAttrDetails: []
189 submitPathNodeModal = (dslQuery,nodetype,dslQueryTree,isEditEnable,pathFilterIndex) =>{
190 console.log('CustomDSLBuilder submitPathNodeModel>>>>>dslQuery ###',dslQuery);
191 console.log(isEditEnable+'<<submitPathNodeModal this.state.nodeDetails>>>>',this.state.nodeDetails)
192 var nodeDetails = this.state.nodeDetails;
193 if(!nodeDetails[nodetype].dslPath){
194 nodeDetails[nodetype].dslPath=[];
195 nodeDetails[nodetype].dslPathTree=[];
198 nodeDetails[nodetype].dslPath[pathFilterIndex]=dslQuery;
199 nodeDetails[nodetype].dslPathTree[pathFilterIndex]=dslQueryTree;
200 console.log('nodeDetails on edit>>>>>>>>>',nodeDetails);
202 nodeDetails[nodetype].dslPath.push(dslQuery);
203 nodeDetails[nodetype].dslPathTree.push(dslQueryTree);
205 this.setState({ nodeDetails: nodeDetails },()=>{this.closePathNodeModal()});
207 editPathNodeModal = (key,path,tree,indx) =>{
208 console.log('editPathNodeModal>>>>>>>>>###',indx);
209 let attrDetails=this.state.nodeDetails[key].attrDetails;
210 let nodeType=this.state.nodeDetails[key].nodeType;
211 this.setState({showPathFilterDslBuilder: true,pathFilterNodeType: key,pathFilterNodeName:nodeType,pathFIlterAttrDetails: '',dslPathBuilder: path,dslPathTree:tree,isEditEnable:true,pathFilterIndex:indx});
213 deletePathNodeModal = (key,path,tree,index) =>{
214 console.log(index+'<<deletePathNodeModal>>>>>',key);
215 var nodeDetails = this.state.nodeDetails;
216 nodeDetails[key].dslPath.splice(index,1);
217 nodeDetails[key].dslPathTree.splice(index,1);
218 this.setState({ nodeDetails: nodeDetails });
221 var nodeDetails = this.state.nodeDetails;
222 if (e.target.checked) {
223 nodeDetails[e.target.value].isSelected = true;
224 this.selectAll(e.target.value);
226 nodeDetails[e.target.value].isSelected = false;
227 this.deselectAll(e.target.value);
229 // update the state with the new array of traverse to nodes
230 this.setState({ nodeDetails: nodeDetails });
233 var nodeDetails = this.state.nodeDetails;
234 if (e.target.checked) {
235 nodeDetails[e.target.value].isSelected = true;
236 this.selectAll(e.target.value);
238 for (var key in nodeDetails) {
239 if(key != e.target.value && nodeDetails[key].isSelected ){
240 nodeDetails[key].isSelected = false;
241 this.deselectAll(key);
244 // update the state with the new array of traverse to nodes
245 this.setState({ nodeDetails: nodeDetails });
247 onAutoZoomCheckbox(e) {
249 if (e.target.checked) {
254 this.setState({ autoZoomEnabled: cbValue });
256 onAggregateCheckbox(e) {
258 if (e.target.checked) {
263 this.setState({ aggregateObjects: cbValue });
265 onAttributeCheckbox(e){
266 let splitVal = e.target.value.split("|");
267 let nodeKey = splitVal[0];
268 let attrValue = splitVal[1];
269 let nodeDetails = this.state.nodeDetails;
270 let node = nodeDetails[nodeKey];
271 let attribute = null;
272 if(!node.attrDetails){
273 node.attrDetails = [];
275 if(!node.attrDetails[attrValue]){
276 node.attrDetails[attrValue] = {};
277 node.attrDetails[attrValue].isSelected = true;
278 node.attrDetails[attrValue].filterValue = [];
279 node.attrDetails[attrValue].filterType = [];
280 node.attrDetails[attrValue].dslPath = [];
281 node.attrDetails[attrValue].dslPathTree = [];
284 // check if the check box is checked or unchecked
285 if (e.target.checked) {
286 // add the value of the checkbox to nodes array
287 node.attrDetails[attrValue].isSelected = true;
288 node.attrDetails[attrValue].filterType[0]='EQ';
290 // or remove the value from the unchecked checkbox from the array
291 node.attrDetails[attrValue].isSelected = false;
292 //node.attrDetails[attrValue].filterType = [''];
293 //node.attrDetails[attrValue].filterValue = [''];
295 nodeDetails[nodeKey] = node;
296 // update the state with the new array of traverse to nodes
297 this.setState({ nodeDetails: nodeDetails });
299 onFilterValueChange(e, nodeKey, attrKey, indx){
300 let nodeDetails = this.state.nodeDetails;
301 let node = nodeDetails[nodeKey];
302 if(!node.attrDetails){
303 node.attrDetails = [];
305 if(!node.attrDetails[attrKey]){
306 node.attrDetails[attrKey] = {};
307 node.attrDetails[attrKey].isSelected = true;
308 node.attrDetails[attrKey].filterValue = [];
309 node.attrDetails[attrKey].filterType = [];
310 node.attrDetails[attrValue].dslPath = [];
311 node.attrDetails[attrValue].dslPathTree = [];
313 // add the value of the checkbox to nodes array
314 //node.attrDetails[attrKey].filterValue.push(e.target.value);
315 let filterValArr=node.attrDetails[attrKey].filterValue;
316 filterValArr[indx]=e.target.value;
317 node.attrDetails[attrKey].filterValue=filterValArr;
318 nodeDetails[nodeKey] = node;
319 // update the state with the new array of traverse to nodes
320 this.setState({ nodeDetails: nodeDetails });
322 submitNodeModal = () =>{
323 if(this.state.selectedNode){
324 var d = this.state.selectedNode;
325 for(var node in this.state.nodeDetails){
326 if(this.state.nodeDetails[node].isSelected){
329 name: this.state.nodeDetails[node].nodeType,
333 Object.assign(newNodeObj.details, this.state.nodeDetails[node]);
334 var newNode = d3.hierarchy(newNodeObj);
335 newNode.depth = d.depth + 1;
336 newNode.height = d.height - 1;
342 if(newNodeObj.details){
343 var selectedAttributeCount = 0;
344 for (var key in newNodeObj.details.attrDetails){
345 if (newNodeObj.details.attrDetails[key].isSelected){
346 selectedAttributeCount++;
348 if(selectedAttributeCount === Object.keys(newNodeObj.details.attrDetails).length){
349 newNodeObj.details.includeInOutput = true;
353 d.children.push(newNode);
354 this.setState({ nodeDetails: [] });
357 this.update(this, d);
359 showNodeModal: false,
360 enableModalFeedback: false,
366 var attrDetails = null;
369 for (var key in this.state.nodeDetails) {
370 if(this.state.nodeDetails[key].isSelected){
371 nodeType = this.state.nodeDetails[key].nodeType;
372 attrDetails = this.state.nodeDetails[key].attrDetails;
373 dslPath =this.state.nodeDetails[key].dslPath;
374 dslPathTree=this.state.nodeDetails[key].dslPathTree;
377 this.build(nodeType, null, attrDetails,null,dslPath,dslPathTree);
378 this.setState({ nodeDetails: [], showNodeModal: false, enableModalFeedback:false, traverseToNodes: [], selectedNode: null });
381 submitEditNodeModal = () =>{
382 this.update(this, this.state.selectedNode);
383 this.setState({showEditNodeModal: false,showPathFilterDslBuilder:false});
385 populateEdgeRules = (nodeType) => {
386 let nodeDetails=GeneralCommonFunctions.populateEdgeRules(nodeType,this.state.edgeRules);
388 nodeDetails: nodeDetails
392 buildOXMAttributesAndReturn = (nodeType) =>{
394 var result = JSON.parse(OXM);
395 var arrayOfTypes = result['xml-bindings']['java-types'][0]['java-type'];
396 for (var i = 0; i < arrayOfTypes.length; i++) {
397 var propertiesDsl = [];
398 for (var j = 0; j < arrayOfTypes[i]['java-attributes'][0]['xml-element'].length; j++) {
399 let property = arrayOfTypes[i]['java-attributes'][0]['xml-element'][j]['$']['name'];
400 let type = arrayOfTypes[i]['java-attributes'][0]['xml-element'][j]['$']['type'];
401 if (type === 'java.lang.String' || type === 'java.lang.Boolean') {
402 propertiesDsl[property] = {};
403 propertiesDsl[property].isSelected = false;
404 propertiesDsl[property].attributeName = property;
405 propertiesDsl[property].filterValue = [''];
406 propertiesDsl[property].filterType = [''];
407 propertiesDsl[property].dslPath = [];
408 propertiesDsl[property].dslPathTree = [];
411 let sortedPropertiesDsl = propertiesDsl.sort(function (filter1, filter2) {
412 if (filter1.attributeName < filter2.attributeName) {
414 } else if (filter1.attributeName > filter2.attributeName) {
420 oxmArray[GeneralCommonFunctions.camelToDash(arrayOfTypes[i]['xml-root-element'][0]['$']['name'])] = sortedPropertiesDsl;
422 this.setState({oxmMapping: oxmArray});
423 return oxmArray[nodeType];
427 console.log("running DSL");
428 let paramToPassThrough = '';
429 if(this.state.aggregateObjects){
430 paramToPassThrough = '/customDsl/built-aggregate/' + btoa('<pre>' + this.state.dslQuery + '</pre>');
432 paramToPassThrough = '/customDsl/built/' + btoa('<pre>' + this.state.dslQuery + '</pre>');
434 this.props.history.push(paramToPassThrough);
436 submitEditAndRunDSL = () =>{
437 this.setState({ dslQuery: this.state.editModel }, () => this.runDSL());
439 showEditDSLModal = () => {
440 console.log("enabling DSL edit modal");
441 this.setState({ editModel: this.state.dslQuery, showEditModal: true });
443 closeEditDSLModal = () => {
444 console.log("closing DSL edit modal");
445 this.setState({ showEditModal: false });
448 this.setState({ editModel: e.target.value });
450 populateDSL = (tree, isInit) =>{
453 var treeArrayLength = 0;
458 treeArray = tree.children;
459 treeArrayLength = tree.children.length;
461 for(var k = 0; treeArray && k < treeArrayLength; k++){
462 if(k === 0 && treeArrayLength > 1){
472 console.log('Node data while rendering DSl path>>',JSON.stringify(node.data));
473 DSL += node.data.name;
475 if(node.data.details){
476 var tempAttributeString = '';
477 var selectedAttributeCount = 0;
478 for (var key in node.data.details.attrDetails){
479 if (node.data.details.attrDetails[key].isSelected){
480 selectedAttributeCount++;
481 let aliasWithProp=node.data.details.attrDetails[key].attributeName;
482 if(node.data.details.attrDetails[key].alias){
483 aliasWithProp= aliasWithProp+'\' as \''+node.data.details.attrDetails[key].alias;
485 if(selectedAttributeCount === 1){
486 tempAttributeString += '{\'' + aliasWithProp +'\'';
489 tempAttributeString += ',\'' + aliasWithProp + '\'';
493 if(selectedAttributeCount === Object.keys(node.data.details.attrDetails).length){
496 if((selectedAttributeCount < Object.keys(node.data.details.attrDetails).length) && propState){
497 DSL += tempAttributeString + '}';
499 for (var key in node.data.details.attrDetails){
500 if(node.data.details.attrDetails[key].filterValue && node.data.details.attrDetails[key].filterValue[0] !==''){
501 DSL += '(\'' + node.data.details.attrDetails[key].attributeName + '\',';
503 for(var indx=0; indx<node.data.details.attrDetails[key].filterValue.length; indx++){
504 dslValues=(indx>0) ? dslValues+',':dslValues;
505 if(this.state.enableRealTime && node.data.details.attrDetails[key].filterType && node.data.details.attrDetails[key].filterType[indx]){
506 dslValues += node.data.details.attrDetails[key].filterType[indx]+'(\''+ node.data.details.attrDetails[key].filterValue[indx] + '\')';
508 dslValues +='\''+node.data.details.attrDetails[key].filterValue[indx] + '\'';
510 if(node.data.details.attrDetails[key].filterValue.length-1 === indx){
517 if(node.data.details.dslPath && node.data.details.dslPath.length>0){
518 for(var n in node.data.details.dslPath){
519 DSL += node.data.details.dslPath[n];
525 DSL+= '>' + this.populateDSL(node);
527 if(k !== treeArrayLength - 1){
530 if(k === treeArrayLength - 1 && treeArrayLength > 1){
536 update = (base, source, isInit) => {
538 // Assigns the x and y position for the nodes
539 var treeData = base.state.treemap(base.state.root);
541 var DSL = base.populateDSL(treeData, true);
542 console.log(JSON.stringify("DSL :" + DSL));
544 this.setState({ dslQuery: DSL });
546 // Compute the new tree layout.
547 var nodes = treeData.descendants(),
548 links = treeData.descendants().slice(1);
550 var list1 = d3.selectAll(".fa")
552 .style("display", "block");
554 // Normalize for fixed-depth.
555 nodes.forEach(function(d){ d.y = d.depth * 100});
556 // ****************** Nodes section ***************************
558 // Update the nodes...
559 var node = base.state.g.selectAll('g.node')
560 .data(nodes, function(d) {return d.id });
562 // Enter any new modes at the parent's previous position.
563 var nodeEnter = node.enter().append('g')
564 .attr('class', 'node')
565 .attr("transform", function(d) {
566 return "translate(" + source.y0 + "," + source.x0 + ")";
568 // .on('click', click)
569 .on('dblclick', doubleClick);
571 // Add Circle for the nodes
572 nodeEnter.append('circle')
573 .attr('class', 'node')
575 .style("fill", "lightsteelblue");
576 nodeEnter.append("svg:foreignObject")
581 .append("xhtml:span")
582 .attr("class", function (d) {
584 if(!INVLIST.IS_ONAP){
585 icon = 'icon-datanetwork-serverL';
587 icon = 'browse-fa fa fa-server';
589 if(d.data.details && d.data.details.parentContainer){
590 var iconKey = ((d.data.details.parentContainer).replace(/-/g, '')).toUpperCase();
591 if(INVLIST.INVENTORYLIST[iconKey] && INVLIST.INVENTORYLIST[iconKey].icon){
592 return INVLIST.INVENTORYLIST[iconKey].icon;
600 .style("font-size", function (d) {
601 if (!INVLIST.IS_ONAP){
607 .attr("id", function (d) {return "nodeIcon" + d.id})
608 .style("color", '#387dff')
609 .style("display", "block")
610 .style("padding-top",function(d){
611 if (!INVLIST.IS_ONAP){
618 nodeEnter.append("svg:foreignObject")
623 .on('click', function (d) {
624 if(d.data.details.isRootNode){
628 for(var i = 0; d.parent.children && i < d.parent.children.length; i++){
629 if (d.parent.children.length > 1 && d.data.name === d.parent.children[i].data.name){
630 d.parent.children.splice(i, 1);
631 }else if (d.parent.children.length === 1 && d.data.name === d.parent.children[i].data.name){
632 d.parent.children = null;
635 base.update(base, d);
638 .append("xhtml:span")
639 .attr("class", "fa fa-minus")
640 .style("padding-top", "1px")
641 .style("font-size", function (d){ return "5px";})
642 .attr("id", function (d) {return "nodeDelete" + d.data.id})
643 .style("color", '#387dff')
644 .style("display", function (d) {return "block";});
645 nodeEnter.append("svg:foreignObject")
650 .on('click', function (d) { base.setState({enableModalFeedback: true}, function () {setTimeout(() => {add(d)},1);})})
651 .append("xhtml:span")
652 .attr("class", "fa fa-plus")
653 .style("padding-top", "1px")
654 .style("font-size", function (d){ return "5px";})
655 .attr("id", function (d) {return "nodeAdd" + d.data.id})
656 .style("color", '#387dff');
657 nodeEnter.append("svg:foreignObject")
662 .on('click', function (d) { edit(d)})
663 .append("xhtml:span")
664 .attr("class", "fa fa-pencil-square")
665 .style("padding-top", "1px")
666 .style("font-size", function (d){ return "5px";})
667 .attr("id", function (d) {return "nodeEdit" + d.data.id})
668 .style("color", '#387dff');
669 // Add labels for the nodes
670 nodeEnter.append("svg:foreignObject")
675 .append("xhtml:span")
678 .attr("x", function(d) {
679 return d.children ? -13 : 13;
681 .text(function(d) { return d.data.name; })
682 .style("float","right")
683 .style("color", '#000000');
686 var nodeUpdate = nodeEnter.merge(node);
687 var postNodeDrawnCallBack = function (d){
688 if(!isInit && base.state.autoZoomEnabled || d.data.details.isRootNode){
689 base.state.zoomFit();
692 // Transition to the proper position for the node
693 nodeUpdate.transition()
694 .duration(base.state.duration)
695 .attr("transform", function(d) {
696 return "translate(" + d.y + "," + d.x + ")"
697 }).on("end", postNodeDrawnCallBack);
699 // Update the node attributes and style
700 nodeUpdate.select('circle.node')
702 .style("fill", "lightsteelblue")
703 .attr('cursor', 'pointer');
706 // Remove any exiting nodes
707 var nodeExit = node.exit().transition()
708 .duration(base.state.duration)
709 .attr("transform", function(d) {
710 return "translate(" + source.y + "," + source.x + ")";
714 // On exit reduce the node circles size to 0
715 nodeExit.select('circle')
718 // On exit reduce the opacity of text labels
719 nodeExit.select('text')
720 .style('fill-opacity', 1e-6);
722 // ****************** links section ***************************
724 // Update the links...
725 var link = base.state.g.selectAll('path.link')
726 .data(links, function(d) { return d.id; });
728 // Enter any new links at the parent's previous position.
729 var linkEnter = link.enter().insert('path', "g")
730 .attr("class", "link")
731 .attr('d', function(d){
732 var o = {x: source.x0, y: source.y0}
733 return diagonal(o, o)
737 var linkUpdate = linkEnter.merge(link);
739 // Transition back to the parent element position
740 linkUpdate.transition()
741 .duration(base.state.duration)
742 .attr('d', function(d){ return diagonal(d, d.parent) });
744 // Remove any exiting links
745 var linkExit = link.exit().transition()
746 .duration(base.state.duration)
747 .attr('d', function(d) {
748 var o = {x: source.x, y: source.y}
749 return diagonal(o, o)
753 // Store the old positions for transition.
754 nodes.forEach(function(d){
759 // Creates a curved (diagonal) path from parent to the child nodes
760 function diagonal(s, d) {
761 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;
764 base.state.svg.on("dblclick.zoom", null);
765 // Toggle children on click.
767 base.populateEdgeRules(d.data.name,base.state.edgeRules);
770 d.data.children = [];
775 enableModalFeedback: false
780 console.log("object editing: " + d);
781 var nodeDetails = base.state.nodeDetails;
782 //set up node details to have the node to edit
783 if(d.data.details.isRootNode && base.props.match.params.type){
784 var attributes = GeneralCommonFunctions.getFilteringOptions(d.data.details.nodeType);
785 if(Object.keys(attributes).length > 0){
787 nodeDetails[0].isRootNode = true;
788 nodeDetails[0].nodeType = base.props.match.params.type;
789 nodeDetails[0].isSelected = true;
790 nodeDetails[0].attrDetails = attributes;
791 if(base.state.initialRootEdit){
792 for (var key in nodeDetails[0].attrDetails) {
793 nodeDetails[0].attrDetails[key].isSelected = true;
796 nodeDetails[0].parentContainer = GeneralCommonFunctions.populateContainer(base.props.match.params.type);
797 for (var key in d.data.details.attrDetails) {
798 nodeDetails[0].attrDetails[key] = d.data.details.attrDetails[key];
799 if(base.state.initialRootEdit){
800 nodeDetails[0].attrDetails[key].filterType = [];
801 nodeDetails[0].attrDetails[key].filterType.push('EQ');
805 d.data.details = nodeDetails[0];
807 initialRootEdit: false
810 nodeDetails[0] = d.data.details;
814 showEditNodeModal: true,
815 showPathFilterDslBuilder: false
818 function doubleClick(d) {
822 selectAll = (nodeKey) =>{
823 var nodeDetails = this.state.nodeDetails;
824 for (var key in nodeDetails[nodeKey].attrDetails) {
825 nodeDetails[nodeKey].attrDetails[key].isSelected = true;
827 this.setState({nodeDetails: nodeDetails});
829 deselectAll = (nodeKey) =>{
830 var nodeDetails = this.state.nodeDetails;
831 for (var key in nodeDetails[nodeKey].attrDetails) {
832 nodeDetails[nodeKey].attrDetails[key].isSelected = false;
834 this.setState({nodeDetails: nodeDetails});
836 build = (type, propID, attrDetails, preBuiltTree,dslPath,dslPathTree) =>{
839 if(!preBuiltTree && type && (propID || attrDetails)){
849 treeData.details.includeInOutput = true;
850 treeData.details.isSelected = true;
851 treeData.details.isRootNode = true;
852 treeData.details.nodeType = nodeType;
854 treeData.details.attrDetails = attrDetails;
856 treeData.details.attrDetails = {};
858 if(dslPath && dslPath.length>0 && dslPathTree && dslPathTree.length>0){
859 treeData.details.dslPath=dslPath;
860 treeData.details.dslPathTree=dslPathTree;
863 let propIds = (propID) ? propID.split(';') : '';
864 let propertyValue = '';
865 for(var i in propIds){
866 let propValue = propIds[i].split(':');
867 console.log(propValue[0] + '....' + propValue[1]);
868 treeData.details.attrDetails[propValue[0]] = {};
869 treeData.details.attrDetails[propValue[0]].filterValue=[];
870 treeData.details.attrDetails[propValue[0]].filterValue.push(atob(propValue[1]).replace('<pre>','').replace('</pre>',''));
871 treeData.details.attrDetails[propValue[0]].attributeName = propValue[0];
872 treeData.details.attrDetails[propValue[0]].isSelected = true;
875 }else if (preBuiltTree){
876 treeData = preBuiltTree;
877 if(treeData.details && treeData.details.dslPathTree && treeData.details.dslPathTree.length>0){
878 for(var x=0;x<treeData.details.dslPathTree.length;x++){
879 treeData.details.dslPath.push(GeneralCommonFunctions.populatePathDSL(treeData.details.dslPathTree[x],true,true,this.state.enableRealTime));
882 if(treeData.children && treeData.children.length>0){
883 for(var x=0;x<treeData.children.length;x++){
884 treeData.children[x]=this.updateDslPathValueOnExtract(treeData.children[x]);
889 // append the svg object to the body of the page
890 // appends a 'group' element to 'svg'
891 // moves the 'group' element to the top left margin
892 var svg = d3.select("#DSLBuilder");
893 // Set the dimensions and margins of the diagram
895 var margin = {top: 20, right: 120, bottom: 20, left: 120},
896 width = +svg.attr("width") - margin.right - margin.left,
897 height = +svg.attr("height") - margin.top - margin.bottom;
899 var g = svg.append("g")
900 .attr("transform", "translate("
901 + margin.left + "," + margin.top + ")");
906 // declares a tree layout and assigns the size
907 var treemap = d3.tree().size([height - 200, width]);
909 // Assigns parent, children, height, depth
910 root = d3.hierarchy(treeData, function(d) { return d.children; });
911 root.x0 = height / 2;
915 function zoom_actions(){
916 g.attr("transform", d3.event.transform)
918 //add zoom capabilities
919 var zoom_handler = d3.zoom()
920 .on("zoom", zoom_actions);
925 var bounds = g.node().getBBox();
926 var parent = g.node().parentElement;
927 if(bounds && parent){
928 var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
929 fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
930 var width = bounds.width,
931 height = bounds.height;
932 var midX = bounds.x + width / 2,
933 midY = bounds.y + height / 2;
934 if (width == 0 || height == 0) return; // nothing to fit
935 var scale = Math.min((0.95 / Math.max(width / fullWidth, height / fullHeight)), 4);
936 var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
938 var transform = d3.zoomIdentity
939 .translate(300, translate[1])
941 svg.transition().duration(350)
942 .call(zoom_handler.transform, transform);
948 svg.call(zoom_handler)
949 .call(zoom_handler.transform, d3.zoomIdentity.translate(80, -1000).scale(4));
958 }, ()=>{this.update(this, root, true);})
960 // Collapse the node and all it's children
961 function collapse(d) {
963 d.children.forEach(collapse)
969 updateDslPathValueOnExtract=(treeDataChildren)=>{
970 if(treeDataChildren.details && treeDataChildren.details.dslPathTree && treeDataChildren.details.dslPathTree.length>0){
971 for(var x=0;x<treeDataChildren.details.dslPathTree.length;x++){
972 let dsl=GeneralCommonFunctions.populatePathDSL(treeDataChildren.details.dslPathTree[x],true,true,this.state.enableRealTime);
973 treeDataChildren.details.dslPath.push(dsl);
976 if(treeDataChildren && treeDataChildren.children && treeDataChildren.children.length>0){
977 for(var x=0;x<treeDataChildren.children.length;x++){
978 treeDataChildren.children[x]=this.updateDslPathValueOnExtract(treeDataChildren.children[x]);
981 return treeDataChildren;
983 onTargetMenuOfFilterTypes=(listname,id)=>{
984 console.log(listname+'onTargetMenuOfFilterTypes',id);
985 let keysOfArray=id.split('#');
986 let nodekey=keysOfArray[0];
987 let attrKey=keysOfArray[1];
988 let indx=parseInt(keysOfArray[2]);
989 let nodeDetails = this.state.nodeDetails;
990 let node = nodeDetails[nodekey];
991 if(!node.attrDetails){
992 node.attrDetails = [];
994 if(!node.attrDetails[attrKey]){
995 node.attrDetails[attrKey] = {};
996 node.attrDetails[attrKey].isSelected = true;
997 node.attrDetails[attrKey].filterValue = [];
998 node.attrDetails[attrKey].filterType = [];
1000 let filterTypes=node.attrDetails[attrKey].filterType;
1001 filterTypes[indx]=listname;
1002 node.attrDetails[attrKey].filterType=filterTypes;
1004 nodeDetails[nodekey] = node;
1005 // update the state with the new array of traverse to nodes
1006 this.setState({ nodeDetails: nodeDetails });
1008 filterTags = (key,property,state) =>{
1011 state=true;//always enable, in future if wants to disable remove this line
1012 if(APERTURE_SERVICE && this.state.enableRealTime){
1013 let nodeDetails = this.state.nodeDetails;
1014 let node = nodeDetails[key];
1015 filterTags= Object.keys(Object.keys(node.attrDetails[property].filterType)).map((indx) =>{
1016 let selectedFilter=(node.attrDetails[property].filterType[indx]!=='')?node.attrDetails[property].filterType[indx]:this.state.filterTypeDisplay;
1017 return <div style={{margin:'0px 0px 0px 5px'}}>
1019 <FilterTypes param={this.state}
1020 selectedFilter={selectedFilter}
1021 id={key+'#'+property+'#'+indx}
1022 onMenuSelect={this.onTargetMenuOfFilterTypes}
1027 filters= <Col md={4} className='removeLeftPadding'>{filterTags}</Col>;
1031 addOrTemplate=(nodeKey,attrKey,indx)=>{
1032 let nodeDetails = this.state.nodeDetails;
1033 let node = nodeDetails[nodeKey];
1034 node.attrDetails[attrKey].filterValue.push('');
1035 node.attrDetails[attrKey].filterType.push('EQ');
1036 nodeDetails[nodeKey] = node;
1037 // update the state with the new array of traverse to nodes
1038 this.setState({ nodeDetails: nodeDetails });
1040 deleteOrTemplate=(nodeKey,attrKey,index)=>{
1041 let nodeDetails = this.state.nodeDetails;
1042 let node = nodeDetails[nodeKey];
1043 let filterValuesArray=node.attrDetails[attrKey].filterValue;
1044 let filterTypeArray=node.attrDetails[attrKey].filterType;
1045 filterValuesArray.splice(index,1);
1046 filterTypeArray.splice(index,1);
1047 node.attrDetails[attrKey].filterValue=filterValuesArray;
1048 node.attrDetails[attrKey].filterType=filterTypeArray;
1049 nodeDetails[nodeKey] = node;
1050 this.setState({ nodeDetails: nodeDetails });
1052 toggleRealTimeAnalysisCallback=(checked)=>{
1053 console.log('toggleRealTimeAnalysisCallback>>>>',checked);
1054 sessionStorage.setItem(ENVIRONMENT + 'ENABLE_ANALYSIS', !checked);
1055 this.baseState.enableRealTime=!checked;
1056 this.baseState.init= true;
1057 this.setState({...this.baseState},()=>{document.getElementById("DSLBuilder").innerHTML='';});
1059 renderPathFilterBuilder=(key,dslPath,dslPathTree)=>{
1060 console.log('renderPathFilterBuilder>>>>',key);
1061 let attrDetails=this.state.nodeDetails[key].attrDetails;
1062 let nodeType=this.state.nodeDetails[key].nodeType;
1063 this.setState({showPathFilterDslBuilder: true,pathFilterNodeType: key,pathFilterNodeName:nodeType,pathFIlterAttrDetails: attrDetails,dslPathBuilder: dslPath,dslPathTree:dslPathTree,isEditEnable:false});
1065 /* Load Functions */
1066 getAndPopulateTreeFromDSL = (dslQuery) =>{
1067 var treeObject = [];
1068 var payload = {dsl: dslQuery};
1069 settings['ISAPERTURE'] = true;
1070 commonApi(settings, 'dsl/convert-query-to-tree', 'PUT', payload, 'ConvertQueryToTree')
1072 console.log('res:' + res.data, 'load');
1073 if(res.status === 200 || res.status === 404){
1074 if(res.data.status && (res.data.status !== 200 && res.data.status !== 201 && res.data.status !== 404)){
1075 this.triggerError(res.data, 'treeLoad');
1077 treeObject = res.data;
1079 enableTreeLoadBusyFeedback:false,
1080 treeLoadErrMsg: null
1082 console.log("TREE OBJECT: " + JSON.stringify(treeObject));
1085 this.state.svg.selectAll("*").remove();
1087 //set the init state
1088 this.setState({init: true, dslQuery: '', initialRootEdit: false, nodeDetails: [], selectedNode: null });
1089 var initNode = this.extractNodeDetails(treeObject.children[0], true);
1090 if(!this.state.treeLoadErrMsg || this.state.treeLoadErrMsg === ''){
1091 console.log(JSON.stringify(initNode));
1092 this.build(null, null, null, initNode);
1093 setTimeout(() => { this.state.zoomFit() }, 600);
1094 //scroll to the hidden static modal since svg offsetTop doesnt work for DSLBuilder id
1095 GeneralCommonFunctions.scrollTo('customDslBuilderModel');
1097 this.triggerError(null, 'invalidQuery');
1101 this.triggerError(res.data, 'treeLoad');
1104 if(error.response.status === 404){
1105 this.setState({enableTreeLoadBusyFeedback:false});
1107 this.triggerError(error.response.data, 'treeLoad');
1110 this.triggerError(error, 'treeLoad');
1114 resetBuilder = () => {
1116 this.state.svg.selectAll("*").remove();
1122 queryDescription:'',
1123 initialRootEdit: false,
1127 enableTreeLoadBusyFeedback: false,
1128 aggregateObjects: false
1131 triggerError = (error, type) => {
1132 console.error('[CustomDslBuilder.jsx] error : ', JSON.stringify(error));
1134 if(error && error.status && error.message){
1135 errMsg += "Error Occurred: " + error.status + ' - ' +error.message;
1137 errMsg += "Error Occurred: " + JSON.stringify(error);
1139 console.log(errMsg);
1140 if(type === 'treeLoad' || type === 'invalidQuery'){
1141 this.resetBuilder();
1142 var errorMessage = errMsg;
1143 if(type === 'invalidQuery'){
1144 errorMessage = 'The loaded query uses DSL syntax not supported by the DSL Builder,'
1145 + ' please only load queries compatible with the builder. For more'
1146 + ' information on this error, please contact an administrator.';
1148 this.setState({treeLoadErrMsg: errorMessage});
1149 GeneralCommonFunctions.scrollTo('treeLoadErrorMessage');
1151 console.log('[CustomDslBuilder.jsx] :: triggerError invoked with invalid type : ' + type);
1154 validLoadableDSL = (dslQuery) => {
1156 dslQuery = dslQuery.replace(/\s/g, '');
1157 valid = dslQuery.indexOf(']>') === -1 && !(new RegExp("LIMIT[0-9]+$").test(dslQuery));
1160 loadCallback = (name, description, category, dslQuery, isAggregate, type, queryId, id, templateDetails, makeCall) =>{
1161 var decodedDslQuery = atob(dslQuery).replace('<pre>','').replace('</pre>','');
1162 if(this.validLoadableDSL(decodedDslQuery)){
1163 if(name !== '' && description !== ''){
1166 queryDescription:description,
1168 isPublicChecked: type === 'public',
1170 treeLoadErrMsg: null,
1171 aggregateObjects: isAggregate === "true"
1173 console.log("DSL Query Loaded: "+ decodedDslQuery);
1174 console.log("DSL Query Name: "+ name);
1175 console.log("DSL Query Description: "+ description);
1176 console.log("DSL Query ID: "+ queryId);
1177 console.log("DSL Query Category: "+ category);
1178 console.log("DSL Query isAggregate: "+ isAggregate);
1179 console.log("DSL Query type: "+ type);
1180 var treeObject = this.getAndPopulateTreeFromDSL(decodedDslQuery);
1183 this.triggerError(null, "invalidQuery");
1186 extractNodeDetails = (node, isRoot) =>{
1187 let nodeType = node['node-type'];
1194 nodeData.details.includeInOutput = node.store;
1195 nodeData.details.isSelected = true;
1196 nodeData.details.isRootNode = isRoot;
1197 nodeData.details.nodeType = nodeType;
1198 var attributes = GeneralCommonFunctions.getFilteringOptions(nodeType);
1199 nodeData.details.attrDetails = attributes;
1200 nodeData.details.parentContainer = GeneralCommonFunctions.populateContainer(nodeType);
1201 if(node.store && !node['requested-props']){
1202 for(var key in nodeData.details.attrDetails){
1203 nodeData.details.attrDetails[key].isSelected = true;
1205 }else if (node.store && node['requested-props']){
1206 for(var key in node['requested-props']){
1207 nodeData.details.attrDetails[key].isSelected = true;
1208 nodeData.details.attrDetails[key].alias=node['requested-props'][key];
1212 for (var x in node['node-filter']){
1214 for (var y in node['node-filter'][x]) {
1216 var attrKey = node['node-filter'][x][y]['key'];
1217 var filter = node['node-filter'][x][y]['filter'];
1218 //If aperture is not turned on and query loaded uses anything besides EQ throw error
1219 if(!APERTURE_SERVICE && filter !== 'EQ'){
1220 this.triggerError(null, "invalidQuery");
1223 if(!nodeData.details.attrDetails[attrKey]){
1224 nodeData.details.attrDetails[attrKey] = {};
1226 if(nodeData.details.attrDetails[attrKey].filterType.length > 0 && nodeData.details.attrDetails[attrKey].filterType[0] === ''){
1227 nodeData.details.attrDetails[attrKey].filterType = [];
1229 if(nodeData.details.attrDetails[attrKey].filterValue.length > 0 && nodeData.details.attrDetails[attrKey].filterValue[0] === ''){
1230 nodeData.details.attrDetails[attrKey].filterValue = [];
1232 //if a filter had no values associated to it throw a not supported error
1233 if(node['node-filter'][x][y]['value'][0]){
1234 for (var i in node['node-filter'][x][y]['value']){
1235 nodeData.details.attrDetails[attrKey].filterType.push(filter);
1236 nodeData.details.attrDetails[attrKey].filterValue.push(node['node-filter'][x][y]['value'][i]);
1238 if(!nodeData.details.attrDetails[attrKey].attributeName){
1239 nodeData.details.attrDetails[attrKey].attributeName = attrKey;
1242 this.triggerError(null, "invalidQuery");
1249 var initWhereNode = null;
1250 if(node['where-filter'].length > 0){
1251 for(var index in node['where-filter']){
1252 initWhereNode = this.extractNodeDetails(node['where-filter'][index].children[0], true);
1256 nodeData.details.dslPath=[];
1257 nodeData.details.dslPathTree=[];
1258 nodeData.details.dslPathTree.push(initWhereNode);
1260 if(node.children.length > 0){
1261 for(var i = 0; i < node.children.length; i++){
1262 nodeData.children[i] = this.extractNodeDetails(node.children[i], false);
1268 setQueriesState = (savedQueries) =>{
1270 loadedQueries: savedQueries
1273 /* End Load Functions */
1275 var toggelRealtimeAnalysis = '';
1276 if(APERTURE_SERVICE){
1277 toggelRealtimeAnalysis = <div className='toggleSwitch'><BootstrapSwitchButton
1278 checked={!this.state.enableRealTime}
1284 onChange={(checked) => {
1285 this.toggleRealTimeAnalysisCallback(checked);
1291 {toggelRealtimeAnalysis}
1292 <div className="addPadding">
1293 <div className='row container-fluid my-4'>
1294 <div className='col-lg-9'>
1295 <header className='jumbotron'>
1296 <h1 className='display-2'>Visual Query Builder for <strong>B</strong>uild <strong>Y</strong>our <strong>O</strong>wn <strong>Q</strong>uery</h1>
1297 <p className='lead'>
1298 Visually build your own query, you can click the + icon to add objects to your query,
1299 - icon to remove objects from your query, or the pencil icon/double click to edit attributes.
1300 Single click and drag in the view to pan, use scrollwheel or pinch to zoom. <br/>
1305 <div className={'addPaddingTop alert alert-danger ' +(this.state.treeLoadErrMsg && this.state.treeLoadErrMsg !== '' ? 'show' : 'hidden')} id="treeLoadErrorMessage" role="alert">
1306 An error occurred in loading the query. Please see details {this.state.treeLoadErrMsg}
1308 <CustomDSLSaveLoad loadCallback={this.loadCallback} setQueriesState={this.setQueriesState} ref={this.saveLoadComponent} isDataSteward={this.state.isDataSteward} isDSLBuilder={true}/>
1309 <div className={'row ' + (this.state.init ? 'show' : 'hidden')}>
1310 <button className='btn btn-primary' type='button' onClick={this.initialize.bind(this)}>Start Building (+)</button>
1312 <div className={'row ' + (!this.state.init ? 'show' : 'hidden')}>
1313 <button className='btn btn-primary' type='button' onClick={this.runDSL}>Run Query</button>
1314 <button className='btn btn-outline-secondary' type='button' onClick={this.showEditDSLModal}>Manual Edit & Run</button>
1315 <div className={'checkbox ' + (GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1317 <input type="checkbox" checked={this.state.aggregateObjects} onChange={this.onAggregateCheckbox.bind(this)} />
1321 <input type="checkbox" checked={this.state.autoZoomEnabled} onChange={this.onAutoZoomCheckbox.bind(this)} />
1327 <div className='static-modal' id='customDslBuilderModel'>
1328 <Modal show={this.state.showNodeModal} onHide={this.closeNodeModal}>
1330 <Modal.Title>Modify Query</Modal.Title>
1334 {Object.keys(this.state.nodeDetails).sort().map((key, node) => (
1335 <div className="dsl-panel">
1339 <div className={'checkbox ' + (!this.state.init ? 'show' : 'hidden')}>
1341 <input type="checkbox" checked={this.state.nodeDetails[key].isSelected} value={key} onChange={this.onNodeCheckbox.bind(this)} />
1342 {this.state.nodeDetails[key].nodeType}
1345 <div className="pull-right">Options</div>
1348 <div className={(this.state.init ? 'show' : 'hidden')}>
1350 <input type="radio" value={key} checked={this.state.nodeDetails[key].isSelected} onChange={this.onNodeRadio.bind(this)} />
1351 {" " + this.state.nodeDetails[key].nodeType}
1354 <div className="pull-right">Options</div>
1360 <Panel.Body className='cardwrap'>
1362 <div style={{float:'right'}}>
1363 <button type='button' className='btn btn-primary pull-right' onClick={()=>this.renderPathFilterBuilder(key)}>Build Path Filter</button>
1366 {this.state.nodeDetails[key].dslPath && this.state.nodeDetails[key].dslPath.length>0 &&
1367 <Grid fluid={true} className='addPaddingTop'>
1368 <Row className='show-grid addPaddingTop'>
1370 <strong>DSL PATH Filter</strong>
1372 <Col md={2} className='removeLeftPadding'>
1373 <strong>Action</strong>
1378 {this.state.nodeDetails[key].dslPath && Object.keys(this.state.nodeDetails[key].dslPath).map((indx) => {
1380 <Row className='show-grid'>
1382 <div style={{float:'left',width:'100%',margin:'10px 0px'}}>
1383 {this.state.nodeDetails[key].dslPath[indx]}
1388 className='btn btn-primary'
1389 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1391 onClick={e => {this.editPathNodeModal(key,this.state.nodeDetails[key].dslPath[indx],this.state.nodeDetails[key].dslPathTree[indx],indx)}}>Edit</button>
1393 className='btn btn-primary'
1394 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1396 onClick={e => {this.deletePathNodeModal(key,this.state.nodeDetails[key].dslPath[indx],this.state.nodeDetails[key].dslPathTree[indx],indx)}}>Delete</button>
1402 <div style={{float:'left'}} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1403 <button type='button' className='btn btn-outline-primary pull-right' onClick={()=>this.deselectAll(key)}>Deselect All</button>
1404 <button type='button' className='btn btn-primary pull-right' onClick={()=>this.selectAll(key)}>Select All</button>
1406 <Grid fluid={true} className='addPaddingTop'>
1407 <Row className='show-grid addPaddingTop'>
1408 <Col md={(this.state.enableRealTime)?4:6} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1409 <strong>Include in Output</strong>
1411 {APERTURE_SERVICE && this.state.enableRealTime && <Col md={4} className='removeLeftPadding'>
1412 <strong>Filter Types</strong>
1414 <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1415 <strong>Filter By (Optional)</strong>
1418 {Object.keys(this.state.nodeDetails[key].attrDetails).sort().map((attrKey, attr) => {
1420 <Row className='show-grid'>
1421 <Col md={(this.state.enableRealTime)?4:6} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1422 <div className="checkbox">
1424 <input type="checkbox" checked={this.state.nodeDetails[key].attrDetails
1425 && this.state.nodeDetails[key].attrDetails[attrKey]
1426 && this.state.nodeDetails[key].attrDetails[attrKey].isSelected }
1427 value={key + "|" + attrKey} onChange={this.onAttributeCheckbox.bind(this)} />
1432 {this.filterTags(key,attrKey,this.state.nodeDetails[key].attrDetails[attrKey].isSelected)}
1433 <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1434 {Object.keys(this.state.nodeDetails[key].attrDetails[attrKey].filterValue).map((indx) =>{
1437 {this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] ==='' && <input type="text"
1438 placeholder={"Enter " + attrKey }
1439 className='inputFilter'
1440 onBlur={(e)=>{this.onFilterValueChange(e, key, attrKey,indx);}}
1443 {this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] !=='' && <input type="text"
1444 onChange={(e)=>{this.onFilterValueChange(e, key, attrKey,indx);}}
1445 placeholder={"Enter " + attrKey }
1446 className='inputFilter'
1447 value={this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx]}
1450 {indx == 0 && <button
1451 className={(this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] !=='')?'btn btn-primary':'btn btn-secondary'}
1452 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1453 disabled={this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx]===''}
1455 onClick={e => {this.addOrTemplate(key,attrKey,indx)}}>+</button>}
1456 {indx > 0 && <button
1457 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1459 className='btn btn-danger'
1461 onClick={e => {this.deleteOrTemplate(key,attrKey,indx)}}>x</button>}
1479 <div className={this.state.showPathFilterDslBuilder ? 'show' : 'hidden'}>
1480 <Modal show={this.state.showPathFilterDslBuilder} onHide={!this.state.showPathFilterDslBuilder} style={{width:'100%'}}>
1482 <Modal.Title>Build DSL Path</Modal.Title>
1484 <Modal.Body style={{overflow:'scroll'}}>
1485 <PathFilterDslBuilder nodeType={this.state.pathFilterNodeType}
1486 nodeName={this.state.pathFilterNodeName}
1487 attrDetails={this.state.pathFIlterAttrDetails}
1488 closePathNodeModal={this.closePathNodeModal}
1489 submitPathNodeModal={this.submitPathNodeModal}
1490 showPathFilterDslBuilder={this.state.showPathFilterDslBuilder}
1491 dslPath={this.state.dslPathBuilder}
1492 dslPathTree={this.state.dslPathTree}
1493 isEditEnable={this.state.isEditEnable}
1494 pathFilterIndex={this.state.pathFilterIndex}/>
1500 <Button onClick={this.closeNodeModal}>Close</Button>
1501 <Button onClick={this.submitNodeModal}>Submit</Button>
1505 <div className='static-modal' id='editNodeModel'>
1506 <Modal show={this.state.showEditNodeModal} onHide={this.closeEditNodeModal}>
1508 <Modal.Title>Modify Node</Modal.Title>
1512 <div className="dsl-panel">
1517 <label>{this.state.selectedNode
1518 && this.state.selectedNode.data
1519 && this.state.selectedNode.data.details ?
1520 this.state.selectedNode.data.details.nodeType
1527 <Panel.Body className='cardwrap'>
1528 <Grid fluid={true} className='addPaddingTop'>
1529 <Row className='show-grid addPaddingTop'>
1530 <div style={{float:'right'}}>
1531 <button type='button' className='btn btn-primary pull-right' onClick={()=>this.renderPathFilterBuilder(0)}>Build Path Filter</button>
1534 {this.state.selectedNode
1535 && this.state.selectedNode.data
1536 && this.state.selectedNode.data.details
1537 && this.state.nodeDetails[0]
1538 && this.state.nodeDetails[0].dslPath && this.state.nodeDetails[0].dslPath.length>0 &&
1539 <Row className='show-grid addPaddingTop'>
1541 <strong>DSL PATH Filter</strong>
1543 <Col md={2} className='removeLeftPadding'>
1544 <strong>Action</strong>
1548 {this.state.selectedNode
1549 && this.state.selectedNode.data
1550 && this.state.selectedNode.data.details
1551 && this.state.nodeDetails[0]
1552 && this.state.nodeDetails[0].dslPath && Object.keys(this.state.nodeDetails[0].dslPath).map((indx) => {
1554 <Row className='show-grid'>
1556 <div style={{float:'left',width:'100%',margin:'10px 0px'}}>
1557 {this.state.nodeDetails[0].dslPath[indx]}
1562 className='btn btn-primary'
1563 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1565 onClick={e => {this.editPathNodeModal(0,this.state.nodeDetails[0].dslPath[indx],this.state.nodeDetails[0].dslPathTree[indx],indx)}}>Edit</button>
1567 className='btn btn-primary'
1568 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1570 onClick={e => {this.deletePathNodeModal(0,this.state.nodeDetails[0].dslPath[indx],this.state.nodeDetails[0].dslPathTree[indx],indx)}}>Delete</button>
1575 <div style={{float:'left'}} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1576 <button type='button' className='btn btn-outline-primary pull-right' onClick={()=>this.deselectAll(0)}>Deselect All</button>
1577 <button type='button' className='btn btn-primary pull-right' onClick={()=>this.selectAll(0)}>Select All</button>
1579 <Grid fluid={true} className='addPaddingTop'>
1580 <Row className='show-grid addPaddingTop'>
1581 <Col md={(this.state.enableRealTime)?4:6} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1582 <strong>Include in Output</strong>
1584 {this.state.enableRealTime && <Col md={4} className='removeLeftPadding'>
1585 <strong>Filter Types</strong>
1587 <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1588 <strong>Filter By (Optional)</strong>
1591 {this.state.selectedNode
1592 && this.state.selectedNode.data
1593 && this.state.selectedNode.data.details
1594 && this.state.nodeDetails[0]
1595 && Object.keys(this.state.nodeDetails[0].attrDetails).sort().map((attrKey, attr) => {
1597 <Row className='show-grid'>
1598 <Col md={(this.state.enableRealTime)?4:6} className={(GlobalExtConstants.INVLIST.IS_ONAP ? 'hidden' : '' )}>
1599 <div className="checkbox">
1601 <input type="checkbox" checked={this.state.nodeDetails[0].attrDetails
1602 && this.state.nodeDetails[0].attrDetails[attrKey]
1603 && this.state.nodeDetails[0].attrDetails[attrKey].isSelected }
1604 value={0 + "|" + attrKey} onChange={this.onAttributeCheckbox.bind(this)} />
1609 {this.filterTags(0,attrKey, this.state.nodeDetails[0].attrDetails[attrKey].isSelected)}
1610 <Col md={(this.state.enableRealTime)?4:6} className='removeLeftPadding'>
1611 {Object.keys(this.state.nodeDetails[0].attrDetails[attrKey].filterValue).map((indx) =>{
1615 {this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] ==='' && <input type="text"
1616 placeholder={"Enter " + attrKey }
1617 className='inputFilter'
1618 onBlur={(e)=>{this.onFilterValueChange(e, 0, attrKey, indx);}}
1621 {this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] !=='' && <input type="text"
1622 onChange={(e)=>{this.onFilterValueChange(e, 0, attrKey,indx);}}
1623 placeholder={"Enter " + attrKey }
1624 className='inputFilter'
1625 value={this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]}
1628 {indx == 0 && <button
1629 className={(this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]!=='')?'btn btn-primary':'btn btn-secondary'}
1630 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1631 disabled={this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]===''}
1633 onClick={e => {this.addOrTemplate(0 ,attrKey,indx)}}>+</button>}
1634 {indx > 0 && <button
1635 style={{padding:'2px',margin:'0px 0px 7px 3px'}}
1637 className='btn btn-danger'
1639 onClick={e => {this.deleteOrTemplate(0 ,attrKey,indx)}}>x</button>}
1655 <div className={(this.state.showPathFilterDslBuilder && this.state.showEditNodeModal) ? 'show' : 'hidden'}>
1656 <Modal show={this.state.showPathFilterDslBuilder} onHide={!this.state.showPathFilterDslBuilder} style={{width:'100%'}}>
1658 <Modal.Title>Build DSL Path</Modal.Title>
1660 <Modal.Body style={{overflow:'scroll'}}>
1661 <PathFilterDslBuilder nodeType={this.state.pathFilterNodeType}
1662 nodeName={this.state.pathFilterNodeName}
1663 attrDetails={this.state.pathFIlterAttrDetails}
1664 closePathNodeModal={this.closePathNodeModal}
1665 submitPathNodeModal={this.submitPathNodeModal}
1666 showPathFilterDslBuilder={this.state.showPathFilterDslBuilder}
1667 dslPath={this.state.dslPathBuilder}
1668 dslPathTree={this.state.dslPathTree}
1669 isEditEnable={this.state.isEditEnable}
1670 pathFilterIndex={this.state.pathFilterIndex}/>
1676 <Button onClick={this.closeEditNodeModal}>Close</Button>
1677 <Button onClick={this.submitEditNodeModal}>Submit</Button>
1681 <div className='static-modal'>
1682 <Modal show={this.state.showEditModal} onHide={this.closeEditDSLModal}>
1684 <Modal.Title>Edit DSL Query</Modal.Title>
1688 <FormGroup controlId="dslQuery">
1689 <ControlLabel>DSL Query</ControlLabel>
1690 <FormControl onChange={this.bindEdits.bind(this)} value={this.state.editModel} componentClass="textarea" placeholder="Enter DSL Query" />
1695 <Button onClick={this.closeEditDSLModal}>Close</Button>
1696 <Button onClick={this.submitEditAndRunDSL}>Submit</Button>
1701 <div className={'card-header ' + (this.state.queryName && this.state.queryName !== '' ? 'show' : 'hidden')}>
1703 <h3>{this.state.queryName}</h3>
1706 <div className={'card-header ' + (this.state.queryDescription && this.state.queryDescription !== '' ? 'show' : 'hidden')}>
1708 <h4>{this.state.queryDescription}</h4>
1711 <div className={'card-header ' + (this.state.dslQuery && this.state.dslQuery !== '' ? 'show' : 'hidden')}>
1713 <h4><strong>DSL Query: </strong><span className='pre-wrap-text'>{this.state.dslQuery}</span></h4>
1717 {this.state.enableModalFeedback && <Spinner loading={true}><span height="100%" width="100%"></span></Spinner>}
1718 <svg id='DSLBuilder' width='1800' height='800'></svg>
1725 export default CustomDslBuilder;