/* * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ import React, {Component} from 'react'; import commonApi from 'utils/CommonAPIService.js'; import {GeneralCommonFunctions} from 'utils/GeneralCommonFunctions.js'; import Modal from 'react-bootstrap/lib/Modal'; import Grid from 'react-bootstrap/lib/Grid'; import FormGroup from 'react-bootstrap/lib/FormGroup'; import FormControl from 'react-bootstrap/lib/FormControl'; import ControlLabel from 'react-bootstrap/lib/ControlLabel'; import Button from 'react-bootstrap/lib/Button'; import {GlobalExtConstants} from 'utils/GlobalExtConstants.js'; import Spinner from 'utils/SpinnerContainer.jsx'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; import Panel from 'react-bootstrap/lib/Panel'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import FilterTypes from 'generic-components/filter/components/FilterTypes.jsx'; import PathFilterDslBuilder from './PathFilterDslBuilder.jsx'; import CustomDSLSaveLoad from 'app/byoq/CustomDSLSaveLoad.jsx'; import BootstrapSwitchButton from 'bootstrap-switch-button-react'; import * as d3 from "d3"; import 'd3-selection-multi'; let EDGERULES = GlobalExtConstants.EDGERULES; let OXM = GlobalExtConstants.OXM; let INVLIST = GlobalExtConstants.INVLIST; let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT; let APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE')); let nodeTypes = []; let properties = null; let traverseRulesDsl = []; const settings = { 'NODESERVER': INVLIST.NODESERVER, 'PROXY': INVLIST.PROXY, 'PREFIX': INVLIST.PREFIX, 'VERSION': INVLIST.VERSION, 'APERTURE': INVLIST.APERTURE, 'USESTUBS': INVLIST.useStubs }; class CustomDslBuilder extends Component { constructor(props) { console.log('props>>>>',props); super(props); this.saveLoadComponent = React.createRef(); APERTURE_SERVICE=JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'APERTURE_SERVICE')); this.state = {edgeRules : null, connectableNodes:[], showNodeModal: false, enableModalFeedback: false, showEditNodeModal: false, treemap: null, root: null, svg: null, duration: null, g: null, selectedNode: null, traverseToNodes:[], traverseToNodeAttributes: [], nodeDetails: [], dslQuery: '', editModel:'', showEditModal: false, zoomFit: null, autoZoomEnabled: true, aggregateObjects: false, init: true, filterTypeDisplay: 'Filter Type', selectedfilterType:[], oxmMapping: null, initialRootEdit: true, showPathFilterDslBuilder: false, pathFilterNodeType: '', pathFilterNodeName:'', pathFIlterAttrDetails: [], dslPathBuilder:'', dslPathTree:'', loadedQueries: [], queryDescription: '', queryName: '', category:'', queryId:'', treeLoadErrMsg: '', isEditEnable:false, pathFilterIndex:0, isDataSteward: sessionStorage.getItem(ENVIRONMENT + 'roles') && sessionStorage.getItem(ENVIRONMENT + 'roles').indexOf('data_steward_ui_view') > -1, isPublicChecked: sessionStorage.getItem(ENVIRONMENT + 'roles') && sessionStorage.getItem(ENVIRONMENT + 'roles').indexOf('data_steward_ui_view') > -1, enableRealTime: JSON.parse(sessionStorage.getItem(ENVIRONMENT + 'ENABLE_ANALYSIS')) } this.baseState=this.state; } componentDidMount () { console.log('componentDidMount',JSON.stringify(this.props)); //this.buildSQLStatementsFromSchema(); this.processEdgeRules(EDGERULES); if(this.props.match.params.type && this.props.match.params.propId) { this.build(this.props.match.params.type, this.props.match.params.propId); } } initialize = () =>{ this.setState({enableModalFeedback: true}, function () { //console.log("EnableModalFeedback: " + this.state.enableModalFeedback); setTimeout(() => {this.postSpinner()},1); }); } postSpinner = () => { var nodeDetails = []; var node = null; console.log('initializing'); var id = GeneralCommonFunctions.generateID(); var nodeTypes = GeneralCommonFunctions.getNodeTypes(); for (var i = 0; i < nodeTypes.length; i++) { node = nodeTypes[i] + id; var attributes = GeneralCommonFunctions.getFilteringOptions(nodeTypes[i]); if(!nodeDetails[node] && Object.keys(attributes).length > 0){ nodeDetails[node] = {}; nodeDetails[node].nodeType = nodeTypes[i]; nodeDetails[node].isSelected = false; nodeDetails[node].attrDetails = attributes; nodeDetails[node].parentContainer = GeneralCommonFunctions.populateContainer(nodeTypes[i]); } } let nodesSorted = nodeDetails.sort(function (filter1, filter2) { if (filter1.nodeType < filter2.nodeType) { return -1; } else if (filter1.nodeType > filter2.nodeType) { return 1; } else { return 0; } }); //console.log('Node Types List' + JSON.stringify(nodesSorted)); nodeDetails = nodesSorted; this.setState({nodeDetails: nodeDetails, showNodeModal: true, enableModalFeedback: false}); } processEdgeRules = (data) => { this.setState({ edgeRules: data.rules },()=>{this.baseState=this.state}); } closeNodeModal = () =>{ this.setState({ showNodeModal: false, enableModalFeedback: false, traverseToNodes: [], selectedNode: null }); } closeEditNodeModal = () =>{ this.setState({ showEditNodeModal: false, selectedNode: null, showPathFilterDslBuilder: false }); } closePathNodeModal = () =>{ console.log('closePathNodeModal>>>>>>>'); this.setState({ showPathFilterDslBuilder: false, pathFilterNodeType: '', pathFilterNodeName:'', pathFIlterAttrDetails: [] }); } submitPathNodeModal = (dslQuery,nodetype,dslQueryTree,isEditEnable,pathFilterIndex) =>{ console.log('CustomDSLBuilder submitPathNodeModel>>>>>dslQuery ###',dslQuery); console.log(isEditEnable+'<>>>',this.state.nodeDetails) var nodeDetails = this.state.nodeDetails; if(!nodeDetails[nodetype].dslPath){ nodeDetails[nodetype].dslPath=[]; nodeDetails[nodetype].dslPathTree=[]; } if(isEditEnable){ nodeDetails[nodetype].dslPath[pathFilterIndex]=dslQuery; nodeDetails[nodetype].dslPathTree[pathFilterIndex]=dslQueryTree; console.log('nodeDetails on edit>>>>>>>>>',nodeDetails); }else{ nodeDetails[nodetype].dslPath.push(dslQuery); nodeDetails[nodetype].dslPathTree.push(dslQueryTree); } this.setState({ nodeDetails: nodeDetails },()=>{this.closePathNodeModal()}); } editPathNodeModal = (key,path,tree,indx) =>{ console.log('editPathNodeModal>>>>>>>>>###',indx); let attrDetails=this.state.nodeDetails[key].attrDetails; let nodeType=this.state.nodeDetails[key].nodeType; this.setState({showPathFilterDslBuilder: true,pathFilterNodeType: key,pathFilterNodeName:nodeType,pathFIlterAttrDetails: '',dslPathBuilder: path,dslPathTree:tree,isEditEnable:true,pathFilterIndex:indx}); } deletePathNodeModal = (key,path,tree,index) =>{ console.log(index+'<>>>>',key); var nodeDetails = this.state.nodeDetails; nodeDetails[key].dslPath.splice(index,1); nodeDetails[key].dslPathTree.splice(index,1); this.setState({ nodeDetails: nodeDetails }); } onNodeCheckbox(e) { var nodeDetails = this.state.nodeDetails; if (e.target.checked) { nodeDetails[e.target.value].isSelected = true; this.selectAll(e.target.value); }else { nodeDetails[e.target.value].isSelected = false; this.deselectAll(e.target.value); } // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); } onNodeRadio(e) { var nodeDetails = this.state.nodeDetails; if (e.target.checked) { nodeDetails[e.target.value].isSelected = true; this.selectAll(e.target.value); } for (var key in nodeDetails) { if(key != e.target.value && nodeDetails[key].isSelected ){ nodeDetails[key].isSelected = false; this.deselectAll(key); } } // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); } onAutoZoomCheckbox(e) { var cbValue = false; if (e.target.checked) { cbValue = true; }else { cbValue = false; } this.setState({ autoZoomEnabled: cbValue }); } onAggregateCheckbox(e) { var cbValue = false; if (e.target.checked) { cbValue = true; }else { cbValue = false; } this.setState({ aggregateObjects: cbValue }); } onAttributeCheckbox(e){ let splitVal = e.target.value.split("|"); let nodeKey = splitVal[0]; let attrValue = splitVal[1]; let nodeDetails = this.state.nodeDetails; let node = nodeDetails[nodeKey]; let attribute = null; if(!node.attrDetails){ node.attrDetails = []; } if(!node.attrDetails[attrValue]){ node.attrDetails[attrValue] = {}; node.attrDetails[attrValue].isSelected = true; node.attrDetails[attrValue].filterValue = []; node.attrDetails[attrValue].filterType = []; node.attrDetails[attrValue].dslPath = []; node.attrDetails[attrValue].dslPathTree = []; } // check if the check box is checked or unchecked if (e.target.checked) { // add the value of the checkbox to nodes array node.attrDetails[attrValue].isSelected = true; node.attrDetails[attrValue].filterType[0]='EQ'; } else { // or remove the value from the unchecked checkbox from the array node.attrDetails[attrValue].isSelected = false; //node.attrDetails[attrValue].filterType = ['']; //node.attrDetails[attrValue].filterValue = ['']; } nodeDetails[nodeKey] = node; // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); } onFilterValueChange(e, nodeKey, attrKey, indx){ let nodeDetails = this.state.nodeDetails; let node = nodeDetails[nodeKey]; if(!node.attrDetails){ node.attrDetails = []; } if(!node.attrDetails[attrKey]){ node.attrDetails[attrKey] = {}; node.attrDetails[attrKey].isSelected = true; node.attrDetails[attrKey].filterValue = []; node.attrDetails[attrKey].filterType = []; node.attrDetails[attrValue].dslPath = []; node.attrDetails[attrValue].dslPathTree = []; } // add the value of the checkbox to nodes array //node.attrDetails[attrKey].filterValue.push(e.target.value); let filterValArr=node.attrDetails[attrKey].filterValue; filterValArr[indx]=e.target.value; node.attrDetails[attrKey].filterValue=filterValArr; nodeDetails[nodeKey] = node; // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); } submitNodeModal = () =>{ if(this.state.selectedNode){ var d = this.state.selectedNode; for(var node in this.state.nodeDetails){ if(this.state.nodeDetails[node].isSelected){ var newNodeObj = { type: 'node', name: this.state.nodeDetails[node].nodeType, details: {} }; //Creates new Node Object.assign(newNodeObj.details, this.state.nodeDetails[node]); var newNode = d3.hierarchy(newNodeObj); newNode.depth = d.depth + 1; newNode.height = d.height - 1; newNode.parent = d; newNode.id = node; if(!d.children){ d.children = []; } if(newNodeObj.details){ var selectedAttributeCount = 0; for (var key in newNodeObj.details.attrDetails){ if (newNodeObj.details.attrDetails[key].isSelected){ selectedAttributeCount++; } if(selectedAttributeCount === Object.keys(newNodeObj.details.attrDetails).length){ newNodeObj.details.includeInOutput = true; } } } d.children.push(newNode); this.setState({ nodeDetails: [] }); } } this.update(this, d); this.setState({ showNodeModal: false, enableModalFeedback: false, traverseToNodes: [], selectedNode: null }); }else{ var nodeType = ""; var attrDetails = null; var dslPath =[]; var dslPathTree=[]; for (var key in this.state.nodeDetails) { if(this.state.nodeDetails[key].isSelected){ nodeType = this.state.nodeDetails[key].nodeType; attrDetails = this.state.nodeDetails[key].attrDetails; dslPath =this.state.nodeDetails[key].dslPath; dslPathTree=this.state.nodeDetails[key].dslPathTree; } } this.build(nodeType, null, attrDetails,null,dslPath,dslPathTree); this.setState({ nodeDetails: [], showNodeModal: false, enableModalFeedback:false, traverseToNodes: [], selectedNode: null }); } } submitEditNodeModal = () =>{ this.update(this, this.state.selectedNode); this.setState({showEditNodeModal: false,showPathFilterDslBuilder:false}); } populateEdgeRules = (nodeType) => { let nodeDetails=GeneralCommonFunctions.populateEdgeRules(nodeType,this.state.edgeRules); this.setState({ nodeDetails: nodeDetails }); } buildOXMAttributesAndReturn = (nodeType) =>{ var oxmArray = []; var result = JSON.parse(OXM); var arrayOfTypes = result['xml-bindings']['java-types'][0]['java-type']; for (var i = 0; i < arrayOfTypes.length; i++) { var propertiesDsl = []; for (var j = 0; j < arrayOfTypes[i]['java-attributes'][0]['xml-element'].length; j++) { let property = arrayOfTypes[i]['java-attributes'][0]['xml-element'][j]['$']['name']; let type = arrayOfTypes[i]['java-attributes'][0]['xml-element'][j]['$']['type']; if (type === 'java.lang.String' || type === 'java.lang.Boolean') { propertiesDsl[property] = {}; propertiesDsl[property].isSelected = false; propertiesDsl[property].attributeName = property; propertiesDsl[property].filterValue = ['']; propertiesDsl[property].filterType = ['']; propertiesDsl[property].dslPath = []; propertiesDsl[property].dslPathTree = []; } } let sortedPropertiesDsl = propertiesDsl.sort(function (filter1, filter2) { if (filter1.attributeName < filter2.attributeName) { return -1; } else if (filter1.attributeName > filter2.attributeName) { return 1; } else { return 0; } }); oxmArray[GeneralCommonFunctions.camelToDash(arrayOfTypes[i]['xml-root-element'][0]['$']['name'])] = sortedPropertiesDsl; } this.setState({oxmMapping: oxmArray}); return oxmArray[nodeType]; } runDSL = () => { console.log("running DSL"); let paramToPassThrough = ''; if(this.state.aggregateObjects){ paramToPassThrough = '/customDsl/built-aggregate/' + btoa('
' + this.state.dslQuery + '
'); }else{ paramToPassThrough = '/customDsl/built/' + btoa('
' + this.state.dslQuery + '
'); } this.props.history.push(paramToPassThrough); } submitEditAndRunDSL = () =>{ this.setState({ dslQuery: this.state.editModel }, () => this.runDSL()); } showEditDSLModal = () => { console.log("enabling DSL edit modal"); this.setState({ editModel: this.state.dslQuery, showEditModal: true }); } closeEditDSLModal = () => { console.log("closing DSL edit modal"); this.setState({ showEditModal: false }); } bindEdits = (e) => { this.setState({ editModel: e.target.value }); } populateDSL = (tree, isInit) =>{ var DSL = ''; var treeArray = ''; var treeArrayLength = 0; if(isInit){ treeArray = tree; treeArrayLength = 1; }else{ treeArray = tree.children; treeArrayLength = tree.children.length; } for(var k = 0; treeArray && k < treeArrayLength; k++){ if(k === 0 && treeArrayLength > 1){ DSL += '['; } var node = ''; if(isInit){ node = tree; }else{ node = treeArray[k]; } if(node.data){ console.log('Node data while rendering DSl path>>',JSON.stringify(node.data)); DSL += node.data.name; let propState=false; if(node.data.details){ var tempAttributeString = ''; var selectedAttributeCount = 0; for (var key in node.data.details.attrDetails){ if (node.data.details.attrDetails[key].isSelected){ selectedAttributeCount++; let aliasWithProp=node.data.details.attrDetails[key].attributeName; if(node.data.details.attrDetails[key].alias){ aliasWithProp= aliasWithProp+'\' as \''+node.data.details.attrDetails[key].alias; } if(selectedAttributeCount === 1){ tempAttributeString += '{\'' + aliasWithProp +'\''; propState=true; }else{ tempAttributeString += ',\'' + aliasWithProp + '\''; } } } if(selectedAttributeCount === Object.keys(node.data.details.attrDetails).length){ DSL+= '*'; } if((selectedAttributeCount < Object.keys(node.data.details.attrDetails).length) && propState){ DSL += tempAttributeString + '}'; } for (var key in node.data.details.attrDetails){ if(node.data.details.attrDetails[key].filterValue && node.data.details.attrDetails[key].filterValue[0] !==''){ DSL += '(\'' + node.data.details.attrDetails[key].attributeName + '\','; let dslValues=''; for(var indx=0; indx0) ? dslValues+',':dslValues; if(this.state.enableRealTime && node.data.details.attrDetails[key].filterType && node.data.details.attrDetails[key].filterType[indx]){ dslValues += node.data.details.attrDetails[key].filterType[indx]+'(\''+ node.data.details.attrDetails[key].filterValue[indx] + '\')'; }else{ dslValues +='\''+node.data.details.attrDetails[key].filterValue[indx] + '\''; } if(node.data.details.attrDetails[key].filterValue.length-1 === indx){ dslValues +=')'; } } DSL += dslValues; } } if(node.data.details.dslPath && node.data.details.dslPath.length>0){ for(var n in node.data.details.dslPath){ DSL += node.data.details.dslPath[n]; } } } } if(node.children){ DSL+= '>' + this.populateDSL(node); } if(k !== treeArrayLength - 1){ DSL += ','; } if(k === treeArrayLength - 1 && treeArrayLength > 1){ DSL += ']'; } } return DSL; } update = (base, source, isInit) => { // Assigns the x and y position for the nodes var treeData = base.state.treemap(base.state.root); var DSL = base.populateDSL(treeData, true); console.log(JSON.stringify("DSL :" + DSL)); this.setState({ dslQuery: DSL }); // Compute the new tree layout. var nodes = treeData.descendants(), links = treeData.descendants().slice(1); var list1 = d3.selectAll(".fa") .filter(".fa-plus") .style("display", "block"); // Normalize for fixed-depth. nodes.forEach(function(d){ d.y = d.depth * 100}); // ****************** Nodes section *************************** // Update the nodes... var node = base.state.g.selectAll('g.node') .data(nodes, function(d) {return d.id }); // Enter any new modes at the parent's previous position. var nodeEnter = node.enter().append('g') .attr('class', 'node') .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) // .on('click', click) .on('dblclick', doubleClick); // Add Circle for the nodes nodeEnter.append('circle') .attr('class', 'node') .attr('r', 1e-6) .style("fill", "lightsteelblue"); nodeEnter.append("svg:foreignObject") .attr("width", 20) .attr("height", 25) .attr("y", -14) .attr("x", -10) .append("xhtml:span") .attr("class", function (d) { let icon = ''; if(!INVLIST.IS_ONAP){ icon = 'icon-datanetwork-serverL'; }else{ icon = 'browse-fa fa fa-server'; } if(d.data.details && d.data.details.parentContainer){ var iconKey = ((d.data.details.parentContainer).replace(/-/g, '')).toUpperCase(); if(INVLIST.INVENTORYLIST[iconKey] && INVLIST.INVENTORYLIST[iconKey].icon){ return INVLIST.INVENTORYLIST[iconKey].icon; }else{ return icon; } }else{ return icon; } }) .style("font-size", function (d) { if (!INVLIST.IS_ONAP){ return "20px"; } else { return "16px"; } }) .attr("id", function (d) {return "nodeIcon" + d.id}) .style("color", '#387dff') .style("display", "block") .style("padding-top",function(d){ if (!INVLIST.IS_ONAP){ return "0px"; } else { return "8px"; } }); nodeEnter.append("svg:foreignObject") .attr("width", 6) .attr("height", 6) .attr("y", 10) .attr("x", -10) .on('click', function (d) { if(d.data.details.isRootNode){ d = null; base.resetBuilder(); }else{ for(var i = 0; d.parent.children && i < d.parent.children.length; i++){ if (d.parent.children.length > 1 && d.data.name === d.parent.children[i].data.name){ d.parent.children.splice(i, 1); }else if (d.parent.children.length === 1 && d.data.name === d.parent.children[i].data.name){ d.parent.children = null; } } base.update(base, d); } }) .append("xhtml:span") .attr("class", "fa fa-minus") .style("padding-top", "1px") .style("font-size", function (d){ return "5px";}) .attr("id", function (d) {return "nodeDelete" + d.data.id}) .style("color", '#387dff') .style("display", function (d) {return "block";}); nodeEnter.append("svg:foreignObject") .attr("width", 6) .attr("height", 6) .attr("y", 10) .attr("x", 5) .on('click', function (d) { base.setState({enableModalFeedback: true}, function () {setTimeout(() => {add(d)},1);})}) .append("xhtml:span") .attr("class", "fa fa-plus") .style("padding-top", "1px") .style("font-size", function (d){ return "5px";}) .attr("id", function (d) {return "nodeAdd" + d.data.id}) .style("color", '#387dff'); nodeEnter.append("svg:foreignObject") .attr("width", 6) .attr("height", 6) .attr("y", -17) .attr("x", -10) .on('click', function (d) { edit(d)}) .append("xhtml:span") .attr("class", "fa fa-pencil-square") .style("padding-top", "1px") .style("font-size", function (d){ return "5px";}) .attr("id", function (d) {return "nodeEdit" + d.data.id}) .style("color", '#387dff'); // Add labels for the nodes nodeEnter.append("svg:foreignObject") .attr("width", 60) .attr("height", 40) .attr("y", -10) .attr("x", -75) .append("xhtml:span") .append('text') .attr("dy", ".35em") .attr("x", function(d) { return d.children ? -13 : 13; }) .text(function(d) { return d.data.name; }) .style("float","right") .style("color", '#000000'); // UPDATE var nodeUpdate = nodeEnter.merge(node); var postNodeDrawnCallBack = function (d){ if(!isInit && base.state.autoZoomEnabled || d.data.details.isRootNode){ base.state.zoomFit(); } } // Transition to the proper position for the node nodeUpdate.transition() .duration(base.state.duration) .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")" }).on("end", postNodeDrawnCallBack); // Update the node attributes and style nodeUpdate.select('circle.node') .attr('r', 11) .style("fill", "lightsteelblue") .attr('cursor', 'pointer'); // Remove any exiting nodes var nodeExit = node.exit().transition() .duration(base.state.duration) .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) .remove(); // On exit reduce the node circles size to 0 nodeExit.select('circle') .attr('r', 1e-6); // On exit reduce the opacity of text labels nodeExit.select('text') .style('fill-opacity', 1e-6); // ****************** links section *************************** // Update the links... var link = base.state.g.selectAll('path.link') .data(links, function(d) { return d.id; }); // Enter any new links at the parent's previous position. var linkEnter = link.enter().insert('path', "g") .attr("class", "link") .attr('d', function(d){ var o = {x: source.x0, y: source.y0} return diagonal(o, o) }); // UPDATE var linkUpdate = linkEnter.merge(link); // Transition back to the parent element position linkUpdate.transition() .duration(base.state.duration) .attr('d', function(d){ return diagonal(d, d.parent) }); // Remove any exiting links var linkExit = link.exit().transition() .duration(base.state.duration) .attr('d', function(d) { var o = {x: source.x, y: source.y} return diagonal(o, o) }) .remove(); // Store the old positions for transition. nodes.forEach(function(d){ d.x0 = d.x; d.y0 = d.y; }); // Creates a curved (diagonal) path from parent to the child nodes function diagonal(s, d) { 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; return path } base.state.svg.on("dblclick.zoom", null); // Toggle children on click. function add(d){ base.populateEdgeRules(d.data.name,base.state.edgeRules); if(!d.children){ d.children = []; d.data.children = []; } base.setState({ selectedNode: d, showNodeModal: true, enableModalFeedback: false }); } function edit(d){ console.log("object editing: " + d); var nodeDetails = base.state.nodeDetails; //set up node details to have the node to edit if(d.data.details.isRootNode && base.props.match.params.type){ var attributes = GeneralCommonFunctions.getFilteringOptions(d.data.details.nodeType); if(Object.keys(attributes).length > 0){ nodeDetails[0] = {}; nodeDetails[0].isRootNode = true; nodeDetails[0].nodeType = base.props.match.params.type; nodeDetails[0].isSelected = true; nodeDetails[0].attrDetails = attributes; if(base.state.initialRootEdit){ for (var key in nodeDetails[0].attrDetails) { nodeDetails[0].attrDetails[key].isSelected = true; } } nodeDetails[0].parentContainer = GeneralCommonFunctions.populateContainer(base.props.match.params.type); for (var key in d.data.details.attrDetails) { nodeDetails[0].attrDetails[key] = d.data.details.attrDetails[key]; if(base.state.initialRootEdit){ nodeDetails[0].attrDetails[key].filterType = []; nodeDetails[0].attrDetails[key].filterType.push('EQ'); } } } d.data.details = nodeDetails[0]; base.setState({ initialRootEdit: false }); }else{ nodeDetails[0] = d.data.details; } base.setState({ selectedNode: d, showEditNodeModal: true, showPathFilterDslBuilder: false }); } function doubleClick(d) { edit(d); } } selectAll = (nodeKey) =>{ var nodeDetails = this.state.nodeDetails; for (var key in nodeDetails[nodeKey].attrDetails) { nodeDetails[nodeKey].attrDetails[key].isSelected = true; } this.setState({nodeDetails: nodeDetails}); } deselectAll = (nodeKey) =>{ var nodeDetails = this.state.nodeDetails; for (var key in nodeDetails[nodeKey].attrDetails) { nodeDetails[nodeKey].attrDetails[key].isSelected = false; } this.setState({nodeDetails: nodeDetails}); } build = (type, propID, attrDetails, preBuiltTree,dslPath,dslPathTree) =>{ var selected = null; var treeData; if(!preBuiltTree && type && (propID || attrDetails)){ let nodeType = type; treeData = { "name": nodeType, "id": nodeType, "children": [], "details":{}, "dslPath":[], "dslPathTree":[] } treeData.details.includeInOutput = true; treeData.details.isSelected = true; treeData.details.isRootNode = true; treeData.details.nodeType = nodeType; if(attrDetails){ treeData.details.attrDetails = attrDetails; } else{ treeData.details.attrDetails = {}; } if(dslPath && dslPath.length>0 && dslPathTree && dslPathTree.length>0){ treeData.details.dslPath=dslPath; treeData.details.dslPathTree=dslPathTree; } if(propID){ let propIds = (propID) ? propID.split(';') : ''; let propertyValue = ''; for(var i in propIds){ let propValue = propIds[i].split(':'); console.log(propValue[0] + '....' + propValue[1]); treeData.details.attrDetails[propValue[0]] = {}; treeData.details.attrDetails[propValue[0]].filterValue=[]; treeData.details.attrDetails[propValue[0]].filterValue.push(atob(propValue[1]).replace('
','').replace('
','')); treeData.details.attrDetails[propValue[0]].attributeName = propValue[0]; treeData.details.attrDetails[propValue[0]].isSelected = true; } } }else if (preBuiltTree){ treeData = preBuiltTree; if(treeData.details && treeData.details.dslPathTree && treeData.details.dslPathTree.length>0){ for(var x=0;x0){ for(var x=0;x{this.update(this, root, true);}) // Collapse the node and all it's children function collapse(d) { if(d.children) { d.children.forEach(collapse) d.children = null } } } updateDslPathValueOnExtract=(treeDataChildren)=>{ if(treeDataChildren.details && treeDataChildren.details.dslPathTree && treeDataChildren.details.dslPathTree.length>0){ for(var x=0;x0){ for(var x=0;x{ console.log(listname+'onTargetMenuOfFilterTypes',id); let keysOfArray=id.split('#'); let nodekey=keysOfArray[0]; let attrKey=keysOfArray[1]; let indx=parseInt(keysOfArray[2]); let nodeDetails = this.state.nodeDetails; let node = nodeDetails[nodekey]; if(!node.attrDetails){ node.attrDetails = []; } if(!node.attrDetails[attrKey]){ node.attrDetails[attrKey] = {}; node.attrDetails[attrKey].isSelected = true; node.attrDetails[attrKey].filterValue = []; node.attrDetails[attrKey].filterType = []; }else{ let filterTypes=node.attrDetails[attrKey].filterType; filterTypes[indx]=listname; node.attrDetails[attrKey].filterType=filterTypes; } nodeDetails[nodekey] = node; // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); }; filterTags = (key,property,state) =>{ let filterTags =''; let filters=''; state=true;//always enable, in future if wants to disable remove this line if(APERTURE_SERVICE && this.state.enableRealTime){ let nodeDetails = this.state.nodeDetails; let node = nodeDetails[key]; filterTags= Object.keys(Object.keys(node.attrDetails[property].filterType)).map((indx) =>{ let selectedFilter=(node.attrDetails[property].filterType[indx]!=='')?node.attrDetails[property].filterType[indx]:this.state.filterTypeDisplay; return
}); filters= {filterTags}; } return filters; }; addOrTemplate=(nodeKey,attrKey,indx)=>{ let nodeDetails = this.state.nodeDetails; let node = nodeDetails[nodeKey]; node.attrDetails[attrKey].filterValue.push(''); node.attrDetails[attrKey].filterType.push('EQ'); nodeDetails[nodeKey] = node; // update the state with the new array of traverse to nodes this.setState({ nodeDetails: nodeDetails }); }; deleteOrTemplate=(nodeKey,attrKey,index)=>{ let nodeDetails = this.state.nodeDetails; let node = nodeDetails[nodeKey]; let filterValuesArray=node.attrDetails[attrKey].filterValue; let filterTypeArray=node.attrDetails[attrKey].filterType; filterValuesArray.splice(index,1); filterTypeArray.splice(index,1); node.attrDetails[attrKey].filterValue=filterValuesArray; node.attrDetails[attrKey].filterType=filterTypeArray; nodeDetails[nodeKey] = node; this.setState({ nodeDetails: nodeDetails }); } toggleRealTimeAnalysisCallback=(checked)=>{ console.log('toggleRealTimeAnalysisCallback>>>>',checked); sessionStorage.setItem(ENVIRONMENT + 'ENABLE_ANALYSIS', !checked); this.baseState.enableRealTime=!checked; this.baseState.init= true; this.setState({...this.baseState},()=>{document.getElementById("DSLBuilder").innerHTML='';}); } renderPathFilterBuilder=(key,dslPath,dslPathTree)=>{ console.log('renderPathFilterBuilder>>>>',key); let attrDetails=this.state.nodeDetails[key].attrDetails; let nodeType=this.state.nodeDetails[key].nodeType; this.setState({showPathFilterDslBuilder: true,pathFilterNodeType: key,pathFilterNodeName:nodeType,pathFIlterAttrDetails: attrDetails,dslPathBuilder: dslPath,dslPathTree:dslPathTree,isEditEnable:false}); } /* Load Functions */ getAndPopulateTreeFromDSL = (dslQuery) =>{ var treeObject = []; var payload = {dsl: dslQuery}; settings['ISAPERTURE'] = true; commonApi(settings, 'dsl/convert-query-to-tree', 'PUT', payload, 'ConvertQueryToTree') .then(res => { console.log('res:' + res.data, 'load'); if(res.status === 200 || res.status === 404){ if(res.data.status && (res.data.status !== 200 && res.data.status !== 201 && res.data.status !== 404)){ this.triggerError(res.data, 'treeLoad'); }else{ treeObject = res.data; this.setState({ enableTreeLoadBusyFeedback:false, treeLoadErrMsg: null }); console.log("TREE OBJECT: " + JSON.stringify(treeObject)); //clear the svg if(this.state.svg){ this.state.svg.selectAll("*").remove(); } //set the init state this.setState({init: true, dslQuery: '', initialRootEdit: false, nodeDetails: [], selectedNode: null }); var initNode = this.extractNodeDetails(treeObject.children[0], true); if(!this.state.treeLoadErrMsg || this.state.treeLoadErrMsg === ''){ console.log(JSON.stringify(initNode)); this.build(null, null, null, initNode); setTimeout(() => { this.state.zoomFit() }, 600); //scroll to the hidden static modal since svg offsetTop doesnt work for DSLBuilder id GeneralCommonFunctions.scrollTo('customDslBuilderModel'); }else{ this.triggerError(null, 'invalidQuery'); } } }else{ this.triggerError(res.data, 'treeLoad'); } }, error=>{ if(error.response.status === 404){ this.setState({enableTreeLoadBusyFeedback:false}); }else{ this.triggerError(error.response.data, 'treeLoad'); } }).catch(error => { this.triggerError(error, 'treeLoad'); }) }; resetBuilder = () => { if(this.state.svg){ this.state.svg.selectAll("*").remove(); } this.setState({ init: true, dslQuery: '', queryName:'', queryDescription:'', initialRootEdit: false, nodeDetails: [], selectedNode: null, treeLoadErrMsg: '', enableTreeLoadBusyFeedback: false, aggregateObjects: false }); } triggerError = (error, type) => { console.error('[CustomDslBuilder.jsx] error : ', JSON.stringify(error)); let errMsg = ''; if(error && error.status && error.message){ errMsg += "Error Occurred: " + error.status + ' - ' +error.message; }else{ errMsg += "Error Occurred: " + JSON.stringify(error); } console.log(errMsg); if(type === 'treeLoad' || type === 'invalidQuery'){ this.resetBuilder(); var errorMessage = errMsg; if(type === 'invalidQuery'){ errorMessage = 'The loaded query uses DSL syntax not supported by the DSL Builder,' + ' please only load queries compatible with the builder. For more' + ' information on this error, please contact an administrator.'; } this.setState({treeLoadErrMsg: errorMessage}); GeneralCommonFunctions.scrollTo('treeLoadErrorMessage'); }else{ console.log('[CustomDslBuilder.jsx] :: triggerError invoked with invalid type : ' + type); } } validLoadableDSL = (dslQuery) => { var valid = false; dslQuery = dslQuery.replace(/\s/g, ''); valid = dslQuery.indexOf(']>') === -1 && !(new RegExp("LIMIT[0-9]+$").test(dslQuery)); return valid; } loadCallback = (name, description, category, dslQuery, isAggregate, type, queryId, id, templateDetails, makeCall) =>{ var decodedDslQuery = atob(dslQuery).replace('
','').replace('
',''); if(this.validLoadableDSL(decodedDslQuery)){ if(name !== '' && description !== ''){ this.setState({ queryName:name, queryDescription:description, category:category, isPublicChecked: type === 'public', queryId: queryId, treeLoadErrMsg: null, aggregateObjects: isAggregate === "true" }); console.log("DSL Query Loaded: "+ decodedDslQuery); console.log("DSL Query Name: "+ name); console.log("DSL Query Description: "+ description); console.log("DSL Query ID: "+ queryId); console.log("DSL Query Category: "+ category); console.log("DSL Query isAggregate: "+ isAggregate); console.log("DSL Query type: "+ type); var treeObject = this.getAndPopulateTreeFromDSL(decodedDslQuery); } }else{ this.triggerError(null, "invalidQuery"); } } extractNodeDetails = (node, isRoot) =>{ let nodeType = node['node-type']; let nodeData = { "name": nodeType, "id": nodeType, "children": [], "details":{} } nodeData.details.includeInOutput = node.store; nodeData.details.isSelected = true; nodeData.details.isRootNode = isRoot; nodeData.details.nodeType = nodeType; var attributes = GeneralCommonFunctions.getFilteringOptions(nodeType); nodeData.details.attrDetails = attributes; nodeData.details.parentContainer = GeneralCommonFunctions.populateContainer(nodeType); if(node.store && !node['requested-props']){ for(var key in nodeData.details.attrDetails){ nodeData.details.attrDetails[key].isSelected = true; } }else if (node.store && node['requested-props']){ for(var key in node['requested-props']){ nodeData.details.attrDetails[key].isSelected = true; nodeData.details.attrDetails[key].alias=node['requested-props'][key]; } } var isValid = true; for (var x in node['node-filter']){ if(isValid){ for (var y in node['node-filter'][x]) { if(isValid){ var attrKey = node['node-filter'][x][y]['key']; var filter = node['node-filter'][x][y]['filter']; //If aperture is not turned on and query loaded uses anything besides EQ throw error if(!APERTURE_SERVICE && filter !== 'EQ'){ this.triggerError(null, "invalidQuery"); isValid = false; } if(!nodeData.details.attrDetails[attrKey]){ nodeData.details.attrDetails[attrKey] = {}; } if(nodeData.details.attrDetails[attrKey].filterType.length > 0 && nodeData.details.attrDetails[attrKey].filterType[0] === ''){ nodeData.details.attrDetails[attrKey].filterType = []; } if(nodeData.details.attrDetails[attrKey].filterValue.length > 0 && nodeData.details.attrDetails[attrKey].filterValue[0] === ''){ nodeData.details.attrDetails[attrKey].filterValue = []; } //if a filter had no values associated to it throw a not supported error if(node['node-filter'][x][y]['value'][0]){ for (var i in node['node-filter'][x][y]['value']){ nodeData.details.attrDetails[attrKey].filterType.push(filter); nodeData.details.attrDetails[attrKey].filterValue.push(node['node-filter'][x][y]['value'][i]); } if(!nodeData.details.attrDetails[attrKey].attributeName){ nodeData.details.attrDetails[attrKey].attributeName = attrKey; } }else{ this.triggerError(null, "invalidQuery"); isValid = false; } } } } } var initWhereNode = null; if(node['where-filter'].length > 0){ for(var index in node['where-filter']){ initWhereNode = this.extractNodeDetails(node['where-filter'][index].children[0], true); } } if(initWhereNode){ nodeData.details.dslPath=[]; nodeData.details.dslPathTree=[]; nodeData.details.dslPathTree.push(initWhereNode); } if(node.children.length > 0){ for(var i = 0; i < node.children.length; i++){ nodeData.children[i] = this.extractNodeDetails(node.children[i], false); } } return nodeData; } setQueriesState = (savedQueries) =>{ this.setState({ loadedQueries: savedQueries }); }; /* End Load Functions */ render(){ var toggelRealtimeAnalysis = ''; if(APERTURE_SERVICE){ toggelRealtimeAnalysis =
{ this.toggleRealTimeAnalysisCallback(checked); }} />
} return(
{toggelRealtimeAnalysis}

Visual Query Builder for Build Your Own Query

Visually build your own query, you can click the + icon to add objects to your query, - icon to remove objects from your query, or the pencil icon/double click to edit attributes. Single click and drag in the view to pan, use scrollwheel or pinch to zoom.

Modify Query
{Object.keys(this.state.nodeDetails).sort().map((key, node) => (
Options
Options
{this.state.nodeDetails[key].dslPath && this.state.nodeDetails[key].dslPath.length>0 && DSL PATH Filter Action } {this.state.nodeDetails[key].dslPath && Object.keys(this.state.nodeDetails[key].dslPath).map((indx) => { return(
{this.state.nodeDetails[key].dslPath[indx]}
) })}
Include in Output {APERTURE_SERVICE && this.state.enableRealTime && Filter Types } Filter By (Optional) {Object.keys(this.state.nodeDetails[key].attrDetails).sort().map((attrKey, attr) => { return(
{this.filterTags(key,attrKey,this.state.nodeDetails[key].attrDetails[attrKey].isSelected)} {Object.keys(this.state.nodeDetails[key].attrDetails[attrKey].filterValue).map((indx) =>{ return(
{this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] ==='' && {this.onFilterValueChange(e, key, attrKey,indx);}} /> } {this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx] !=='' && {this.onFilterValueChange(e, key, attrKey,indx);}} placeholder={"Enter " + attrKey } className='inputFilter' value={this.state.nodeDetails[key].attrDetails[attrKey].filterValue[indx]} /> } {indx == 0 && } {indx > 0 && }
) })}
); } )}
))}
Build DSL Path
Modify Node
{this.state.selectedNode && this.state.selectedNode.data && this.state.selectedNode.data.details && this.state.nodeDetails[0] && this.state.nodeDetails[0].dslPath && this.state.nodeDetails[0].dslPath.length>0 && DSL PATH Filter Action }
{this.state.selectedNode && this.state.selectedNode.data && this.state.selectedNode.data.details && this.state.nodeDetails[0] && this.state.nodeDetails[0].dslPath && Object.keys(this.state.nodeDetails[0].dslPath).map((indx) => { return(
{this.state.nodeDetails[0].dslPath[indx]}
) })}
Include in Output {this.state.enableRealTime && Filter Types } Filter By (Optional) {this.state.selectedNode && this.state.selectedNode.data && this.state.selectedNode.data.details && this.state.nodeDetails[0] && Object.keys(this.state.nodeDetails[0].attrDetails).sort().map((attrKey, attr) => { return(
{this.filterTags(0,attrKey, this.state.nodeDetails[0].attrDetails[attrKey].isSelected)} {Object.keys(this.state.nodeDetails[0].attrDetails[attrKey].filterValue).map((indx) =>{ return(
{this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] ==='' && {this.onFilterValueChange(e, 0, attrKey, indx);}} /> } {this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx] !=='' && {this.onFilterValueChange(e, 0, attrKey,indx);}} placeholder={"Enter " + attrKey } className='inputFilter' value={this.state.nodeDetails[0].attrDetails[attrKey].filterValue[indx]} /> } {indx == 0 && } {indx > 0 && }
) })}
); } )}
Build DSL Path
Edit DSL Query
DSL Query

{this.state.queryName}

{this.state.queryDescription}

DSL Query: {this.state.dslQuery}

{this.state.enableModalFeedback && }
); } } export default CustomDslBuilder;