2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import React, { Component } from 'react';
23 import Select from 'react-select';
24 import Button from 'react-bootstrap/lib/Button';
25 import Row from 'react-bootstrap/lib/Row';
26 import Col from 'react-bootstrap/lib/Col';
27 import Grid from 'react-bootstrap/lib/Grid';
28 import PanelGroup from 'react-bootstrap/lib/PanelGroup';
29 import Panel from 'react-bootstrap/lib/Panel';
30 import Label from 'react-bootstrap/lib/Label';
31 import Collapse from 'react-bootstrap/lib/Collapse';
32 import moment from "moment";
33 import DatePicker from 'react-datepicker';
34 import Modal from 'react-bootstrap/lib/Modal';
35 import {ExportExcel} from 'utils/ExportExcel.js';
36 import commonApi from 'utils/CommonAPIService.js';
37 import {GlobalExtConstants} from 'utils/GlobalExtConstants.js';
38 import Spinner from 'utils/SpinnerContainer.jsx';
39 import ModelGallery from 'app/model/modelSearch/components/ModelGallery.jsx';
40 import ModelCard from 'app/model/modelSearch/components/ModelCard.jsx';
41 import OutputToggle from 'generic-components/OutputToggle.jsx';
42 import Pagination from 'react-js-pagination';
43 import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
44 import Tooltip from 'react-bootstrap/lib/Tooltip';
45 import {Visualization} from 'generic-components/OutputVisualization.jsx';
46 import DownloadRangeModel from 'generic-components/DownloadRangeModel.jsx';
50 let PAGINATION_CONSTANT = GlobalExtConstants.PAGINATION_CONSTANT;
51 let INVLIST = GlobalExtConstants.INVLIST;
52 let CUSTOMQUERYLIST = GlobalExtConstants.CUSTOMQUERYLIST;
53 let generateExcels = ExportExcel.generateExcels;
54 let DOWNLOAD_ALL = GlobalExtConstants.DOWNLOAD_ALL;
55 let DOWNLOAD_TOOLTIP = GlobalExtConstants.DOWNLOAD_TOOLTIP;
58 let dropdownList = null;
61 const inputClasses = ['form-control'];
63 class CustomQuery extends Component {
66 downloadTooltip = DOWNLOAD_TOOLTIP;
67 downloadAllTooltip = 'Downloads First ' + DOWNLOAD_ALL + ' Results';
68 downloadRangeTooltip= 'Download Results By Custom Range Selection';
69 historyStackString = '';
71 queryPlaceHolder: 'Please Select a Query',
72 placeholder: 'Please Select a Query',
73 reqPropPlaceholder: 'Please Enter Required Query or Property',
74 optionalPropPlaceholder: 'Please Enter Optional Query or Property',
75 displayReqProps: 'hidden',
84 displayDescription: 'hidden',
85 customQueryOptions: null,
88 displayNodes: 'hidden',
94 showPagination: false,
99 displayOptionalProps: 'hidden',
100 showHistoryModal:false,
102 currentPayload: null,
103 viewName: localStorage.getItem(GlobalExtConstants.ENVIRONMENT + '_' + sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'userId') + '_viewPreference') || 'CardLayout',
105 visualAddition: false,
107 showNodeModal: false,
113 showModelOptions: false,
114 enableCalendar: true,
115 resetColumnFilters: true,
116 isPageNumberChange: false,
119 showDownloadResultsModal: false,
120 errorDownloadResults:false,
121 downloadErrorMsg: '',
122 enableModelBusyFeedback:false,
123 downloadCount:DOWNLOAD_ALL,
124 defaultViewName: localStorage.getItem(GlobalExtConstants.ENVIRONMENT + '_' + sessionStorage.getItem(GlobalExtConstants.ENVIRONMENT + 'userId') + '_viewPreference') || 'CardLayout'
127 componentWillMount () {
128 console.log('componentWillMount');
129 sessionStorage.setItem(GlobalExtConstants.ENVIRONMENT + 'ENABLE_ANALYSIS', false);
130 if(!this.props.location.historyStackString){
131 this.props.location.historyStackString = this.props.location.pathname + ',,Origin||';
133 this.historyStackString = this.props.location.historyStackString;
135 let queryList = Object.values(CUSTOMQUERYLIST.CUSTOMQUERYLIST);
136 dropdownList = queryList.sort(function (filter1, filter2) {
137 if (filter1.value < filter2.value) {
139 } else if (filter1.value > filter2.value) {
146 onInputChangeHandler (){
147 console.log('onInputChangeHandler of select-Clear');
149 placeholder: 'Please Select A Query',
150 queryPlaceHolder: 'Please Select A Query', query: '',
151 reqPropPlaceholder: 'Please Enter Required Query or Property',
152 optionalPropPlaceholder: 'Please Enter Optional Query or Property',
157 displayDescription: 'hidden',
159 displayNodes: 'hidden',
162 displayOptionalProps: 'hidden',
164 showPagination: false,
173 updateSelectedHandler = (selectedOption) => {
175 const value = selectedOption === null ? 'Please Select A Query' : selectedOption.value
177 console.log('updateSelectedHandler.reqPropPlaceholder: ' + selectedOption.reqPropPlaceholder);
178 console.log('updateSelectedHandler.value: ' + selectedOption.value);
179 this.setState({ placeholder: selectedOption.placeholder });
180 this.setState({ displayReqProps: selectedOption.reqPropPlaceholder ? 'show' : 'hidden' });
181 this.setState({ displayOptionalProps: selectedOption.optionalPropPlaceholder ? 'show' : 'hidden'});
182 this.setState({ reqPropPlaceholder: selectedOption.reqPropPlaceholder });
183 this.setState({ optionalPropPlaceholder: selectedOption.optionalPropPlaceholder});
184 this.setState({ disableInputs: false });
185 this.setState({ query: value });
186 this.setState({ description: selectedOption.description.summary });
187 this.setState({ additionalInfo: selectedOption.description.additionalInfo });
188 this.setState({ displayDescription: 'show' });
189 this.setState({ startNode: ''});
190 this.setState({ reqProps: ''});
191 this.setState({ optionalProps: ''});
192 this.setState({ queryPlaceHolder: value});
194 /*this.setState({ queryPlaceHolder: value, query: '',
195 reqPropPlaceholder: this.state.reqPropPlaceholder,optionalPropPlaceholder: this.state.optionalPropPlaceholder,
196 startNode: '',reqProps: '', optionalProps: ''});*/
197 this.onInputChangeHandler();
202 isValid = this.state.startNode.trim().length > 1 && isValid;
203 if (this.state.reqPropPlaceholder) {
204 console.log('Checking if reqProps is on state...');
205 isValid = this.state.reqProps.length > 1 && isValid;
210 inputChangeHandler = (event) => {
211 const target = event.target;
212 const value = target.value;
213 const name = target.name;
214 console.log('inputChangeHandler.value: ' + value);
215 console.log('inputChangeHandler.name: ' + name);
216 let formIsValid = null;
220 console.log('startNode:' + this.state.startNode);
221 console.log('reqProps:' + this.state.reqProps);
222 formIsValid = this.checkValidity();
223 console.log('formIsValid:' + formIsValid);
224 this.setState({ formIsValid: formIsValid });
228 onAdditem = (event) => {
229 //window.alert('onAddItem clicked');
230 event.preventDefault();
231 this.nodeResults = '';
232 this.typeOfCall = true;
233 this.formQueryString();
235 formPayload = () => {
236 var startNode = this.state.startNode;
238 console.log('startNode.trim().length: ' + startNode.trim().length);
239 var queryName = this.state.query;
240 var reqProps = this.state.reqProps;
241 var optionalProps = this.state.optionalProps;
242 console.log('start Node: ' + startNode);
243 console.log('query name: ' + queryName);
244 console.log('req props: ' + reqProps);
245 console.log('Optional props: ' + optionalProps);
248 if(queryName === 'node-fromURI'){
252 } else if ( reqProps === '' && optionalProps === '' ){
255 query: 'query/' + queryName
257 } else if(reqProps !== ''){
258 reqProps = '?' + reqProps;
261 query: 'query/' + queryName + reqProps
264 if(optionalProps !== ''){
266 optionalProps = '?' + optionalProps;
268 optionalProps = reqProps + optionalProps;
272 query: 'query/' + queryName + optionalProps
277 formQueryString = () =>{
278 let payload = this.formPayload();
280 console.log('payload>>>>>' + payload.toString());
282 'NODESERVER': INVLIST.NODESERVER,
283 'PROXY': INVLIST.PROXY,
284 'PREFIX': INVLIST.PREFIX,
285 'VERSION': INVLIST.VERSION,
286 'USESTUBS': INVLIST.useStubs
291 queryStr = 'query?format=simple&resultIndex='
292 + this.state.activePage + '&resultSize=' + PAGINATION_CONSTANT.RESULTS_PER_PAGE;
293 this.setState({isLoading: true,nodes: [], currentPayload:payload});
295 let pagerange=this.state.pageRange.toString();
296 pagerange=pagerange.split('-');
297 if(pagerange.length > 1){
298 queryStr = 'query?format=simple&resultIndex=' + parseInt(pagerange[0]) + '&resultSize=' + PAGINATION_CONSTANT.RESULTS_PER_PAGE + '&resultRangeEnd=' + parseInt(pagerange[1]);
300 queryStr = 'query?format=simple&resultIndex=1&resultSize=' + parseInt(pagerange);
302 this.setState({enableModelBusyFeedback: true, currentPayload:payload});
304 this.getNodes(settings, queryStr, 'PUT', payload);
308 getNodes(settings, path, httpMethodType, payload) {
309 commonApi(settings, path, httpMethodType, payload, 'CQDefault')
311 console.log(Object.keys(res.data));
312 this.processData(res);
313 if(this.state.nodes.length > 0 && this.state.visualAddition){
314 Visualization.chart('currentState' , [], [], this.state.res.data, this);
316 console.log('res:' + res);
318 console.log(JSON.stringify(error));
320 this.triggerError(error);
322 let errMsg = this.renderErrorMsg(error);
323 this.setState({ isLoading: false,errorDownloadResults:true,downloadErrorMsg:errMsg,enableModelBusyFeedback:false});
327 console.log(JSON.stringify(error));
329 this.triggerError(error);
331 let errMsg = this.renderErrorMsg(error);
332 this.setState({ isLoading: false,errorDownloadResults:true,downloadErrorMsg:errMsg,enableModelBusyFeedback:false});
339 triggerError = (error) =>{
340 // this.processData('');
341 this.setState({isLoading: false,
343 showPagination: false,
345 isInitialLoad: false,
349 this.downloadAllTooltip = 'Downloads First ' + DOWNLOAD_ALL + ' Results';
350 let errMsg = this.renderErrorMsg(error);
351 this.setState({errorMessage:errMsg});
353 renderErrorMsg = (error) =>{
355 if (error.response) {
356 // The request was made and the server responded with a status code
357 // that falls out of the range of 2xx
358 console.log(error.response.data);
359 console.log(error.response.status);
360 console.log(error.response.headers);
361 if(error.response.status){
362 errMsg += " Code: " + error.response.status;
364 if(error.response.data){
365 errMsg += " - " + JSON.stringify(error.response.data);
367 } else if (error.request) {
368 // The request was made but no response was received
369 // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
370 // http.ClientRequest in node.js
371 console.log(error.request);
372 errMsg += " - Request was made but no response received";
374 // Something happened in setting up the request that triggered an Error
375 console.log('Error', error.message);
376 errMsg += " - Unknown error occurred " + error.message;
378 console.log(error.config);
383 //data = CustomQueryResponse;
384 console.log( 'in Custom Query component file DATA: ' + JSON.stringify(resp.data));
386 if(resp.data && resp.data.results) {
389 nodes: resp.data.results},
391 console.log('how many nodes? ', this.state.nodes.length);
392 this.setState({ multipleNodes: this.state.nodes.length > 1 ? 'col-lg-3 col-xl-3' : '' });
395 let totalResults = 0;
396 let downloadCount = DOWNLOAD_ALL;
398 totalResults = parseInt(resp.headers['total-results']);
399 if(totalResults > DOWNLOAD_ALL){
400 this.downloadAllTooltip = DOWNLOAD_ALL + ' results out of '+ totalResults +' Results will be downloaded, please filter results further to obtain full report';
402 this.downloadAllTooltip = (totalResults === 1) ?'Downloads ' + totalResults + ' Results' : 'Downloads all ' + totalResults + ' Results' ;
403 downloadCount= totalResults;
405 this.setState({isLoading: false,
406 totalResults: totalResults,
407 totalPages: parseInt(resp.headers['total-pages']),
408 showResults: resp.headers['total-results'] > 0 ? true : false,
409 showPagination: resp.headers['total-results'] > 0 ? true : false,
410 isInitialLoad: false,
411 noResults: resp.headers['total-results'] && resp.headers['total-results'] > 0 ? false : true,
412 errorResults: !resp.headers['total-results'],
413 downloadCount: downloadCount
417 this.setState({ displayNodes: 'show', viewName: this.state.defaultViewName });
419 if(resp.data && resp.data.results) {
420 this.nodeResults = resp.data.results;
421 let totalResults = 0;
424 totalResults = parseInt(resp.headers['total-results']);
425 totalPages = parseInt(resp.headers['total-pages']);
427 this.setState({isLoading: false,totalPages:totalPages,errorDownloadResults:false,downloadErrorMsg:''},() => {this.getAllExcels()});
429 this.nodeResults = '';
430 this.setState({isLoading: false,errorDownloadResults:true,downloadErrorMsg:error+'',enableModelBusyFeedback:false});
435 nodeOnClick(event, uri, id, nodeType) {
436 event.preventDefault();
437 let delimiter = '\/';
439 let tokens = uri.split(delimiter).slice(start);
440 let result = tokens.join(delimiter);
441 sessionStorage.setItem(GlobalExtConstants.ENVIRONMENT + 'URI', result);
442 console.log(['/model/' + nodeType + '/' + id + '/' + '1']);
444 openDownloadRange = () =>{
446 showDownloadResultsModal: true,
447 errorDownloadResults: false,
448 downloadErrorMsg:''});
450 closeDownloadResults = () =>{
452 showDownloadResultsModal: false,
453 enableModelBusyFeedback: false
456 getAllExcels = (pageRange,rangeState) =>{
458 console.log('getAllExcels>>>>>>>>>>>*',pageRange);
460 this.typeOfCall=false;
461 let rangeModelState=(rangeState)? rangeState: false;
463 { pageRange: pageRange,enableModelBusyFeedback:true,showDownloadResultsModal:rangeModelState},
464 function () { this.formQueryString(); }.bind(this)
468 {errorDownloadResults: false, showDownloadResultsModal: false, downloadErrorMsg:'', isLoading: false, enableModelBusyFeedback:false},
469 function () { generateExcels(this.nodeResults);this.nodeResults='';this.typeOfCall = true;}.bind(this)
474 this.typeOfCall = true;
475 generateExcels(this.state.nodes);
478 handlePageChange = (pageNumber) => {
479 console.log('[CustomQuery.jsx] HandelPageChange active page is', pageNumber);
480 this.typeOfCall = true;
482 { activePage: pageNumber, isLoading: true, nodes: [], resetColumnFilters: false, isPageNumberChange: true },
483 function () { this.formQueryString(); }.bind(this)
486 openHistory = (nodeDisplay, nodeUri, nodeType) => { // open modal from Card
487 console.log('history >> showModal',nodeDisplay);
491 nodeDisplay: nodeDisplay,
492 showHistoryModal: true,
493 showModelOptions:true,
495 historyType:(this.state.historyType === 'cq') ? 'nodeState' : this.state.historyType,
496 focusedNodeUri: nodeUri,
497 focusedNodeType: nodeType,
500 let payload = this.formPayload();
502 showHistoryModal:true,
503 showModelOptions:false,
504 focusedNodeUri: JSON.stringify(payload),
505 focusedNodeType: nodeType,
511 closeHistory = () => {
513 showHistoryModal: false,
515 historyType :'nodeState'
520 console.log(event.currentTarget.value);
522 viewName: event.currentTarget.value
526 setDefaultViewName(event) {
527 let ENVIRONMENT = GlobalExtConstants.ENVIRONMENT;
528 let layout = event.target.value;
530 if(sessionStorage.getItem(ENVIRONMENT + 'userId')) {
531 if (event.target.checked) {
532 localStorage.setItem(ENVIRONMENT + '_' + sessionStorage.getItem(ENVIRONMENT + 'userId') + '_viewPreference', layout);
534 localStorage.removeItem(ENVIRONMENT + '_' + sessionStorage.getItem(ENVIRONMENT + 'userId') + '_viewPreference');
539 defaultViewName: event.target.value
543 submitHistory = () => {
544 console.log("submitting history");
545 let paramToPassThrough = '';
546 if(this.state.focusedNodeType){
547 paramToPassThrough = '/history/' + this.state.historyType +'/' + this.state.focusedNodeType + '/' + btoa(this.state.focusedNodeUri);
549 paramToPassThrough = '/historyQuery/' + this.state.historyType + '/' + btoa(this.state.focusedNodeUri);
551 let epochStartTime = (this.state.startDate).unix();
552 this.props.history.push(paramToPassThrough + '/' + epochStartTime * 1000);
555 handleDateChange = (newDate) =>{
556 this.setState({ startDate: moment(+newDate) });
557 console.log('[CustomQuery.jsx] handleDateChange date is ', this.state.startDate);
558 console.log('[CustomQuery.jsx] handleDateChange date is in millis ', +this.state.startDate);
560 setHistoryType(event) {
561 console.log(event.target.value);
562 let enableCalendar = false;
563 if(event.target.value === 'nodeLifeCycle'){
564 enableCalendar = false;
566 enableCalendar = true;
569 historyType: event.target.value,
570 enableCalendar: enableCalendar
572 console.log(this.state.enableCalendar);
574 openNodeModal(nodeDisplay, nodeUri, nodeType){ // open modal
575 console.log('customquery >> showModal');
576 nodeDisplay = "Node Details of " + nodeUri;
579 for(var j = 0; j < this.state.nodes.length && !found; j++){
580 if(this.state.nodes[j].url === nodeUri){
581 node = this.state.nodes[j];
585 if(nodeDisplay && found){
587 nodeDisplay: nodeDisplay,
598 closeNodeModal = () => {
603 componentDidUpdate(prevProps, prevState, snapshot) {
604 if(this.state.nodes.length > 0 && !this.state.visualAddition){
605 Visualization.chart('currentState', [], [], this.state.res.data, this);
607 showPagination: this.state.nodes.length > 0 ? true : false,
612 prepareDownloadRangeModel = () =>{
613 let downloadRangeModel = (this.state.showDownloadResultsModal)?<DownloadRangeModel
614 showDownloadResultsModal={this.state.showDownloadResultsModal}
615 totalPages={this.state.totalPages}
616 totalResults={this.state.totalResults}
617 triggerDownload={this.getAllExcels}
618 errorDownloadResults={this.state.errorDownloadResults}
619 downloadErrorMsg={this.state.downloadErrorMsg}
620 triggerClose={this.closeDownloadResults}
621 enableModelBusyFeedback={this.state.enableModelBusyFeedback}
623 return downloadRangeModel;
626 let simple = 'Enter Start Node Location => network/generic-vnfs/generic-vnf/a642ad94-9a84-4418-9358-c1ee860315e2';
627 let advanced = 'Enter Start Node Location => /cloud-infrastructure/cloud-regions/cloud-region/cloudowner1/cloudregion1';
628 let downloadRangeModel = this.prepareDownloadRangeModel();
629 if (this.state.displayValidationError) {
630 inputClasses.push('invalid');
632 let styling = inputClasses.join(' ');
633 console.log('styling:' + styling);
635 let classes = `${this.state.displayNodes} container-fluid`;
636 const modelGalleryElement = <ModelGallery
637 nodes={this.state.nodes}
638 viewName={this.state.viewName}
639 historyStackString={this.props.location.historyStackString}
640 openHistoryModal={this.openHistory}
641 isPageNumberChange={this.state.isPageNumberChange}
642 resetColumnInd={this.state.resetColumnFilters}
643 enableRealTime={false}/>;
644 if (this.state.nodes.length > 0) {
645 console.log('nodes exist');
649 {modelGalleryElement}
655 <header className='addPadding jumbotron my-4'>
656 <h1 className='display-2'>Welcome to Custom Queries!</h1>
658 On this page you can choose from the many different
659 predefined custom queries has to offer. Simply
660 choose the query name and provide the location of the
662 If prompted please also enter the values in required
663 properties field as some queries require these values
665 Check the Help Section on the right for examples.
668 <div className='static-modal'>
669 <Modal show={this.state.showHistoryModal} onHide={this.closeHistory}>
671 <Modal.Title>Retrieve {(this.state.focusedNodeType) ? this.state.focusedNodeType: 'Custom Query '} History</Modal.Title>
674 <form className={this.state.showModelOptions ? 'show' : 'hidden'}>
675 <div className="radio">
677 <input type="radio" value="nodeState"
678 checked={this.state.historyType === 'nodeState'}
679 onChange={(e) => this.setHistoryType(e)} />
683 <div className="radio">
685 <input type="radio" value="nodeLifeCycleSince"
686 checked={this.state.historyType === 'nodeLifeCycleSince'}
687 onChange={(e) => this.setHistoryType(e)} />
691 <div className="radio">
693 <input type="radio" value="nodeLifeCycle"
694 checked={this.state.historyType === 'nodeLifeCycle'}
695 onChange={(e) => this.setHistoryType(e)} />
700 <div className={this.state.enableCalendar ? 'show' : 'hidden'}>
703 selected={this.state.startDate}
704 onChange={(newDate) => this.handleDateChange(newDate)}
708 dateFormat="MMMM D, YYYY h:mm a"
714 <Button onClick={this.closeHistory}>Close</Button>
715 <Button onClick={this.submitHistory}>Submit</Button>
719 <div className='static-modal'>
720 <Modal show={this.state.showNodeModal} onHide={this.closeNodeModal} dialogClassName="modal-override">
722 <Modal.Title>Retrieve {this.state.nodeDisplay}</Modal.Title>
726 <Row className='show-grid'>
727 <Col lg={12} md={12} sm={12} xs={12}>
729 key={this.state.focusedNode.id}
730 nodeId={this.state.focusedNode.id}
731 nodeType={this.state.focusedNode['node-type']}
732 nodeProps={this.state.focusedNode.properties}
733 nodeRelatives={this.state.focusedNode['related-to']}
734 nodeUrl={this.state.focusedNode.url}
735 historyStackString={this.props.location.historyStackString}
736 openHistoryModal={this.openHistory}
737 enableRealTime={false}/>
743 <Button onClick={this.closeNodeModal}>Close</Button>
747 <div className='addPadding'>
748 <div className='row addPaddingTop'>
750 <form style={{ margin: 0 }} onSubmit={this.onAdditem} id='customQueryForm' name='customQueryForm'>
751 <div className='form-group'>
752 <label>Query:</label><br />
753 <div id='customQueryText'>
755 className='dropdown-item'
757 placeholder={this.state.queryPlaceHolder}
758 value={this.state.query}
759 onChange={this.updateSelectedHandler}
760 options={dropdownList} />
763 <div className={this.state.displayDescription} id='customQueryDescription'>
764 <Label bsStyle='info'>Description</Label>
765 <p><br />{this.state.description}</p>
766 <a onClick={() => this.setState({ showText: !this.state.showText })}
767 className={this.state.additionalInfo==='' ? 'hidden' : 'show'}>See more</a><br />
768 <Collapse in={this.state.showText}>
771 {this.state.additionalInfo.split('\n').map(info => {
772 return <div>{info}</div>;
778 <div className='form-group addPaddingTop' id='startNodeText'>
779 <label htmlFor='StartNode'>Enter Start Node Location (full uri path): </label>
784 placeholder={this.state.placeholder}
785 onChange={this.inputChangeHandler}
786 disabled={this.state.disableInputs}
787 value={this.state.startNode} />
789 <div className={this.state.displayReqProps} id='reqPropsText'>
790 <label htmlFor={'reqProps'}>Required Properties</label>
795 placeholder={this.state.reqPropPlaceholder}
796 onChange={this.inputChangeHandler}
797 disabled={this.state.disableInputs}
798 value={this.state.reqProps}/>
800 <div className={this.state.displayOptionalProps}>
801 <label htmlFor={'optionalProps'}>Optional Properties</label>
806 placeholder={this.state.optionalPropPlaceholder}
807 onChange={this.inputChangeHandler}
808 disabled={this.state.disableInputs}
809 value={this.state.optionalProps} />
811 <div className='row addPaddingTop'>
813 <button className='btn btn-primary btn-md' disabled={!this.state.formIsValid}>Submit</button>
814 { INVLIST.isHistoryEnabled && (<button className='btn btn-outline-secondary' type='button' onClick={this.openHistory} disabled={!this.state.formIsValid}>History</button>)}
820 <PanelGroup accordion id='rb-accordion'>
823 <Panel.Title toggle>+ Simple Query</Panel.Title>
825 <Panel.Body collapsible className='cardwrap'>
827 Please specify a Query from the Dropdown Menu.<br />
829 Please enter exact location of the Starting Node Path
834 Query => complex-fromVnf<br />
835 Enter Starting Node => /network/pnfs/pnf/pnf-name1<br /> <br />
837 *Simple Query requires no other values to be passed other than the start node path
843 <Panel.Title toggle>+ Advanced Queries with Properties</Panel.Title>
845 <Panel.Body collapsible>
846 <p className='cardwrap'>
847 Please specify a Query from the Dropdown Menu.<br />
849 Please enter exact location of the Starting Node Path<br /> <br />
850 Please enter required query parameter - if applicable<br /> <br />
851 Please enter optional query parameter - if applicable<br /> <br />
853 Query => vlantag-fromVlanidouter<br /> <br />
854 {advanced}<br /> <br />
855 Required Properties: vlanIdOuter=203<br /> <br />
856 Optional Properties: vlanIdInner=103
865 <div className='addPaddingTop'>
866 <div className='container-fluid model-container custom-query-result'>
867 <Spinner loading={this.state.isLoading}>
868 <Row className={this.state.isInitialLoad ? 'hidden' : 'show'}>
871 <span className='badge badge-dark'>{this.state.query}</span> Results
874 <h5>Total Results: <strong>{this.state.totalResults}</strong></h5>
877 { this.state.showResults && <div className='addPaddingTop'>
878 <OutputToggle scope={this} visualDisabled={this.state.totalResults > PAGINATION_CONSTANT}/>
880 <Row className={this.state.showResults ? 'show' : 'hidden'}>
881 <Col md={8} className={this.state.showPagination ? 'show' : 'hidden'}>
883 activePage={this.state.activePage}
884 itemsCountPerPage={PAGINATION_CONSTANT.RESULTS_PER_PAGE}
885 totalItemsCount={this.state.totalResults}
886 pageRangeDisplayed={PAGINATION_CONSTANT.PAGE_RANGE_DISPLAY}
887 onChange={this.handlePageChange} />
889 <Col md={2} className='text-right'>
890 <OverlayTrigger placement='top' overlay={<Tooltip id='tooltip-top'>{this.downloadAllTooltip}</Tooltip>}>
891 <span className="d-inline-block" style={{display: 'inline-block'}}>
892 <Button bsSize='small' onClick={()=>{this.getAllExcels(this.state.downloadCount)}}>
893 Download XLSX <i className='icon-documents-downloadablefile'></i>
898 <Col md={2} className='text-right'>
899 <OverlayTrigger placement='top' overlay={<Tooltip id='tooltip-top'>{this.downloadRangeTooltip}</Tooltip>}>
900 <span className="d-inline-block" style={{display: 'inline-block'}}>
901 <Button bsSize='small' onClick={this.openDownloadRange}>
902 Download XLSX (Range) <i className='icon-documents-downloadablefile'></i>
908 <div className={'addPaddingTop alert alert-danger ' +(this.state.errorResults ? 'show' : 'hidden')} role="alert">
909 An error occurred, please try again later. If this issue persists, please contact the system administrator. {this.state.errorMessage}
911 <Row className={'addPaddingTop ' + (this.state.noResults ? 'show' : 'hidden')}>
913 <h2>No Results Found</h2>
916 <Row className={this.state.isInitialLoad ? 'hidden' : 'show'}>
917 <div className={this.state.isLoading ? 'hidden' : 'show'}>
918 <div className='col align-self-center'>
919 <div className={classes}>
925 <Row className={this.state.showPagination ? 'show' : 'hidden'}>
928 activePage={this.state.activePage}
929 itemsCountPerPage={PAGINATION_CONSTANT.RESULTS_PER_PAGE}
930 totalItemsCount={this.state.totalResults}
931 pageRangeDisplayed={PAGINATION_CONSTANT.PAGE_RANGE_DISPLAY}
932 onChange={this.handlePageChange} />
936 <Spinner loading={this.state.enableModelBusyFeedback}>
946 export default CustomQuery;