summaryrefslogtreecommitdiffstats
path: root/src/generic-components
diff options
context:
space:
mode:
authorwr148d <wr148d@att.com>2021-01-15 15:32:00 -0500
committerwr148d <wr148d@att.com>2021-02-11 09:47:17 -0500
commit5ee7367a101143715c2869d72ea4a6fbf55f5af6 (patch)
tree84bf43601c0cce4fb37b5b3b494e113c96d5591e /src/generic-components
parentddc05d4ea0254b427fea6ec80e2b03950eeca4ce (diff)
Updated Sparky to add ECOMP functionality Browse, Specialized Search, BYOQ, and the Builder FE Updates
Issue-ID: AAI-3250 Change-Id: I576e37f77f7e9b40d72e4a5e7de645e9f62bc7d2 Signed-off-by: wr148d <wr148d@att.com>
Diffstat (limited to 'src/generic-components')
-rw-r--r--src/generic-components/DownloadRangeModel.jsx236
-rw-r--r--src/generic-components/InfoToggle.jsx106
-rw-r--r--src/generic-components/MultiSelectDropDown.jsx56
-rw-r--r--src/generic-components/OutputToggle.jsx53
-rw-r--r--src/generic-components/OutputVisualization.jsx331
-rw-r--r--src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx64
-rw-r--r--src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js1
-rw-r--r--src/generic-components/filter/Filter.jsx270
-rw-r--r--src/generic-components/filter/components/AddFilters.jsx27
-rw-r--r--src/generic-components/filter/components/ClearFilter.jsx27
-rw-r--r--src/generic-components/filter/components/FilterTypes.jsx102
-rw-r--r--src/generic-components/filter/components/RunFilterQuery.jsx56
-rw-r--r--src/generic-components/filter/components/SelectFilter.jsx100
13 files changed, 1427 insertions, 2 deletions
diff --git a/src/generic-components/DownloadRangeModel.jsx b/src/generic-components/DownloadRangeModel.jsx
new file mode 100644
index 0000000..239ba64
--- /dev/null
+++ b/src/generic-components/DownloadRangeModel.jsx
@@ -0,0 +1,236 @@
+/*
+ * ============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 Modal from 'react-bootstrap/lib/Modal';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+import Row from 'react-bootstrap/lib/Row';
+import Button from 'react-bootstrap/lib/Button';
+import Spinner from 'utils/SpinnerContainer.jsx';
+
+let PAGINATION_CONSTANT = GlobalExtConstants.PAGINATION_CONSTANT;
+let PAGINATION_RESULTS = PAGINATION_CONSTANT.RESULTS_PER_PAGE;
+
+class DownloadRangeModel extends Component {
+ constructor(props){
+ super(props);
+ let totalPages = Math.ceil(this.props.totalResults/PAGINATION_RESULTS);
+ let defaultCount = (totalPages < 10)? totalPages : 10;
+ let defaultPageRange = defaultCount*PAGINATION_RESULTS;
+ this.state = {
+ defaultPageCount : defaultCount,
+ downloadType: 'defaultPage',
+ totalPages:totalPages,
+ limitTotalPages:defaultCount,
+ startPageCount:'',
+ endPageCount:'',
+ defaultPageError:false,
+ downloadPageRangeError:false,
+ defaultPageErrorMsg:'',
+ downloadPageRangeErrorMsg:'',
+ showDownloadResultsModal:this.props.showDownloadResultsModal,
+ triggerDownload:this.props.triggerDownload,
+ triggerClose:this.props.triggerClose,
+ totalResults: this.props.totalResults,
+ errorDownloadResults:this.props.errorDownloadResults,
+ downloadErrorMsg:this.props.downloadErrorMsg,
+ pageRange:defaultPageRange,
+ enableBusyFeedback: this.props.enableModelBusyFeedback
+ };
+ };
+ componentDidMount(){
+ console.log('DownloadRange component mount');
+ };
+ componentWillReceiveProps(nextProps){
+ console.log('DownloadRange component componentWillReceiveProps',nextProps);
+ let totalPages = Math.ceil(nextProps.totalResults/PAGINATION_RESULTS);
+ let defaultCount = (totalPages < 10)? totalPages : 10;
+ let defaultPageRange = defaultCount*PAGINATION_RESULTS;
+ this.setState({
+ showDownloadResultsModal:nextProps.showDownloadResultsModal,
+ errorDownloadResults:nextProps.errorDownloadResults,
+ downloadErrorMsg:nextProps.downloadErrorMsg,
+ enableBusyFeedback: nextProps.enableModelBusyFeedback,
+ totalPages:totalPages,
+ limitTotalPages:defaultCount,
+ defaultPageCount: defaultCount
+ });
+ }
+ renderError = (errorMsg) => {
+ return(
+ <Row className='show-grid topBottomMargin'>
+ <span className='label badge-pill label-danger topBottomMargin pre-wrap-text'><strong>Error</strong>: {errorMsg}</span>
+ </Row>
+ );
+ };
+ onInputDataChange = (event) =>{
+ let name=event.target.name;
+ let value= (event.target.value !== '')? parseInt(event.target.value): '';
+ this.onDataValidate(name,value);
+ }
+ onDataValidate =(name,value) =>{
+ console.log('DownloadRangeModel onDataValidate>>>>>>',this.state);
+ let pageCount=1;
+ let msg='';
+ let totalCount = 0;
+ let totalResultsCount=0;
+ if(name === 'defaultPageCount'){
+ if(isNaN(value)){
+ msg = 'Please enter valid input as Number';
+ }else if(value <= 0){
+ msg = 'Please enter valid page count From 1 to ' + this.state.limitTotalPages;
+ }else if(value > this.state.limitTotalPages ){
+ msg = 'Please enter valid page count From 1 to ' + this.state.limitTotalPages+'.The maximum download is limited to '+this.state.limitTotalPages +' pages at a time';
+ }
+ if(msg === ''){
+ pageCount=value*PAGINATION_RESULTS;
+ console.log('Before setting state defaultPageCount>>>>>',value);
+ this.setState({defaultPageCount:value,pageRange:pageCount,defaultPageError:false,defaultPageErrorMsg:'',disableDownloadBtn:false});
+ }else if(msg !== ''){
+ this.setState({defaultPageCount:event.target.value,defaultPageError:true,defaultPageErrorMsg:msg,disableDownloadBtn:true});
+ }
+ }else if(name === 'startPageCount'){
+ if(isNaN(value)){
+ msg = 'Please enter valid input as Number';
+ }
+ if(msg === ''){
+ console.log('Before setting state startPageCount>>>>>',value);
+ this.setState({startPageCount:value,downloadPageRangeError:false,downloadPageRangeErrorMsg:'',disableDownloadBtn:false},function(){this.onDataValidate('rangeValidation')}.bind(this));
+ }else{
+ this.setState({downloadPageRangeError:true,downloadPageRangeErrorMsg:msg,disableDownloadBtn:true});
+ }
+ }else if(name === 'endPageCount'){
+ if(isNaN(value)){
+ msg = 'Please enter valid input as Number';
+ }
+ if(msg === ''){
+ console.log('Before setting state endPageCount>>>>>',value);
+ this.setState({endPageCount: value,downloadPageRangeError: false, downloadPageRangeErrorMsg: '',disableDownloadBtn:false},function(){this.onDataValidate('rangeValidation')}.bind(this));
+ }else{
+ this.setState({downloadPageRangeError:true,downloadPageRangeErrorMsg:msg,disableDownloadBtn:true});
+ }
+ }
+ if(name === 'rangeValidation'){
+ let startCount = this.state.startPageCount;
+ startCount=(startCount === '')? 0:parseInt(startCount);
+ let endCount = this.state.endPageCount;
+ endCount=(endCount === '')? 0:parseInt(endCount);
+ if(startCount <= 0 || endCount <= 0 || startCount > this.state.totalPages || endCount > this.state.totalPages || startCount > endCount || endCount < startCount){
+ msg = 'Please enter a valid page range from 1 to '+ this.state.totalPages +'.The maximum download is limited to '+ this.state.limitTotalPages +' pages at a time';
+ }else{
+ totalCount = this.state.endPageCount - this.state.startPageCount + 1;
+ totalResultsCount=totalCount*PAGINATION_RESULTS;
+ if(totalCount > 10){
+ msg = 'The maximum download is limited to '+ this.state.limitTotalPages +' pages at a time. Please adjust your input to continue';
+ }
+ }
+ if(msg !== ''){
+ this.setState({downloadPageRangeError:true,downloadPageRangeErrorMsg:msg,disableDownloadBtn:true});
+ }else{
+ pageCount=this.state.startPageCount + '-' + this.state.endPageCount;
+ this.setState({disableDownloadBtn: false, pageRange: pageCount});
+ }
+ }
+ };
+ setSelectTypeOfDownload = (event) =>{
+ console.log('DownloadRange:setSelectTypeOfDownload',event.target.value);
+ let totalPages=parseInt(this.state.totalPages);
+ let pageCount=0;
+ if (event.target.value === 'downloadPageRange'){
+ this.setState(
+ {defaultPageCount : (totalPages < 10)? totalPages : 10,startPageCount:'',endPageCount:'',downloadType:event.target.value,downloadPageRangeError:false,defaultPageError:false,disableDownloadBtn:true, downloadErrorMsg:'', errorDownloadResults:false}
+ );
+ }else{
+ pageCount= (totalPages < 10)? totalPages*PAGINATION_RESULTS : 10*PAGINATION_RESULTS;
+ this.setState({defaultPageCount : (totalPages < 10)? totalPages : 10, startPageCount:'',endPageCount:'',pageRange:pageCount,downloadType:event.target.value,downloadPageRangeError:false,defaultPageError:false,disableDownloadBtn:false, downloadErrorMsg:'',errorDownloadResults:false});
+ }
+ }
+ submitDownloadResults = () =>{
+ console.log('DownloadRange:submitDonwloadResults',this.state);
+ this.props.triggerDownload(this.state.pageRange,true);
+ }
+ closeDownloadResults = () =>{
+ console.log('DownloadRange:closeDownloadReults');
+ this.props.triggerClose();
+ }
+ render(){
+ console.log('downloadRange:this.state>>>>>>>>>>>*',this.state);
+ return(
+ <div id='downloadPagePane' className='addPadding customDsl'>
+ <div className='static-modal'>
+ <Modal show={this.state.showDownloadResultsModal} onHide={this.closeDownloadResults}>
+ <Modal.Header>
+ <Modal.Title>Download Results</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <h4>Your result set has <strong>{this.state.totalPages}</strong> pages</h4>
+ {this.state.errorDownloadResults && (<div>{this.renderError(this.state.downloadErrorMsg)}</div>)}
+ <form id='downloadRangeForm' name='downloadRangeForm'>
+ <div className="radio">
+ <label>
+ <input type="radio" value="defaultPage"
+ checked={this.state.downloadType === 'defaultPage'}
+ onChange={(e) => this.setSelectTypeOfDownload(e)} />
+ <input type='number' size='8' name='defaultPageCount'
+ onBlur={(event) => this.onInputDataChange(event)}
+ placeholder='Default Page Count'
+ value={this.state.defaultPageCount}
+ disabled={!(this.state.downloadType === 'defaultPage')}
+ onChange={(event) => this.onInputDataChange(event)} />
+ <span>pages</span>
+ </label>
+ {this.state.defaultPageError && (<div>{this.renderError(this.state.defaultPageErrorMsg)}</div>)}
+ </div>
+ <div className="radio">
+ <label>
+ <input type="radio" value="downloadPageRange"
+ checked={this.state.downloadType === 'downloadPageRange'}
+ onChange={(e) => this.setSelectTypeOfDownload(e)} />
+ From
+ <span><input type='number' size='8' name='startPageCount'
+ onBlur={(event) => this.onInputDataChange(event)}
+ placeholder='Start Page'
+ disabled={!(this.state.downloadType === 'downloadPageRange')}
+ value={this.state.startPageCount}
+ onChange={(event) => this.onInputDataChange(event)} /></span>
+ <span>To</span>
+ <span><input type='number' size='8' name='endPageCount'
+ onBlur={(event) => this.onInputDataChange(event)}
+ placeholder='End Page'
+ value={this.state.endPageCount}
+ disabled={!(this.state.downloadType === 'downloadPageRange')}
+ onChange={(event) => this.onInputDataChange(event)} /></span>
+ <span>pages</span>
+ </label>
+ {this.state.downloadPageRangeError && (<div>{this.renderError(this.state.downloadPageRangeErrorMsg)}</div>)}
+ </div>
+ </form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button onClick={this.closeDownloadResults}>Close</Button>
+ <Button onClick={this.submitDownloadResults} disabled={this.state.disableDownloadBtn}>Download</Button>
+ </Modal.Footer>
+ </Modal>
+ </div>
+ </div>
+ );
+ }
+}
+export default DownloadRangeModel;
diff --git a/src/generic-components/InfoToggle.jsx b/src/generic-components/InfoToggle.jsx
new file mode 100644
index 0000000..928eea7
--- /dev/null
+++ b/src/generic-components/InfoToggle.jsx
@@ -0,0 +1,106 @@
+/*
+ * ============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 Modal from 'react-bootstrap/lib/Modal';
+import Col from 'react-bootstrap/lib/Col';
+import Row from 'react-bootstrap/lib/Row';
+import Tabs from 'react-bootstrap/lib/Tabs';
+import Button from 'react-bootstrap/lib/Button';
+import Tab from 'react-bootstrap/lib/Tab';
+import BootstrapTable from 'react-bootstrap-table-next';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+
+
+class InfoToggle extends Component {
+ constructor(props){
+ console.log(props);
+ super(props);
+ this.props = props;
+ this.state = {
+ showInfoModal: false
+ };
+ }
+ openInfoModal = () =>{
+ this.setState({showInfoModal:true});
+ }
+ closeInfoModal = () =>{
+ this.setState({showInfoModal:false});
+ }
+ getReferenceJson = (reference) =>{
+ return require('app/assets/configuration/' + GlobalExtConstants.PATHNAME + '/reference/' + reference + '.json');
+ }
+ render(){
+ let tableColumnsList = [];
+ let tableDataList = [];
+ let types = this.getReferenceJson('types');
+ types.map(type => {
+ tableColumnsList[type] = [];
+ tableDataList[type] = this.getReferenceJson(type);
+ for(var key in tableDataList[type][0]){
+ var isHidden = key === 'id';
+ tableColumnsList[type].push({dataField: key, text: key, hidden: isHidden });
+ }
+ });
+ let tabs=types.map((nodeType,index) => {
+ return(
+ <Tab eventKey={nodeType} title={nodeType}>
+ <BootstrapTable
+ id={nodeType}
+ keyField='id'
+ data={tableDataList[nodeType]}
+ columns={tableColumnsList[nodeType]}
+ bordered={ true }
+ headerClasses='table-header-view'
+ bootstrap4 striped hover condensed
+ />
+ </Tab>
+ )
+ });
+ if (!GlobalExtConstants.INVLIST.IS_ONAP){
+ return (
+ <div>
+ <div className='static-modal'>
+ <Modal show={this.state.showInfoModal} onHide={this.closeInfoModal}>
+ <Modal.Header>
+ <Modal.Title>Information</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Tabs defaultActiveKey={types[0]} id="multipleTabularView">
+ {tabs}
+ </Tabs>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button onClick={this.closeInfoModal}>Close</Button>
+ </Modal.Footer>
+ </Modal>
+ </div>
+ <div className='col-xs-1'>
+ <i className='dsl-hint icon-documents-manual' onClick={this.openInfoModal} ></i>
+ <pre>Info</pre>
+ </div>
+ </div>);
+ }else{
+ return (<span></span>);
+ }
+ }
+};
+
+export default InfoToggle;
diff --git a/src/generic-components/MultiSelectDropDown.jsx b/src/generic-components/MultiSelectDropDown.jsx
new file mode 100644
index 0000000..e9124a5
--- /dev/null
+++ b/src/generic-components/MultiSelectDropDown.jsx
@@ -0,0 +1,56 @@
+/*
+ * ============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 Select from 'react-select';
+
+class MultiSelectDropDown extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ options:[],
+ displayValue:'Category'
+ };
+ }
+ componentDidMount(){
+ console.log('MultiSelectDropDown component mount');
+ };
+ componentWillReceiveProps(nextProps){
+ console.log('MultiSelectDropDown component componentWillReceiveProps',nextProps);
+ this.setState({
+ options:nextProps.options,
+ displayValue:nextProps.displayValue,
+ triggerSelect:nextProps.triggerSelect,
+ });
+ }
+ render() {
+ return (
+ <Select
+ className='dropdown-item basic-multi-select'
+ placeholder={this.state.displayValue}
+ onChange={this.state.triggerSelect}
+ options={this.state.options}
+ isMulti
+ classNamePrefix="select"
+ />
+ );
+ }
+}
+export default MultiSelectDropDown;
diff --git a/src/generic-components/OutputToggle.jsx b/src/generic-components/OutputToggle.jsx
new file mode 100644
index 0000000..9d82260
--- /dev/null
+++ b/src/generic-components/OutputToggle.jsx
@@ -0,0 +1,53 @@
+/*
+ * ============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 from 'react';
+import Col from 'react-bootstrap/lib/Col';
+import Row from 'react-bootstrap/lib/Row';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+
+let PAGINATION_CONSTANT = GlobalExtConstants.PAGINATION_CONSTANT;
+
+const OutputToggle = (props) => {
+
+ return (
+ <div className="addPaddingSide">
+ <Row className='show-grid'>
+ <Col md={8}>
+ <button type='button' className={'btn ' + ((props.scope.state.viewName === "CardLayout") ? 'btn-primary' : 'btn-outline-secondary')} value="CardLayout" onClick={(e) => props.scope.setViewName(e)}><i className={'icon-content-gridL ' + ((props.scope.state.viewName === "CardLayout") ? 'tabIconChosen' : 'tabIconNotChosen')} role="img"></i></button>
+ {!props.cellDisabled && <button type='button' className={'btn ' + ((props.scope.state.viewName === "CellLayout") ? 'btn-primary' : 'btn-outline-secondary')} value="CellLayout" onClick={(e) => props.scope.setViewName(e)}><i className={'icon-content-gridguideL ' + ((props.scope.state.viewName === "CellLayout") ? 'tabIconChosen' : 'tabIconNotChosen')} role="img"></i></button>}
+ {!props.visualDisabled && <button type='button' className={'btn ' + ((props.scope.state.viewName === "VisualLayout") ? 'btn-primary' : 'btn-outline-secondary')} value="VisualLayout" onClick={(e) => props.scope.setViewName(e)}><i className={'icon-datanetwork-globalnetworkL ' + ((props.scope.state.viewName === "VisualLayout") ? 'tabIconChosen' : 'tabIconNotChosen')} role="img"></i></button>}
+ </Col>
+ </Row>
+ <Row className='show-grid'>
+ <Col md={8}>
+ <div className='checkbox'>
+ <label>
+ {props.scope.state.viewName !== 'VisualLayout' && <input type='checkbox' className='radio' value={props.scope.state.viewName} name='defaultViewName' checked={props.scope.state.viewName === props.scope.state.defaultViewName} onChange={(e) => props.scope.setDefaultViewName(e)} disabled={props.scope.state.viewName === props.scope.state.defaultViewName}/>}
+ {props.scope.state.viewName !== 'VisualLayout' && (props.scope.state.viewName === props.scope.state.defaultViewName ? 'Default View' : 'Set as Default View')}
+ </label>
+ </div>
+ </Col>
+ </Row>
+ </div>
+ );
+};
+
+export default OutputToggle;
diff --git a/src/generic-components/OutputVisualization.jsx b/src/generic-components/OutputVisualization.jsx
new file mode 100644
index 0000000..734887d
--- /dev/null
+++ b/src/generic-components/OutputVisualization.jsx
@@ -0,0 +1,331 @@
+/*
+ * ============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 from 'react';
+import * as d3 from "d3";
+import 'd3-selection-multi';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+
+let INVLIST = GlobalExtConstants.INVLIST;
+let PAGINATION_CONSTANT = GlobalExtConstants.PAGINATION_CONSTANT;
+
+/**
+ * This function will create a visualization from query outputs
+ * @param props
+ * @returns {*}
+ */
+var populateGraphObject = (nodes, links, data) => {
+ for(var i = 0; i < data.results.length; i++){
+ nodes[data.results[i].url] = data.results[i];
+ let nodeType = data.results[i]['node-type'];
+ nodes[data.results[i].url].weight = 1/((((data.results[i].url).split('\/')).length) - 3);
+ let splitUrl = (data.results[i].url).split(nodeType + '\/');
+ nodes[data.results[i].url].nodeTypeLabel = nodeType;
+ nodes[data.results[i].url].nodeKeyLabel = splitUrl.pop();
+ let tempIconString = ((splitUrl.pop()).split('\/'));
+ tempIconString.pop(); //pop last off, not needed
+ let iconString = tempIconString.pop();
+ let iconKey = (iconString.replace(/-/g, '')).toUpperCase();
+ if(INVLIST.INVENTORYLIST[iconKey] && INVLIST.INVENTORYLIST[iconKey].icon){
+ nodes[data.results[i].url].icon = INVLIST.INVENTORYLIST[iconKey].icon;
+ }else{
+ nodes[data.results[i].url].icon = 'icon-datanetwork-serverL';
+ }
+ console.log("icon string: " + nodes[data.results[i].url].icon);
+ nodes[data.results[i].url].id = data.results[i].url;
+ for(var j = 0; j < data.results[i]['related-to'].length; j++){
+ let linkKey = data.results[i].url + '|' + data.results[i]['related-to'][j].url;
+ let inverseLinkKey = data.results[i]['related-to'][j].url + '|' + data.results[i].url;
+ if(!links[linkKey] && !links[inverseLinkKey]){
+ links[linkKey] = data.results[i]['related-to'][j];
+ links[linkKey].source = data.results[i].url;
+ links[linkKey].target = data.results[i]['related-to'][j].url;
+ links[linkKey].weight = 1/((((data.results[i].url).split('\/')).length) - 3);
+ let subset = (data.results[i]['related-to'][j]['relationship-label']).split(/[\.]+/);
+ links[linkKey].type = subset[subset.length - 1];
+ }
+ }
+ }
+
+ for (var key in links) {
+ if (links.hasOwnProperty(key)) {
+ console.log(key + " -> " + links[key]);
+ if(!nodes[links[key].source] || !nodes[links[key].target]){
+ delete links[key];
+ }
+ }
+ }
+}
+var chart = (chartId, nodesObj, linksObj, rawData, classContext) => {
+ if(rawData.results.length <= PAGINATION_CONSTANT.RESULTS_PER_PAGE){
+ populateGraphObject( nodesObj, linksObj, rawData);
+ let links = Object.values(linksObj).map(d => Object.create(d));
+ let nodes = Object.values(nodesObj).map(d => Object.create(d));
+ let colors = d3.scaleOrdinal(d3.schemeCategory10);
+
+ let svg = d3.select('#'+chartId),
+ width = +svg.attr("width"),
+ height = +svg.attr("height"),
+ node,
+ link,
+ edgepaths,
+ edgelabels;
+
+ svg.html(null);
+ var g = svg.append("g")
+ .attr("class", "everything");
+ g.append("rect")
+ .attr("width", "100%")
+ .attr("height", "100%")
+ .attr("fill", "white");
+
+ var forceLink = d3
+ .forceLink().id(function (d) {
+ return d.id;
+ })
+ .distance(function (d) {
+ return 1000 * d.weight;
+ })
+ .strength(1.5);
+
+ var collisionForce = d3.forceCollide(100).strength(1.5).iterations(100);
+
+ var simulation = d3.forceSimulation()
+ .force("link", forceLink)
+ .force("charge", d3.forceManyBody().strength(function (d, i) {
+ var a = i == 0 ? -2000 : -1000;
+ return a;
+ }).distanceMin(200).distanceMax(1000))
+ .force("center", d3.forceCenter(width / 2, height / 2))
+ .force("collisionForce",collisionForce);
+
+ //Zoom functions
+ function zoom_actions(){
+ g.attr("transform", d3.event.transform)
+ }
+ //add zoom capabilities
+ var zoom_handler = d3.zoom()
+ .on("zoom", zoom_actions);
+
+ zoom_handler(svg);
+
+ update(links, nodes);
+
+ function zoomFit() {
+ var bounds = g.node().getBBox();
+ var parent = g.node().parentElement;
+ var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
+ fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
+ var width = bounds.width,
+ height = bounds.height;
+ var midX = bounds.x + width / 2,
+ midY = bounds.y + height / 2;
+ if (width == 0 || height == 0) return; // nothing to fit
+ var scale = 0.95 / Math.max(width / fullWidth, height / fullHeight);
+ var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
+
+ console.trace("zoomFit", translate, scale);
+
+ /*zoom_handler.translateTo(g, translate[0], translate[1])
+ .scaleTo(g, scale);*/
+ }
+
+ function update(links, nodes) {
+ link = g.selectAll(".link")
+ .data(links)
+ .enter()
+ .append("line")
+ .attrs({
+ 'stroke': '#999',
+ 'stroke-opacity': .6,
+ 'stroke-width': '1px',
+ 'id': function (d, i) {return 'line' + chartId + d.id}
+ });
+
+ link.append("title")
+ .text(function (d) {return d.type;});
+
+ edgepaths = g.selectAll(".edgepath")
+ .data(links)
+ .enter()
+ .append('path')
+ .attrs({
+ 'class': 'edgepath',
+ 'fill-opacity': 0,
+ 'stroke-opacity': 0,
+ 'id': function (d, i) {return 'edgepath' + chartId + d.id}
+ })
+ .style("pointer-events", "none");
+
+ /*edgelabels = g.selectAll(".edgelabel")
+ .data(links)
+ .enter()
+ .append('text')
+ .style("pointer-events", "none")
+ .attrs({
+ 'class': 'edgelabel',
+ 'id': function (d, i) {return 'edgelabel' + chartId + d.id},
+ 'font-size': 8,
+ 'fill': '#aaa'
+ });
+
+ edgelabels.append('textPath')
+ .attr('xlink:href', function (d, i) {return '#edgepath' + chartId + d.id})
+ .style("text-anchor", "middle")
+ .style("pointer-events", "none")
+ .attr("startOffset", "50%")
+ .text(function (d) {return d.type});*/
+
+ node = g.selectAll(".node")
+ .data(nodes)
+ .enter()
+ .append("g")
+ .attr("class", "node")
+ .attr("id", function (d) {return "node" + chartId + (((decodeURIComponent(d.url)).replace(new RegExp('\/', 'g'),'-')).replace(new RegExp(':', 'g'),'-')).replace(new RegExp('\\.', 'g'),'-')})
+ .call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended)
+ );
+
+ node.append("svg:foreignObject")
+ .attr("width", 70)
+ .attr("height", 70)
+ .attr("x", -45)
+ .attr("dy", function (d) {return -1 * (Math.max((Math.round(d.weight * 250)/10), 2));})
+ .append("xhtml:span")
+ .attr("class", function (d) {return d.icon;})
+ .style("padding", "10px")
+ .style("font-size", function (d) {return Math.max(Math.round(d.weight * 250), 20) + "px";})
+ .attr("id", function (d) {return "nodeIcon" + chartId + (((decodeURIComponent(d.url)).replace(new RegExp('\/', 'g'),'-')).replace(new RegExp(':', 'g'),'-')).replace(new RegExp('\\.', 'g'),'-')})
+ .style("color", '#387dff')
+ .style("display", "block");
+
+
+ node.append("title")
+ .text(function (d) {return decodeURIComponent(d.id);});
+
+ node.append("text")
+ .attr("dy", 0)
+ .attr("dx", -10)
+ .attr('font-size', 10)
+ .text(function (d) {return d.nodeTypeLabel;})
+ .style("text-anchor", "middle");
+
+ node.append("text")
+ .attr("dy", function (d) {return (Math.max(Math.round(d.weight * 250) + 15, 55));})
+ .attr("dx", -10)
+ .attr('font-size', 8)
+ .text(function (d) {return decodeURIComponent(d.nodeKeyLabel);})
+ .style("text-anchor", "middle");
+
+ node.on("dblclick",function(d){ classContext.openNodeModal("test", d.url, d['node-type']) });
+
+ simulation
+ .nodes(nodes)
+ .on("tick", ticked)
+ .on("end", zoomFit);
+
+ simulation.force("link")
+ .links(links);
+
+ svg.on("dblclick.zoom", null);
+ }
+
+ function ticked() {
+ link
+ .attr("x1", function (d) {return d.source.x;})
+ .attr("y1", function (d) {return d.source.y;})
+ .attr("x2", function (d) {return d.target.x;})
+ .attr("y2", function (d) {return d.target.y;});
+
+ node
+ .attr("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});
+
+ edgepaths.attr('d', function (d) {
+ return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
+ });
+
+ /*edgelabels.attr('transform', function (d) {
+ if (d.target.x < d.source.x) {
+ let bbox = this.getBBox();
+ let rx = bbox.x + bbox.width / 2;
+ let ry = bbox.y + bbox.height / 2;
+ return 'rotate(180 ' + rx + ' ' + ry + ')';
+ }
+ else {
+ return 'rotate(0)';
+ }
+ });*/
+ }
+
+ function dragstarted(d) {
+ simulation.stop();
+ }
+
+ function dragged(d) {
+ d.fx = d3.event.x;
+ d.fy = d3.event.y;
+ d.x = d3.event.x;
+ d.y = d3.event.y;
+ ticked();
+ }
+
+ function dragended(d) {
+ d.fixed = true;
+ ticked();
+ }
+ }else{
+ let svg = d3.select('#'+chartId),
+ width = +svg.attr("width"),
+ height = +svg.attr("height"),
+ node,
+ link,
+ edgepaths,
+ edgelabels;
+ let svgHtml = "<foreignObject x=\"0\" y=\"0\" width=\"100%\" height=\"100%\">" +
+ "<body xmlns=\"http://www.w3.org/1999/xhtml\">" +
+ "<div class=\"svgbody\">" +
+ "<h1>Graphical output is limited to " + PAGINATION_CONSTANT.RESULTS_PER_PAGE +
+ " nodes. Your query returned " + rawData.results.length +
+ " nodes, which the GUI does not support, please limit your query or if this data" +
+ " is needed access it through our externally supported APIs." +
+ "</h1>" +
+ "</div>"+
+ "</body>"+
+ "</foreignObject>";
+ svg.html(svgHtml);
+ }
+}
+const OutputVisualization = (props) => {
+ if (props.identifier && props.width && props.height && props.overflow) {
+ return (
+ <svg id={props.identifier} width={props.width} height={props.height} overflow={props.overflow}></svg>
+ );
+
+ }else{
+ return (<p>Graph Configuration Error</p>);
+ }
+};
+
+export default OutputVisualization;
+export const Visualization = {
+ chart: chart
+}
diff --git a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx
index 47cdc9a..3bc9508 100644
--- a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx
+++ b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBar.jsx
@@ -25,13 +25,16 @@ import AutoSuggest from 'react-autosuggest';
import Highlighter from 'react-highlight-words';
import debounce from 'lodash.debounce';
import {ButtonGroup} from 'react-bootstrap';
+import Modal from 'react-bootstrap/lib/Modal';
import {Link} from 'react-router-dom';
+import {genericRequest} from 'app/networking/NetworkCalls.js';
import {changeUrlAddress} from 'utils/Routes.js';
import {
ICON_CLASS_SEARCH,
ICON_CLASS_CLEAR,
+ ICON_CLASS_HELP,
SEARCH_DEBOUNCE_TIME,
NO_MATCHES_FOUND,
SEARCH_PLACEHOLDER_TEXT
@@ -45,6 +48,15 @@ export default class AutoCompleteSearchBar extends Component {
suggestionName: PropTypes.string
};
+ constructor(props) {
+ console.log(props);
+ super(props);
+ this.state = {
+ helpModalShow: false,
+ searchable: []
+ };
+ };
+
componentWillMount() {
this.debouncedLoadSuggestions =
debounce(this.props.onSuggestionsFetchRequested, SEARCH_DEBOUNCE_TIME);
@@ -107,9 +119,40 @@ export default class AutoCompleteSearchBar extends Component {
onChange: onInputChange
};
+ let closeHelpModal = () => {
+ this.setState({helpModalShow: false});
+ };
+ let showHelpModal = () => {
+ genericRequest('/schema/searchable', true, 'GET').then(res=>{
+ let searchDOM = res.sort(function(a, b) {
+ var compareA = (a['node-type']).toLowerCase();
+ var compareB = (b['node-type']).toLowerCase();
+ if(compareA < compareB){
+ return -1;
+ };
+ if(compareA > compareB){
+ return 1;
+ };
+ return 0;
+ }).map((prop) => {
+ return (
+ <div><p><strong>{prop['node-type']}:</strong></p><p>{prop['searchable-attributes']}</p></div>
+ );
+ });
+ this.setState({searchable: searchDOM, helpModalShow: true});
+ }, error => {
+ console.log(error);
+ this.setState({searchable: 'An error occurred, please try again later.', helpModalShow: true});
+ }).catch(error => {
+ console.log(error);
+ this.setState({searchable: 'An error occurred, please try again later.', helpModalShow: true});
+ });
+ };
+
let clearButtonClass = (value.length > 0)
? 'auto-complete-clear-button'
: 'auto-complete-clear-button hidden';
+
return (
<div className='auto-complete-search'>
<AutoSuggest
@@ -127,10 +170,12 @@ export default class AutoCompleteSearchBar extends Component {
renderSuggestionsContainer={this.renderSuggestionsContainer}/>
<ButtonGroup className='auto-complete-search-button-group'>
<Button type='submit' className={clearButtonClass}
- onClick={onClearSuggestionsTextFieldRequested}>
+ onClick={onClearSuggestionsTextFieldRequested}>
<i className={ICON_CLASS_CLEAR} aria-hidden='true'/>
</Button>
-
+ <Button type='submit' className='auto-complete-help-button' onClick={showHelpModal}>
+ <i className={ICON_CLASS_HELP} aria-hidden='true'/>
+ </Button>
<Button type='submit' className='auto-complete-search-button' onClick={() => {
this.newSearchSelected(this.getSelectedSuggestionObj(value, cachedSuggestions),
onInvalidSearch, dispatchAnalytics, value);
@@ -139,6 +184,21 @@ export default class AutoCompleteSearchBar extends Component {
<i className={ICON_CLASS_SEARCH} aria-hidden='true'/>
</Button>
</ButtonGroup>
+ <div className='static-modal'>
+ <Modal show={this.state.helpModalShow} onHide={closeHelpModal}>
+ <Modal.Header>
+ <Modal.Title>Searchable Fields</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <div className='modal-searchable'>
+ {this.state.searchable}
+ </div>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button onClick={closeHelpModal}>Close</Button>
+ </Modal.Footer>
+ </Modal>
+ </div>
</div>
);
}
diff --git a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js
index 975584a..a836275 100644
--- a/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js
+++ b/src/generic-components/autoCompleteSearchBar/AutoCompleteSearchBarConstants.js
@@ -35,3 +35,4 @@ export const SEARCH_DEBOUNCE_TIME = 300;
export const ICON_CLASS_SEARCH = 'fa fa-search fa-lg';
export const ICON_CLASS_CLEAR = 'fa fa-times fa-lg';
+export const ICON_CLASS_HELP = 'fa fa-question-circle fa-lg';
diff --git a/src/generic-components/filter/Filter.jsx b/src/generic-components/filter/Filter.jsx
new file mode 100644
index 0000000..2270665
--- /dev/null
+++ b/src/generic-components/filter/Filter.jsx
@@ -0,0 +1,270 @@
+/*
+ * ============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 Col from 'react-bootstrap/lib/Col';
+import Row from 'react-bootstrap/lib/Row';
+import Grid from 'react-bootstrap/lib/Grid';
+import AddFilters from './components/AddFilters.jsx';
+import ClearFilter from './components/ClearFilter.jsx';
+import RunFilterQuery from './components/RunFilterQuery.jsx';
+import SelectFilter from './components/SelectFilter.jsx';
+import FilterTypes from './components/FilterTypes.jsx';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+let APERTURE_SERVICE = JSON.parse(sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'APERTURE_SERVICE'));
+
+class Filter extends Component {
+ constructor(props){
+ super(props);
+ APERTURE_SERVICE=JSON.parse(sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'APERTURE_SERVICE'));
+ };
+ state = {
+ filterList: this.props.filterList,
+ filterSelected: this.props.nodeType,
+ filterDisplay: 'Select Filter' ,
+ filterTypeDisplay: 'Filter Type',
+ errorMsg: '',
+ showFilter:(this.props.filterMessage && this.props.filterMessage.length > 0) ? true : false,
+ filterMessage:this.props.filterMessage,
+ filterValue:'',
+ filterSelectedList:this.props.filterSelectedList,
+ isRunEnable:this.props.isRunEnable,
+ enableRealTime:JSON.parse(sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'ENABLE_ANALYSIS'))
+ };
+ componentDidMount(){
+ console.log('Filter component mount');
+ };
+ componentWillReceiveProps(){
+ console.log('filter component componentWillReceiveProps');
+ this.setState({
+ filterDisplay:this.props.filterDisplay,
+ filterTypeDisplay:this.props.filterTypeDisplay,
+ errorMsg:(this.props.errorMsg) ? this.props.errorMsg : '',
+ filterSelected:this.props.nodeType,
+ showFilter:(this.props.filterMessage && this.props.filterMessage.length > 0) ? true : false,
+ filterMessage: this.props.filterMessage,
+ filterValue:'',
+ filterSelectedList:this.props.filterSelectedList,
+ enableRealTime:JSON.parse(sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'ENABLE_ANALYSIS'))
+ });
+ }
+ renderFilterMessage = (props) => {
+ console.log('Filter render Filter Message>>>>>',props.showFilter);
+ if(props.showFilter){
+ const filters = props.filterSelectedList.map( (filterMsg,index) =>{
+ let filterType=(this.state.enableRealTime && filterMsg.type ==='=')? 'CONTAINS' : filterMsg.type;
+ return (
+ <div className = 'badgeFilter' key={index}>
+ <span><b>{filterMsg.id}</b>&nbsp;<i>{filterType}</i>&nbsp;{filterMsg.value}</span>
+ <button type='button' className='close' aria-label='Close' onClick={() => this.onRemoveFilters(filterMsg.id.trim(),filterMsg.value.trim(),filterMsg.type)}>
+ <span aria-hidden='true'>&times;</span>
+ </button>
+ </div>
+ );
+ });
+ console.log('render Filter Message>>>>>before return ');
+ return(
+ <Row className='show-grid topBottomMargin'>
+ <Col md={12} className='removeLeftPadding'>
+ { filters }
+ </Col>
+ </Row>
+ );
+ console.log('Filter render Filter Message>>>>>After return ');
+ }
+ };
+ renderError = (props) => {
+ if(props.errorMsg) {
+ return(
+ <Row className='show-grid topBottomMargin'>
+ <span className='label badge-pill label-danger topBottomMargin'><strong>Error </strong>: {this.state.errorMsg}</span>
+ </Row>
+ );
+ }
+ };
+ filterClearAllButtonSelectedHandler = () => {
+ console.log('clear all called');
+ if(this.state.isRunEnable || this.state.filterMessage.length === 0){
+ this.setState(
+ {
+ filterDisplay: 'Select Filter',
+ filterTypeDisplay: 'Filter Type',
+ errorMsg: '',
+ filterMessage: [],
+ filterValue:'',
+ filterSelectedList:[]
+ }
+ );
+ }else{
+ var tempState = this.state;
+ tempState.filterMessage = [];
+ tempState.filterSelectedList = [];
+ tempState.filterValue = '';
+ tempState.errorMsg = '';
+ tempState.filterDisplay = 'Select Filter';
+ tempState.filterTypeDisplay = 'Filter Type';
+ this.setState(tempState,function(){this.props.loadInventory(tempState);});
+ }
+
+ };
+ filterAddButtonSelectedHandler = () => {
+ console.log('add Filter called');
+ var found = this.isContaining(this.state.filterDisplay, this.state.filterSelectedList);
+ console.log('filterAddButtonSelectedHandler>>>>>found',found);
+ this.errorMsg = null;
+ let filterDisplayState = true;
+ if(this.state.enableRealTime){
+ if(this.state.filterTypeDisplay !== 'Filter Type'){
+ filterDisplayState = true;
+ }else{
+ filterDisplayState = false;
+ }
+ }
+ if (this.state.filterDisplay !== 'Select Filter' && filterDisplayState && this.state.filterValue && !found){
+ console.log('filterAddButtonSelectedHandler>>>>>inside',this.state.filterValue);
+ var tempState = this.state;
+ if(this.state.enableRealTime){
+ tempState.filterMessage.push(this.state.filterDisplay + this.state.filterTypeDisplay +this.state.filterValue);
+ tempState.filterSelectedList.push({'id' : this.state.filterDisplay, 'value' : this.state.filterValue,'type': this.state.filterTypeDisplay});
+ }else{
+ tempState.filterMessage.push(this.state.filterDisplay + '=' +this.state.filterValue);
+ tempState.filterSelectedList.push({'id' : this.state.filterDisplay, 'value' : this.state.filterValue,'type': '='});
+ }
+ tempState.filterDisplay = 'Select Filter';
+ tempState.filterTypeDisplay = 'Filter Type';
+ tempState.filterValue = '';
+ tempState.showFilter = true;
+ tempState.errorMsg = '';
+ console.log('filterAddButtonSelectedHandler>>>>>tempState',tempState);
+ if(this.state.isRunEnable) {
+ this.setState(tempState);
+ }else{
+ this.setState(tempState,function(){this.props.loadInventory(tempState);});
+ }
+ }else{
+ console.log('filterAddButtonSelectedHandler>>>>>Else',this.state.filterDisplay);
+ console.log('filterAddButtonSelectedHandlerfilterTypeDisplay>>>>>Else',this.state.filterTypeDisplay);
+ console.log('this.state.filterValue>>>>>>>>>>>>>>',this.state.filterValue);
+ if(found){
+ this.setState({errorMsg: 'Please remove the current filter for this field before trying to add another.'});
+ }else if ( this.state.filterDisplay === 'Select Filter'){
+ this.setState({errorMsg: 'Please select a filter.'});
+ }else if (this.state.enableRealTime && this.state.filterTypeDisplay === 'Filter Type'){
+ this.setState({errorMsg: 'Please select a filter type.'});
+ }else{
+ this.setState({errorMsg: 'Please validate your filter, there seems to be an issue.'});
+ }
+ }
+ };
+ isContaining(nameKey, listArray){
+ var found = false;
+ if(listArray) {
+ listArray.map((lists) => {
+ if(lists.id === nameKey){
+ console.log('foundName key in list',lists.id);
+ found = true;
+ }
+ });
+ }
+ return found;
+ };
+ onTargetMenuSelect = (listName) => {
+ console.log('onTargetMenuSelect',listName);
+ this.setState({filterDisplay:listName,errorMsg:''});
+ };
+ onTargetMenuOfFilterTypes = (listName) => {
+ console.log('onTargetMenuOfFilterTypes',listName);
+ this.setState({filterTypeDisplay:listName,errorMsg:''});
+ }
+ onInputDataChange = (event) =>{
+ console.log('inputtext',event.target.value);
+ this.setState({filterValue:event.target.value});
+ };
+ onRemoveFilters = (filter,filterText,filterType) => {
+ console.log('onRemoveFilters',this.state.filterSelectedList);
+ var found = this.isContaining(filter, this.state.filterSelectedList);
+ console.log('onRemoveFilters.....found',found);
+ if(found){
+ const filterList = this.state.filterSelectedList.filter(function(el) {
+ console.log('el.id',el.id);
+ return el.id !== filter;
+ });
+ console.log('onRemoveFilters.....filterList',filterList);
+ let message = filter + filterType + filterText;
+ const filterMsgList = this.state.filterMessage.filter((el) =>{
+ return el !== message;
+ });
+ console.log('onRemoveFilters.....filterMsgList',filterMsgList);
+ if(this.state.isRunEnable) {
+ this.setState({filterSelectedList:filterList,filterValue:'',filterMessage:filterMsgList,errorMsg:''});
+ }else{
+ var tempState = this.state;
+ tempState.filterMessage = filterMsgList;
+ tempState.filterSelectedList = filterList;
+ tempState.filterValue = '';
+ tempState.errorMsg = '';
+ this.setState(tempState,function(){this.props.loadInventory(tempState);});
+ }
+ }
+ };
+ render(){
+ let filterTags ='';
+ if(APERTURE_SERVICE && this.state.enableRealTime){
+ console.log('before passing Filter>*',this.state);
+ filterTags= <Col md={(this.state.isRunEnable) ? 2 : 2} className='removeLeftPadding'>
+ <FilterTypes param={this.state}
+ filterList={this.props.filterList}
+ onMenuSelect={this.onTargetMenuOfFilterTypes} />
+ </Col>
+ }
+ return(
+ <div id='filterPane' className={this.props.isFilterEnable ? 'show' : 'hidden'}>
+ <Grid className='custom-container'>
+ <Row className='show-grid topBottomMargin'>
+ <Col md={(this.state.isRunEnable) ? 3 : 2} className='removeLeftPadding'>
+ <SelectFilter param={this.state}
+ filterList={this.props.filterList}
+ onMenuSelect={this.onTargetMenuSelect} />
+ </Col>
+ {filterTags}
+ <Col md={(this.state.isRunEnable) ? 7 : 8}>
+ <input type='text' size='36'
+ onBlur={(event) => this.onInputDataChange(event)}
+ placeholder='Please Enter Filter text'
+ value={this.state.filterValue}
+ onChange={(event) => this.onInputDataChange(event)} />
+ <AddFilters param={this.state}
+ addHandler={this.filterAddButtonSelectedHandler} />
+ <ClearFilter param={this.state} clearAllHandler={this.filterClearAllButtonSelectedHandler} />
+ <RunFilterQuery param={this.state} />
+ </Col>
+ </Row>
+ {
+ this.renderError(this.state)
+ }
+ {
+ this.renderFilterMessage(this.state)
+ }
+ </Grid>
+ </div>
+ );
+ }
+}
+export default Filter;
diff --git a/src/generic-components/filter/components/AddFilters.jsx b/src/generic-components/filter/components/AddFilters.jsx
new file mode 100644
index 0000000..4b0aa7b
--- /dev/null
+++ b/src/generic-components/filter/components/AddFilters.jsx
@@ -0,0 +1,27 @@
+/*
+ * ============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 from 'react';
+
+const AddFilters = (props) => (
+ <button type='button' className='btn btn-primary' onClick={props.addHandler}>Add Filter</button>
+);
+
+export default AddFilters;
diff --git a/src/generic-components/filter/components/ClearFilter.jsx b/src/generic-components/filter/components/ClearFilter.jsx
new file mode 100644
index 0000000..e231ab8
--- /dev/null
+++ b/src/generic-components/filter/components/ClearFilter.jsx
@@ -0,0 +1,27 @@
+/*
+ * ============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 from 'react';
+
+const ClearFilter = (props) => (
+ <button type='button' className='btn btn-secondary' onClick={props.clearAllHandler}>Clear Filters</button>
+);
+
+export default ClearFilter;
diff --git a/src/generic-components/filter/components/FilterTypes.jsx b/src/generic-components/filter/components/FilterTypes.jsx
new file mode 100644
index 0000000..c25749d
--- /dev/null
+++ b/src/generic-components/filter/components/FilterTypes.jsx
@@ -0,0 +1,102 @@
+/*
+ * ============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 DropdownButton from 'react-bootstrap/lib/DropdownButton';
+import Dropdown from 'react-bootstrap/lib/Dropdown';
+import MenuItem from 'react-bootstrap/lib/MenuItem';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+var filterTypeList = GlobalExtConstants.FILTER_TYPES;
+
+class FilterTypes extends Component {
+ constructor(props) {
+ console.log('FilterTypes props>>>>',props);
+ super(props);
+ this.props = props;
+ this.state = {dropdownIsOpen : false, isInitialize: true}
+ }
+ componentWillReceiveProps (nextProps) {
+ console.log('next props componentWillReceiveProps>>>>>>>',nextProps);
+ console.log('tihs props componentWillReceiveProps>>>>>>>',this.props);
+ if(this.state.isInitialize || this.props !== nextProps){
+ this.props=nextProps;
+ this.setState({isInitialize:false}, ()=>{this.updateDropDownState();});
+ }
+ console.log('this.state under Update>>>>>',this.state);
+ }
+ handleDropdownValues = (props) => {
+ const listItems = Object.keys(filterTypeList).map((filter,index) => {
+ return(
+ <MenuItem
+ eventKey={index}
+ key={filter}>
+ {filterTypeList[index]}
+ </MenuItem>
+ );
+ });
+ return (
+ listItems
+ );
+ };
+ toggleDropdown = () => {
+ console.log('toggleDropdown>>>>>',this.state.dropdownIsOpen);
+ this.setState({ dropdownIsOpen: !this.state.dropdownIsOpen },()=>{this.updateDropDownState()});
+ };
+ updateDropDownState = () =>{
+ console.log('updateDropDownState',this.state.dropdownIsOpen);
+ //document.dispatchEvent(new MouseEvent('click'));
+ let id=(this.props.id)? 'dropdown-root-'+this.props.id :'dropdown-root-2'
+ if(this.state.dropdownIsOpen){
+ document.getElementById(id).getElementsByClassName('dropdown-menu')[0].style.display='block';
+ }else{
+ document.getElementById(id).getElementsByClassName('dropdown-menu')[0].style.display='none';
+ }
+ }
+ handleSelect(eventKey, event) {
+ Object.keys(filterTypeList).map((filter,index) => {
+ if(eventKey === index){
+ this.props.onMenuSelect(filterTypeList[index],this.props.id)
+ }
+ });
+ }
+ render(){
+ if(this.state.isInitialize){
+ this.setState({isInitialize:false},()=>{this.updateDropDownState();});
+ }
+ return(
+ <div id={(this.props.id)? 'dropdown-root-'+this.props.id :'dropdown-root-2'}>
+ <DropdownButton
+ bsStyle='primary'
+ title= {(this.props.selectedFilter)? this.props.selectedFilter: this.props.param.filterTypeDisplay}
+ key= '2'
+ id={(this.props.id)? 'dropdown-basic-'+this.props.id :'dropdown-basic-2'}
+ className='dropdownButton'
+ onToggle={this.toggleDropdown}
+ disabled={(this.props.state)?this.props.state:false}
+ onSelect={this.handleSelect.bind(this)} >
+ {
+ this.handleDropdownValues(this.props)
+ }
+ </DropdownButton>
+ </div>
+ )
+ }
+}
+export default FilterTypes;
diff --git a/src/generic-components/filter/components/RunFilterQuery.jsx b/src/generic-components/filter/components/RunFilterQuery.jsx
new file mode 100644
index 0000000..5b81769
--- /dev/null
+++ b/src/generic-components/filter/components/RunFilterQuery.jsx
@@ -0,0 +1,56 @@
+/*
+ * ============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 from 'react';
+import {Link} from 'react-router-dom';
+//import {BrowserRouter} from 'react-router-dom';
+import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
+let URI_DELIMITCHAR = GlobalExtConstants.URI_DELIMITCHAR;
+
+var prepareURI = (props) => {
+ console.log('prepare URI');
+ let URI = '/model/' + props.filterSelected;
+ let filterList = props.filterSelectedList;
+ if(filterList){
+ for (var key in filterList){
+ if(filterList.hasOwnProperty(key)){
+ URI += ';' + filterList[key].id + URI_DELIMITCHAR + filterList[key].type + URI_DELIMITCHAR + filterList[key].value;
+ }
+ }
+ }
+ return (
+ URI
+ );
+};
+const RunFilterQuery = (props) => {
+ if(props.param.isRunEnable){
+ return(
+ <Link to={prepareURI(props.param)}>
+ <button type='button' className='btn btn-warning'>Run </button>
+ </Link>
+ );
+ }else{
+ return(
+ <span></span>
+ );
+ }
+};
+
+export default RunFilterQuery;
diff --git a/src/generic-components/filter/components/SelectFilter.jsx b/src/generic-components/filter/components/SelectFilter.jsx
new file mode 100644
index 0000000..94f1807
--- /dev/null
+++ b/src/generic-components/filter/components/SelectFilter.jsx
@@ -0,0 +1,100 @@
+/*
+ * ============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 DropdownButton from 'react-bootstrap/lib/DropdownButton';
+import MenuItem from 'react-bootstrap/lib/MenuItem';
+
+class SelectFilter extends Component {
+ constructor(props) {
+ console.log('SelectFilter props',props);
+ super(props);
+ this.props = props;
+ this.state = {dropdownIsOpen : false, isInitialize: true}
+ }
+ componentWillReceiveProps (nextProps) {
+ console.log('next props componentWillReceiveProps>>>>>>>',nextProps);
+ console.log('tihs props componentWillReceiveProps>>>>>>>',this.props);
+ if(this.state.isInitialize || this.props.id !== nextProps.id){
+ this.props=nextProps;
+ this.setState({isInitialize:false},()=>{this.updateDropDownState();});
+ }
+ console.log('this.state under Update>>>>>',this.state);
+ }
+
+ handleDropdownValues = (props) => {
+ const listItems = Object.keys(props.filterList).map((filter,index) => {
+ let filterValue=(props.filterList[index].value)?props.filterList[index].value:props.filterList[index];
+ let description=(props.filterList[index].description)?props.filterList[index].description:'';
+ return(
+ <MenuItem eventKey={index} key={index} title={description}>{filterValue}</MenuItem>
+ );
+ });
+ console.log('listItems',listItems);
+ return (
+ listItems
+ );
+ };
+ toggleDropdown = () => {
+ console.log('toggleDropdown>>>>>',this.state.dropdownIsOpen);
+ this.setState({ dropdownIsOpen: !this.state.dropdownIsOpen },()=>{this.updateDropDownState();});
+ };
+ updateDropDownState = () =>{
+ console.log('updateDropDownState',this.state.dropdownIsOpen);
+ //document.dispatchEvent(new MouseEvent('click'));dropdownIsOpen
+ let id=(this.props.id)? 'dropdown-root-'+this.props.id :'dropdown-root-1'
+ if(this.state.dropdownIsOpen){
+ document.getElementById(id).getElementsByClassName('dropdown-menu')[0].style.display='block';
+ }else{
+ document.getElementById(id).getElementsByClassName('dropdown-menu')[0].style.display='none';
+ }
+ }
+ handleSelect(eventKey, event) {
+ Object.keys(this.props.filterList).map((filter,index) => {
+ if(eventKey === index){
+ let filterValue=(this.props.filterList[index].value)?this.props.filterList[index].value:this.props.filterList[index];
+ this.props.onMenuSelect(filterValue,this.props.id)
+ }
+ });
+ }
+ render(){
+ if(this.state.isInitialize){
+ this.setState({isInitialize:false},()=>{this.updateDropDownState();});
+ }
+ return(
+ <div id={(this.props.id)? 'dropdown-root-'+this.props.id :'dropdown-root-1'}>
+ <DropdownButton
+ bsStyle='primary'
+ title= {(this.props.selectedFilter)? this.props.selectedFilter: this.props.param.filterDisplay}
+ key= '1'
+ id={(this.props.id)? 'dropdown-basic-'+this.props.id :'dropdown-basic-1'}
+ className='dropdownButton'
+ onToggle={this.toggleDropdown}
+ onSelect={this.handleSelect.bind(this)}
+ >
+ {
+ this.handleDropdownValues(this.props)
+ }
+ </DropdownButton>
+ </div>
+ );
+ }
+}
+export default SelectFilter;