Adding filter bar
[aai/sparky-fe.git] / src / app / MainScreenHeader.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 FontAwesome from 'react-fontawesome';
26 import Button from 'react-bootstrap/lib/Button.js';
27 import Modal from 'react-bootstrap/lib/Modal.js';
28 import GlobalAutoCompleteSearchBar from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBar.jsx';
29 import {postAnalyticsData} from 'app/analytics/AnalyticsActions.js';
30 import GlobalInlineMessageBar from 'app/GlobalInlineMessageBar/GlobalInlineMessageBar.jsx';
31 import {getClearGlobalMessageEvent} from 'app/globalInlineMessageBar/GlobalInlineMessageBarActions.js';
32 import {externalUrlRequest, externalMessageRequest} from 'app/contextHandler/ContextHandlerActions.js';
33
34 import {
35   Route,
36   NavLink
37 } from 'react-router-dom';
38
39 import {
40   AAI_TITLE,
41   MENU_ITEM_TIER_SUPPORT,
42   MENU_ITEM_VNF_SEARCH
43 } from './MainScreenWrapperConstants.js';
44
45 import {
46   showMainMenu,
47   clearExtensibleViewData,
48   setSecondaryTitle
49 } from './MainScreenWrapperActionHelper.js';
50
51 import {clearSuggestionsTextField} from 'app/globalAutoCompleteSearchBar/GlobalAutoCompleteSearchBarActions.js';
52 import {changeUrlAddress} from 'utils/Routes.js';
53 import extensibleViews from 'resources/views/extensibleViews.json';
54 import {clearFilters} from 'generic-components/filterBar/FilterBarUtils.js';
55 const mapStateToProps = ({mainWrapper}) => {
56   let {
57     showMenu = false,
58     toggleButtonActive = false,
59     externalRequestFound = {},
60     secondaryTitle = ''
61   } = mainWrapper;
62
63   return {
64     showMenu,
65     toggleButtonActive,
66     externalRequestFound,
67     secondaryTitle
68   };
69 };
70
71
72 const mapActionsToProps = (dispatch) => {
73   return {
74     onShowMenu: () => dispatch(showMainMenu(true)),
75     onHideMenu: () => {
76       dispatch(showMainMenu(false));
77     },
78     dispatchAnalyticsData: () => dispatch(
79       postAnalyticsData(document.documentElement.outerHTML.replace('\s+', ''))),
80     onRouteChange: () => {
81       dispatch(getClearGlobalMessageEvent());
82       dispatch(clearSuggestionsTextField());
83       dispatch(clearExtensibleViewData());
84       dispatch(clearFilters());
85       dispatch(setSecondaryTitle(undefined));
86     },
87     onExternalUrlRequest: (urlParamString) => {
88       dispatch(externalUrlRequest(urlParamString));
89     },
90     onExternalMessageRecieved: (messageJson) => {
91       dispatch(externalMessageRequest(messageJson));
92     }
93   };
94 };
95
96 class MainScreenHeader extends Component {
97   static propTypes = {
98     showMenu: React.PropTypes.bool,
99     toggleButtonActive: React.PropTypes.bool,
100     externalRequestFound: React.PropTypes.object,
101     secondaryTitle: React.PropTypes.string
102   };
103
104   navigationLinkAndCurrentPathMatch(location, to) {
105     let linkPathElements = to.split('/');
106     let locationElements = location.pathname.split('/');
107
108     // the element arrays above will have the route at index 1 ... need to
109     // verify if the routes match
110     return locationElements[1] === linkPathElements[1];
111   }
112
113   hasRouteChanged(currentPath, nextPath) {
114     let currentPathParts = currentPath.split('/');
115     let nextPathParts = nextPath.split('/');
116
117     if (currentPathParts[1] !== nextPathParts[1]) {
118       return true;
119     } else {
120       return false;
121     }
122   }
123   isValidExternalURL(url) {
124     if(decodeURIComponent(url).indexOf('&') > 0 ) {
125       return true;
126     } else {
127       return false;
128     }
129   }
130   componentWillMount() {
131     if(this.props.match.params.externalUrl !== undefined &&
132       this.isValidExternalURL(this.props.match.params.externalUrl)) {
133       this.props.onExternalUrlRequest(this.props.match.params.externalUrl);
134     }
135   }
136   componentWillReceiveProps(nextProps) {
137     if (this.props.location &&
138       this.props.location.pathname !==
139       nextProps.location.pathname) {
140       // update analytics
141       this.props.dispatchAnalyticsData();
142
143       if (this.hasRouteChanged(this.props.location.pathname,
144           nextProps.location.pathname)) {
145         this.props.onRouteChange();
146       }
147     }
148
149     if(nextProps.match.params.externalUrl !== undefined &&
150       nextProps.match.params.externalUrl !== this.props.match.params.externalUrl &&
151       this.isValidExternalURL(nextProps.match.params.externalUrl)) {
152       this.props.onExternalUrlRequest(nextProps.match.params.externalUrl);
153     }
154     /* if the externalURL is not valid, we do not add any message as other proper
155     views will get that messages since the route will be this parameter.*/
156
157     if(this.props.externalRequestFound !== nextProps.externalRequestFound &&
158       nextProps.externalRequestFound !== undefined && nextProps.externalRequestFound.suggestion !== undefined) {
159       changeUrlAddress(nextProps.externalRequestFound.suggestion, nextProps.history);
160     }
161   }
162
163   receiveMessage(event) {
164     function isJson(str) {
165       try {
166         JSON.parse(str);
167       } catch (e) {
168         return false;
169       }
170       return true;
171     }
172     let messageData = event.data.message;
173     if(isJson(messageData)) {
174       this.props.onExternalMessageRecieved(JSON.parse(messageData));
175     }
176   }
177   componentDidMount() {
178     window.addEventListener('message', this.receiveMessage, false);
179   }
180   componentWillUnmount() {
181     window.removeEventListener('message', this.receiveMessage);
182   }
183
184   render() {
185     let {
186       showMenu,
187       onShowMenu,
188       onHideMenu,
189       toggleButtonActive,
190       secondaryTitle
191     } = this.props;
192
193     let menuOptions = [];
194
195     const MenuItem = ({label, iconClass, to}) => (
196       <Route path={to} children={({location}) => (
197         <NavLink to={to} onClick={onHideMenu}>
198           <div className={this.navigationLinkAndCurrentPathMatch(location, to) ? 'main-menu-button-active' : 'main-menu-button'}>
199             <div className={iconClass}/>
200             <div className='button-icon'>{label}</div>
201           </div>
202         </NavLink>
203       )}/>
204     );
205
206     // add Tier Support view
207     menuOptions.push(
208       <MenuItem key='schemaMenu' to='/schema' label={MENU_ITEM_TIER_SUPPORT}
209                 iconClass='button-icon view-inspect-button-icon'/>
210     );
211
212     // add VNF view
213     menuOptions.push(
214       <MenuItem key='vnfSearchMenu'
215         to='/vnfSearch'
216         label={MENU_ITEM_VNF_SEARCH}
217         iconClass='button-icon vnf-search-button-icon'/>
218     );
219
220     // add all custom view menu options
221     for (let view in extensibleViews) {
222       menuOptions.push(
223         <MenuItem key={extensibleViews[view]['viewName'] + 'Menu'} to={'/' + extensibleViews[view]['viewName']}
224                   label={extensibleViews[view]['displayName']}
225                   iconClass={'button-icon ' + extensibleViews[view]['iconClass']}/>
226       );
227     }
228
229     let secondaryTitleClass = 'secondary-header';
230     if (secondaryTitle === undefined || secondaryTitle === '') {
231       secondaryTitleClass = secondaryTitleClass + ' hidden';
232     }
233
234     return (
235       <div className='header'>
236         <div>
237           <Button
238             bsClass={(toggleButtonActive)
239             ? 'toggle-view-button-active'
240             : 'toggle-view-button'}
241             onClick={onShowMenu}>
242             <FontAwesome name='bars'/>
243           </Button>
244           <Modal show={showMenu} onHide={onHideMenu}
245                  dialogClassName='modal-main-menu'>
246             <Modal.Body>
247               {menuOptions}
248             </Modal.Body>
249           </Modal>
250           <span className='application-title'>{AAI_TITLE}</span>
251           <GlobalAutoCompleteSearchBar history={this.props.history}/>
252         </div>
253         <GlobalInlineMessageBar />
254         <div className={secondaryTitleClass}>
255           <span className='secondary-title'>{secondaryTitle}</span>
256         </div>
257       </div>
258     );
259   }
260 }
261
262 export default connect(mapStateToProps, mapActionsToProps)(MainScreenHeader);