Project UI updates and bug fixes
[osm/UI.git] / skyquake / framework / widgets / skyquake_nav / skyquakeNav.jsx
1 /*
2  *
3  *   Copyright 2016 RIFT.IO Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  *
17  */
18
19 import React from 'react';
20 import { Link } from 'react-router';
21 import Utils from 'utils/utils.js';
22 import Crouton from 'react-crouton';
23 import 'style/common.scss';
24
25 import './skyquakeNav.scss';
26 import SelectOption from '../form_controls/selectOption.jsx';
27 import {FormSection} from '../form_controls/formControls.jsx';
28
29 //Temporary, until api server is on same port as webserver
30 var rw = require('utils/rw.js');
31 var API_SERVER = rw.getSearchParams(window.location).api_server;
32 var UPLOAD_SERVER = rw.getSearchParams(window.location).upload_server;
33
34 //
35 // Internal classes/functions
36 //
37
38 class LogoutAppMenuItem extends React.Component {
39     handleLogout() {
40         Utils.clearAuthentication();
41     }
42     render() {
43         return (
44             <div className="app">
45                 <h2>
46                     <a onClick={this.handleLogout}>
47                         Logout
48                     </a>
49                 </h2>
50             </div>
51         );
52     }
53 }
54
55
56 class UserNav extends React.Component {
57     constructor(props) {
58         super(props);
59     }
60     selectProject(e) {
61         let value = JSON.parse(e.currentTarget.value)
62         console.log('selected project', value)
63     }
64     render() {
65         let projects = this.props.projects.map((p,i) => {
66             return {
67                 label: p.name,
68                 value: p
69             }
70         })
71         return (
72             <div className="userSection">
73                 Project:
74                 <SelectOption options={projects} onChange={this.selectProject} className="projectSelect"/>
75             </div>
76         )
77     }
78 }
79
80 UserNav.defaultProps = {
81     projects: [
82
83     ]
84 }
85
86 //
87 // Exported classes and functions
88 //
89
90 //
91 /**
92  * Skyquake Nav Component. Provides navigation functionality between all plugins
93  */
94 export default class skyquakeNav extends React.Component {
95     constructor(props) {
96         super(props);
97         this.state = {};
98         this.state.validateErrorEvent = 0;
99         this.state.validateErrorMsg = '';
100     }
101     componentDidMount() {
102         this.props.store.openProjectSocket();
103         this.props.store.getUserProfile();
104     }
105     validateError = (msg) => {
106         this.setState({
107             validateErrorEvent: true,
108             validateErrorMsg: msg
109         });
110     }
111     validateReset = () => {
112         this.setState({
113             validateErrorEvent: false
114         });
115     }
116     returnCrouton = () => {
117         return <Crouton
118             id={Date.now()}
119             message={this.state.validateErrorMsg}
120             type={"error"}
121             hidden={!(this.state.validateErrorEvent && this.state.validateErrorMsg)}
122             onDismiss={this.validateReset}
123         />;
124     }
125     render() {
126         let html;
127         html = (
128                 <div>
129                 {this.returnCrouton()}
130             <nav className="skyquakeNav">
131                 {buildNav.call(this, this.props.nav, this.props.currentPlugin, this.props)}
132             </nav>
133
134             </div>
135         )
136         return html;
137     }
138 }
139 skyquakeNav.defaultProps = {
140     nav: {}
141 }
142 /**
143  * Returns a React Component
144  * @param  {object} link  Information about the nav link
145  * @param  {string} link.route Hash route that the SPA should resolve
146  * @param  {string} link.name Link name to be displayed
147  * @param  {number} index index of current array item
148  * @return {object} component A React LI Component
149  */
150 //This should be extended to also make use of internal/external links and determine if the link should refer to an outside plugin or itself.
151 export function buildNavListItem (k, link, index) {
152     let html = false;
153     if (link.type == 'external') {
154         this.hasSubNav[k] = true;
155         html = (
156             <li key={index}>
157                 {returnLinkItem(link)}
158             </li>
159         );
160     }
161     return html;
162 }
163
164 /**
165  * Builds a link to a React Router route or a new plugin route.
166  * @param  {object} link Routing information from nav object.
167  * @return {object}  component   returns a react component that links to a new route.
168  */
169 export function returnLinkItem(link) {
170     let ref;
171     let route = link.route;
172     if(link.isExternal) {
173         ref = (
174             <a href={route}>{link.label}</a>
175         )
176     } else {
177         if(link.path && link.path.replace(' ', '') != '') {
178             route = link.path;
179         }
180         if(link.query) {
181             let query = {};
182             query[link.query] = '';
183             route = {
184                 pathname: route,
185                 query: query
186             }
187         }
188         ref = (
189            <Link to={route}>
190                 {link.label}
191             </Link>
192         )
193     }
194     return ref;
195 }
196
197
198
199
200 /**
201  * Constructs nav for each plugin, along with available subnavs
202  * @param  {array} nav List returned from /nav endpoint.
203  * @return {array}     List of constructed nav element for each plugin
204  */
205 export function buildNav(nav, currentPlugin, props) {
206     let navList = [];
207     let navListHTML = [];
208     let secondaryNav = [];
209     let self = this;
210     self.hasSubNav = {};
211     let secondaryNavHTML = (
212         <div className="secondaryNav" key="secondaryNav">
213             {secondaryNav}
214             <UserNav projects={props.projects}/>
215             <LogoutAppMenuItem />
216         </div>
217     )
218     for (let k in nav) {
219         if (nav.hasOwnProperty(k)) {
220             self.hasSubNav[k] = false;
221             let header = null;
222             let navClass = "app";
223             let routes = nav[k].routes;
224             let navItem = {};
225             //Primary plugin title and link to dashboard.
226             let route;
227             let NavList;
228             if (API_SERVER) {
229                 route = routes[0].isExternal ? '/' + k + '/index.html?api_server=' + API_SERVER + '' + '&upload_server=' + UPLOAD_SERVER + '' : '';
230             } else {
231                 route = routes[0].isExternal ? '/' + k + '/' : '';
232             }
233             let dashboardLink = returnLinkItem({
234                 isExternal: routes[0].isExternal,
235                 pluginName: nav[k].pluginName,
236                 label: nav[k].label || k,
237                 route: route
238             });
239             if (nav[k].pluginName == currentPlugin) {
240                 navClass += " active";
241             }
242             NavList = nav[k].routes.map(buildNavListItem.bind(self, k));
243             navItem.priority = nav[k].priority;
244             navItem.order = nav[k].order;
245             navItem.html = (
246                 <div key={k} className={navClass}>
247                     <h2>{dashboardLink} {self.hasSubNav[k] ? <span className="oi" data-glyph="caret-bottom"></span> : ''}</h2>
248                     <ul className="menu">
249                         {
250                             NavList
251                         }
252                     </ul>
253                 </div>
254             );
255             navList.push(navItem)
256         }
257     }
258     //Sorts nav items by order and returns only the markup
259     navListHTML = navList.sort((a,b) => a.order - b.order).map(function(n) {
260         if((n.priority  < 2)){
261             return n.html;
262         } else {
263             secondaryNav.push(n.html);
264         }
265     });
266     navListHTML.push(secondaryNavHTML);
267     return navListHTML;
268 }