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