f4e698063705eac45662959886acc4f285620b82
[aai/sparky-fe.git] / src / app / vnfSearch / VnfSearch.jsx
1 /*
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 import React, {Component} from 'react';
24 import {connect} from 'react-redux';
25 import {
26   isEqual,
27   isEmpty
28 } from 'lodash';
29 import {VerticalFilterBar} from 'vertical-filter-bar';
30 import {CollapsibleSlidingPanel} from 'collapsible-sliding-panel';
31
32 import {setSecondaryTitle} from 'app/MainScreenWrapperActionHelper.js';
33 import {
34   vnfActionTypes,
35   VNF_TITLE,
36   VNFS_ROUTE,
37   VNF_SEARCH_FILTER_NAME
38 } from 'app/vnfSearch/VnfSearchConstants.js';
39 import {
40   processVnfVisualizationsOnFilterChange,
41   processVnfFilterPanelCollapse,
42   setNotificationText,
43   clearVnfSearchData
44 } from 'app/vnfSearch/VnfSearchActions.js';
45 import VnfSearchOrchStatusVisualizations from 'app/vnfSearch/VnfSearchOrchestratedStatusVisualization.jsx';
46 import VnfSearchProvStatusVisualizations from 'app/vnfSearch/VnfSearchProvStatusVisualization.jsx';
47 import VnfSearchNfTypeVisualizations from 'app/vnfSearch/VnfSearchNfTypeVisualization.jsx';
48 import VnfSearchNfRoleVisualizations from 'app/vnfSearch/VnfSearchNfRoleVisualization.jsx';
49 import VnfSearchTotalCountVisualization from 'app/vnfSearch/VnfSearchTotalCountVisualization.jsx';
50 import i18n from 'utils/i18n/i18n';
51 import {changeUrlAddress, buildRouteObjWithFilters} from 'utils/Routes.js';
52 import {
53   getUnifiedFilters,
54   processFilterSelection,
55   setNonConvertedFilterValues,
56   convertNonConvertedValues,
57   buildFilterValueMap,
58   setFilterSelectionsToDefaults,
59   FILTER_BAR_TITLE
60 } from 'generic-components/filterBar/FilterBarUtils.js';
61
62 const mapStateToProps = ({vnfSearch}) => {
63   let {
64         feedbackMsgText = '',
65         feedbackMsgSeverity = '',
66         vnfFilters = {},
67         selectedFilterValues = {},
68         vnfFilterValues = {},
69         vnfVisualizationPanelClass = 'collapsible-panel-main-panel',
70         unifiedFilterValues = {},
71         nonConvertedFilters = {}
72       } = vnfSearch;
73
74   return {
75     feedbackMsgText,
76     feedbackMsgSeverity,
77     vnfFilters,
78     selectedFilterValues,
79     vnfFilterValues,
80     vnfVisualizationPanelClass,
81     unifiedFilterValues,
82     nonConvertedFilters
83   };
84 };
85
86 let mapActionToProps = (dispatch) => {
87   return {
88     onSetViewTitle: (title) => {
89       dispatch(setSecondaryTitle(title));
90     },
91     onInitializeVnfSearchFilters: () => {
92       // first time to the page, need to get the list of available filters
93       dispatch(getUnifiedFilters(VNF_SEARCH_FILTER_NAME, vnfActionTypes.VNF_SEARCH_FILTERS_RECEIVED));
94     },
95     onFilterPanelCollapse: (isOpen) => {
96       // expand/collapse the filter panel
97       dispatch(processVnfFilterPanelCollapse(isOpen));
98     },
99     onFilterSelection: (selectedFilters, allFilters) => {
100       // callback for filter bar whenever a selection is made... need to
101       // convert and save the selected value(s)
102       if (Object.keys(allFilters).length > 0) {
103         // only process the selection if allFilters has values (possible that
104         // filter bar is sending back the default filter selections before
105         // we have received the list of available filters i.e. allFilters)
106         dispatch(processFilterSelection(selectedFilters, allFilters));
107       }
108     },
109     onFilterValueChange: (convertedFilterValues) => {
110       // filter values have been converted, now update the VNF visualizations
111       dispatch(processVnfVisualizationsOnFilterChange(convertedFilterValues));
112     },
113     onReceiveNewFilterValueParams: (filterValueString) => {
114       // new filter values have been received as URL parameters, save the
115       // non-converted values (later to be converted and sent to filter bar)
116       // and update the VNF visualizations
117       let filterValueMap =  buildFilterValueMap(filterValueString);
118
119       dispatch(setNonConvertedFilterValues(filterValueMap));
120       dispatch(processVnfVisualizationsOnFilterChange(filterValueMap));
121
122       // incase url param was changed manually, need to update vnfFilterValues
123     },
124     onResetFilterBarToDefaults: (filters, filterValues) => {
125       dispatch(setFilterSelectionsToDefaults(filters, filterValues));
126     },
127     onPrepareToUnmount: () => {
128       // clean things up:
129       // 1- clear the VNF data
130       // 2- ensure filter bar is closed
131       dispatch(clearVnfSearchData());
132       dispatch(processVnfFilterPanelCollapse(false));
133     },
134     onConvertFilterValues: (nonConvertedValues, allFilters, currentlySetFilterValues) => {
135       // we have saved non-converted filter values received from URL params,
136       // time to convert them so can update filter bar selections programatically
137       dispatch(convertNonConvertedValues(nonConvertedValues, allFilters, currentlySetFilterValues));
138     },
139     onMessageStateChange: (msgText, msgSeverity) => {
140       dispatch(setNotificationText(msgText, msgSeverity));
141     }
142   };
143 };
144
145 class vnfSearch extends Component {
146   static propTypes = {
147     feedbackMsgText: React.PropTypes.string,
148     feedbackSeverity: React.PropTypes.string,
149     vnfFilters: React.PropTypes.object,
150     selectedFilterValues: React.PropTypes.object,
151     vnfFilterValues: React.PropTypes.object,
152     vnfVisualizationPanelClass: React.PropTypes.string,
153     unifiedFilterValues: React.PropTypes.object,
154     nonConvertedFilters: React.PropTypes.object
155   };
156
157   componentWillMount() {
158     this.props.onSetViewTitle(i18n(VNF_TITLE));
159     this.props.onInitializeVnfSearchFilters();
160
161     if (this.props.match &&
162       this.props.match.params &&
163       this.props.match.params.filters) {
164       this.props.onReceiveNewFilterValueParams(this.props.match.params.filters);
165     }
166
167     if (this.props.feedbackMsgText) {
168       this.props.onMessageStateChange(this.props.feedbackMsgText,
169         this.props.feedbackMsgSeverity);
170     }
171   }
172
173   componentWillReceiveProps(nextProps) {
174     if (nextProps.feedbackMsgText &&
175       nextProps.feedbackMsgText !==
176       this.props.feedbackMsgText) {
177       this.props.onMessageStateChange(nextProps.feedbackMsgText,
178         nextProps.feedbackMsgSeverity);
179     }
180
181     if (nextProps.vnfFilterValues &&
182       !isEqual(nextProps.vnfFilterValues, this.props.vnfFilterValues) &&
183       this.props.vnfFilters) {
184       this.props.onFilterValueChange(nextProps.vnfFilterValues);
185       changeUrlAddress(buildRouteObjWithFilters(VNFS_ROUTE, nextProps.vnfFilterValues),
186         this.props.history);
187     }
188
189     if (nextProps.match &&
190       nextProps.match.params &&
191       nextProps.match.params.filters &&
192       !isEqual(nextProps.match.params.filters, this.props.match.params.filters)) {
193       // added line below to reload the filters if filter changes, this will load new filters
194       this.props.onInitializeVnfSearchFilters();
195       this.props.onReceiveNewFilterValueParams(nextProps.match.params.filters);
196     } else if (Object.keys(nextProps.nonConvertedFilters).length > 0 &&
197       !isEqual(this.props.nonConvertedFilters, nextProps.nonConvertedFilters)) {
198       if (Object.keys(this.props.vnfFilters).length > 0) {
199         this.props.onConvertFilterValues(
200           nextProps.nonConvertedFilters, this.props.vnfFilters, this.props.vnfFilterValues);
201       }
202     } else if ((!nextProps.match || !nextProps.match.params || !nextProps.match.params.filters) &&
203       this.props.match.params.filters && this.props.vnfFilters && this.props.vnfFilterValues) {
204       // VNF Search navigation button was pressed while the view is still visible ... need to reset
205       // the filter bar selections to the default values
206       this.props.onResetFilterBarToDefaults(this.props.vnfFilters, this.props.vnfFilterValues);
207     }
208
209     if (nextProps.vnfFilters && !isEqual(nextProps.vnfFilters, this.props.vnfFilters) &&
210       Object.keys(this.props.nonConvertedFilters).length > 0) {
211       // just received list of available filters and there is are nonConvertedFilters (previously
212       // set from url params), need to convert those values and update the filter bar selections
213       this.props.onConvertFilterValues(
214         this.props.nonConvertedFilters, nextProps.vnfFilters, this.props.vnfFilterValues);
215     } else if (nextProps.vnfFilters && !isEqual(nextProps.vnfFilters, this.props.vnfFilters) &&
216       isEmpty(this.props.vnfFilterValues)) {
217       // filter bar previously returned the default filter selections (but we didn't have the list
218       // of available filters at the time, so couldn't do anything. Now receiving the list of
219       // available filters, so triger the filter selection action in order to load the visualization data
220       this.props.onResetFilterBarToDefaults(nextProps.vnfFilters, this.props.vnfFilterValues);
221     }
222   }
223
224   componentWillUnmount() {
225     // set the data to 'NO DATA' so upon return, the view is rendered with
226     // no data until the request for new data is returned
227     this.props.onPrepareToUnmount();
228   }
229
230   getFilterBar() {
231     return (
232       <VerticalFilterBar
233         filtersConfig={this.props.vnfFilters}
234         filterValues={this.props.unifiedFilterValues}
235         filterTitle={FILTER_BAR_TITLE}
236         onFilterChange={(selectedFilters) =>
237           this.props.onFilterSelection(selectedFilters, this.props.vnfFilters)} />    );
238   }
239
240   render() {
241     let filterBar = this.getFilterBar();
242
243     return (
244       <div className='view-container'>
245         <CollapsibleSlidingPanel
246           slidingPanelClassName='collapsible-sliding-panel'
247           slidingPanelClosedClassName='collapsible-sliding-panel-is-closed'
248           expanderHandleClassName='collapsible-sliding-panel-expander'
249           slidingPanelContent={filterBar}>
250           <div className={this.props.vnfVisualizationPanelClass}>
251             <VnfSearchTotalCountVisualization />
252             <VnfSearchProvStatusVisualizations />
253             <VnfSearchOrchStatusVisualizations />
254             <VnfSearchNfTypeVisualizations />
255             <VnfSearchNfRoleVisualizations />
256           </div>
257         </CollapsibleSlidingPanel>
258       </div>
259     );
260   }
261 }
262 export default connect(mapStateToProps, mapActionToProps)(vnfSearch);