a752bf665122dc8fb3cd96aa44ace434d24dc030
[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 import SkyquakeRBAC from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
29
30 //Temporary, until api server is on same port as webserver
31 var rw = require('utils/rw.js');
32 var API_SERVER = rw.getSearchParams(window.location).api_server;
33 var UPLOAD_SERVER = rw.getSearchParams(window.location).upload_server;
34
35 //
36 // Internal classes/functions
37 //
38
39 class LogoutAppMenuItem extends React.Component {
40     handleLogout() {
41         Utils.clearAuthentication();
42     }
43     render() {
44         return (
45             <div className="app">
46                 <h2>
47                     <a onClick={this.handleLogout}>
48                         Logout
49                     </a>
50                 </h2>
51             </div>
52         );
53     }
54 }
55
56 class SelectProject 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 props = this.props;
66         let currentValue = JSON.stringify(props.currentProject);
67         let projects = this.props.projects && this.props.projects.map((p,i) => {
68             return {
69                 label: p.name,
70                 value: p.name
71             }
72         });
73         let hasProjects = (this.props.projects && (this.props.projects.length > 0))
74         return (
75             <div className="userSection app">
76                 {
77                     hasProjects ?  'Project:' : 'No Projects Assigned'
78                 }
79                 {
80                     hasProjects ?
81                     <SelectOption
82                         options={projects}
83                         value={currentValue}
84                         defaultValue={currentValue}
85                         onChange={props.onSelectProject}
86                         className="projectSelect" />
87                     : null
88                 }
89             </div>
90         )
91     }
92 }
93
94 class UserNav extends React.Component {
95     constructor(props) {
96         super(props);
97     }
98     handleLogout() {
99         Utils.clearAuthentication();
100     }
101     selectProject(e) {
102         let value = JSON.parse(e.currentTarget.value)
103         console.log('selected project', value)
104     }
105     render() {
106         let props = this.props;
107         let userProfileLink = '';
108         this.props.nav['user_management'] && this.props.nav['user_management'].routes.map((r) => {
109             if(r.unique) {
110                 userProfileLink = returnLinkItem(r, props.currentUser)
111             }
112         })
113         return (
114             <div className="app">
115                 <h2>
116                     {userProfileLink}
117                     <span className="oi" data-glyph="caret-bottom"></span>
118                 </h2>
119                 <ul className="menu">
120                     <li>
121                         <a onClick={this.handleLogout}>
122                             Logout
123                         </a>
124                     </li>
125                 </ul>
126             </div>
127         )
128     }
129 }
130
131 UserNav.defaultProps = {
132     projects: [
133
134     ]
135 }
136
137 //
138 // Exported classes and functions
139 //
140
141 //
142 /**
143  * Skyquake Nav Component. Provides navigation functionality between all plugins
144  */
145 export default class skyquakeNav extends React.Component {
146     constructor(props) {
147         super(props);
148         this.state = {};
149         this.state.validateErrorEvent = 0;
150         this.state.validateErrorMsg = '';
151     }
152     componentDidMount() {
153         this.props.store.openProjectSocket();
154         this.props.store.getUserProfile();
155     }
156     validateError = (msg) => {
157         this.setState({
158             validateErrorEvent: true,
159             validateErrorMsg: msg
160         });
161     }
162     validateReset = () => {
163         this.setState({
164             validateErrorEvent: false
165         });
166     }
167     returnCrouton = () => {
168         return <Crouton
169             id={Date.now()}
170             message={this.state.validateErrorMsg}
171             type={"error"}
172             hidden={!(this.state.validateErrorEvent && this.state.validateErrorMsg)}
173             onDismiss={this.validateReset}
174         />;
175     }
176     render() {
177         let html;
178         html = (
179                 <div>
180                 {this.returnCrouton()}
181             <nav className="skyquakeNav">
182                 {buildNav.call(this, this.props.nav, this.props.currentPlugin, this.props)}
183             </nav>
184
185             </div>
186         )
187         return html;
188     }
189 }
190 skyquakeNav.defaultProps = {
191     nav: {}
192 }
193 /**
194  * Returns a React Component
195  * @param  {object} link  Information about the nav link
196  * @param  {string} link.route Hash route that the SPA should resolve
197  * @param  {string} link.name Link name to be displayed
198  * @param  {number} index index of current array item
199  * @return {object} component A React LI Component
200  */
201 //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.
202 export function buildNavListItem (k, link, index) {
203     let html = false;
204     if (link.type == 'external') {
205         this.hasSubNav[k] = true;
206         html = (
207             <li key={index}>
208                 {returnLinkItem(link)}
209             </li>
210         );
211     }
212     return html;
213 }
214
215 /**
216  * Builds a link to a React Router route or a new plugin route.
217  * @param  {object} link Routing information from nav object.
218  * @return {object}  component   returns a react component that links to a new route.
219  */
220 export function returnLinkItem(link, label) {
221     let ref;
222     let route = link.route;
223     if(link.isExternal) {
224         ref = (
225             <a href={route}>{label || link.label}</a>
226         )
227     } else {
228         if(link.path && link.path.replace(' ', '') != '') {
229             route = link.path;
230         }
231         if(link.query) {
232             let query = {};
233             query[link.query] = '';
234             route = {
235                 pathname: route,
236                 query: query
237             }
238         }
239         ref = (
240             <Link to={route}>
241                 {label || link.label}
242             </Link>
243         )
244     }
245     return ref;
246 }
247
248
249
250
251 /**
252  * Constructs nav for each plugin, along with available subnavs
253  * @param  {array} nav List returned from /nav endpoint.
254  * @return {array}     List of constructed nav element for each plugin
255  */
256 export function buildNav(nav, currentPlugin, props) {
257     let navList = [];
258     let navListHTML = [];
259     let secondaryNav = [];
260     let self = this;
261     self.hasSubNav = {};
262     let secondaryNavHTML = (
263         <div className="secondaryNav" key="secondaryNav">
264             {secondaryNav}
265             <SelectProject
266                 onSelectProject={props.store.selectActiveProject}
267                 projects={props.projects}
268                 currentProject={props.currentProject} />
269             <UserNav
270                 currentUser={props.currentUser}
271                 nav={nav}  />
272         </div>
273     )
274     for (let k in nav) {
275         if (nav.hasOwnProperty(k)) {
276             self.hasSubNav[k] = false;
277             let header = null;
278             let navClass = "app";
279             let routes = nav[k].routes;
280             let navItem = {};
281             //Primary plugin title and link to dashboard.
282             let route;
283             let NavList;
284             if (API_SERVER) {
285                 route = routes[0].isExternal ? '/' + k + '/index.html?api_server=' + API_SERVER + '' + '&upload_server=' + UPLOAD_SERVER + '' : '';
286             } else {
287                 route = routes[0].isExternal ? '/' + k + '/' : '';
288             }
289             let dashboardLink = returnLinkItem({
290                 isExternal: routes[0].isExternal,
291                 pluginName: nav[k].pluginName,
292                 label: nav[k].label || k,
293                 route: route
294             });
295             if (nav[k].pluginName == currentPlugin) {
296                 navClass += " active";
297             }
298             NavList = nav[k].routes.map(buildNavListItem.bind(self, k));
299             navItem.priority = nav[k].priority;
300             navItem.order = nav[k].order;
301             navItem.html = (
302                 <SkyquakeRBAC allow={nav[k].allow || ['*']} key={k} className={navClass}>
303                     <h2>{dashboardLink} {self.hasSubNav[k] ? <span className="oi" data-glyph="caret-bottom"></span> : ''}</h2>
304                     <ul className="menu">
305                         {
306                             NavList
307                         }
308                     </ul>
309                 </SkyquakeRBAC>
310             );
311             navList.push(navItem)
312         }
313     }
314     //Sorts nav items by order and returns only the markup
315     navListHTML = navList.sort((a,b) => a.order - b.order).map(function(n) {
316         if((n.priority  < 2)){
317             return n.html;
318         } else {
319             secondaryNav.push(n.html);
320         }
321     });
322     navListHTML.push(secondaryNavHTML);
323     return navListHTML;
324 }