update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / launchpad / src / recordViewer / recordCard.jsx
1
2 /*
3  *
4  *   Copyright 2016 RIFT.IO Inc
5  *
6  *   Licensed under the Apache License, Version 2.0 (the "License");
7  *   you may not use this file except in compliance with the License.
8  *   You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *   Unless required by applicable law or agreed to in writing, software
13  *   distributed under the License is distributed on an "AS IS" BASIS,
14  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *   See the License for the specific language governing permissions and
16  *   limitations under the License.
17  *
18  */
19 import React from 'react';
20 import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
21 import DashboardCard from 'widgets/dashboard_card/dashboard_card.jsx';
22 import MonitoringParamsCarousel from '../monitoring_params/monitoringParamsCarousel.jsx';
23 import VnfrCard from '../vnfr/vnfrCard.jsx';
24 import {LaunchpadCard, LpCardNfviMetrics, EpaParams, NsrPrimitiveJobList} from '../launchpad_card/launchpadCard.jsx';
25 import VnfrConfigPrimitives from '../launchpad_card/vnfrConfigPrimitives.jsx';
26 import NsrConfigPrimitives from '../launchpad_card/nsrConfigPrimitives.jsx';
27 import NsrScalingGroups from '../launchpad_card/nsrScalingGroups.jsx';
28 import LoadingIndicator from 'widgets/loading-indicator/loadingIndicator.jsx';
29 import NfviMetricBars from 'widgets/nfvi-metric-bars/nfviMetricBars.jsx';
30 import ParseMP from '../monitoring_params/monitoringParamComponents.js';
31 import PlacementGroupsInfo from './placementGroupsInfo.jsx';
32 import JobListCard from '../launchpad_card/jobListCard.jsx';
33 import NSVirtualLinks from '../virtual_links/nsVirtualLinks.jsx';
34 import LaunchpadFleetStore from '../launchpadFleetStore.js';
35 import _forEach from 'lodash/forEach';
36 import Prism from 'prismjs';
37 import 'prismjs/themes/prism.css';
38 import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
39
40 import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
41 import ROLES from 'utils/roleConstants.js';
42
43 const PROJECT_ROLES = ROLES.PROJECT;
44
45 class RecordCard extends React.Component {
46   constructor(props) {
47     super(props)
48   }
49
50   handleSelect = (index, last) => {
51       // console.log('Selected tab is', index, 'last index is', last);
52   }
53
54   openConsole = (url, event) => {
55     event.preventDefault();
56     LaunchpadFleetStore.getVDUConsoleLink(url);
57   }
58
59   render(){
60     let self = this;
61     let html;
62     let content;
63     let card;
64     let cardData = {};
65     let components = [];
66     let configPrimitivesProps = {};
67     let displayConfigPrimitives = false;
68     let configPrimitiveComponent = null;
69     let scalingGroupsProps = {};
70     let displayScalingGroups = false;
71     let scalingGroupComponent = null;
72     let consoleUrlsComponent = null;
73     let consoleUrlsList = [];
74
75     let displayNSVirtualLinks = false;
76     let nsVirtualLinksProps = {};
77     let nsVirtualLinksComponent = null;
78     let displayVolumesTab = false;
79     let volumesHTML = [];
80     let tabList = [];
81     let tabPanels = [];
82
83     let notice = null;
84
85     let hasAccess = isRBACValid(this.context.userProfile, [PROJECT_ROLES.LCM_ADMIN, PROJECT_ROLES.PROJECT_ADMIN]);
86
87     switch(this.props.type) {
88       case 'vnfr' :
89         cardData = this.props.data[0];
90         // Disabling config primitives for VNF
91         configPrimitivesProps = [cardData];
92         displayConfigPrimitives = cardData['service-primitives-present'];
93         if (displayConfigPrimitives) {
94           configPrimitiveComponent = (
95             <div className="flex vnfrConfigPrimitiveContainer">
96               <VnfrConfigPrimitives data={configPrimitivesProps} hasAccess={hasAccess} />
97             {/* <NsrPrimitiveJobList jobs={cardData['config-agent-job']}/> */}
98             <div style={{display:'flex', flexDirection: 'column',     flex: '1 1 40%'}}>
99                 <div className="launchpadCard_title">
100                   JOB LIST
101                 </div>
102                 <div className="scrollContainer">
103                 {
104                   //Sort for recent on top
105                   this.props.jobData
106                   .sort(function(a,b){
107                     return parseInt(b['job-id']) - parseInt(a['job-id']);
108                   })
109                   .map(function(job){
110                     //Return only vnfr configs
111                     if(job["triggered-by"] == 'vnf-primitive') {
112                       return job.vnfr.map(function(v){
113                         //That match the currently selected job id
114                         if(v.id == cardData.id) {
115                           return v.primitive.map(function(p, i) {
116                             return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={job['job-id'] + '-' + i} {...p} />
117                           })
118                         }
119                       })
120                     }
121                   })}
122                 </div>
123               </div>
124             </div>
125           );
126         }
127
128         if (cardData['vdur']) {
129           cardData['vdur'].map((vdur, index) => {
130             let consoleLink = vdur['console-url'] ? 'Obtain Token And Open VM Console' : 'None';
131             consoleUrlsList.push(
132               <li key={index}>
133                 <h3>
134                   {vdur['name'] + '-' + vdur.id.substr(0,4)}
135                 </h3>
136                 <span className='consoleLink' onClick={self.openConsole.bind(self, vdur["console-url"])}>
137                   {consoleLink} *
138                 </span>
139               </li>
140             )
141             notice = <li className='notice'>* If a separate browser window does not open, please check if the popup was blocked and allow it.</li>
142             if(vdur.hasOwnProperty('volumes') && (vdur.volumes.length > 0)) {
143               displayVolumesTab = true;
144               vdur.volumes.map((volume, vi) => {
145                 // let html = Prism.highlight(JSON.stringify(volume), Prism.languages.javascript, 'javascript');
146                 // volumesHTML.push(
147                 //     <pre className="language-js" key={index + '-' + vi}>
148                 //       <code dangerouslySetInnerHTML={{__html: html}} />
149                 //     </pre>
150                 function buildProperties(obj) {
151                   let p = [];
152                     _forEach(obj, function(v, k) {
153                       if (!v) {
154                         return null;
155                       }
156                     p.push(
157                       <div style={{margin: '0.5rem 0.5rem'}} key={k + '-' + vi}>
158                         <div style={{margin: '0 0.5rem', fontWeight: 'bold', textTransform: 'uppercase', color: '#5b5b5b'}}>{k}</div>
159                         <div style={{margin: '0 0.5rem'}}>{(v.constructor.name == 'String' || v.constructor.name == 'Number') ? v : buildProperties(v)}</div>
160                       </div>
161                     )
162                   });
163                     return p;
164                  }
165                 volumesHTML.push(
166                     <div key={index + vi}>
167                       <div className="launchpadCard_title">
168                         VOLUME ({vdur['name']})
169                       </div>
170                       <div style={{display: 'flex', flexDirection: 'column'}}>
171                       {
172                         buildProperties(volume)
173                       }
174                       </div>
175                     </div>
176                 )
177               })
178             }
179           });
180           consoleUrlsComponent = (
181             <div className="consoleUrlsComponent">
182               <ul className="consoleUrlsList">
183                 {consoleUrlsList}
184                 {notice}
185               </ul>
186             </div>
187           );
188         }
189         components = ParseMP.call(this, cardData["monitoring-param"], "vnfr-id");
190         break;
191       case 'nsr' :
192         cardData = this.props.data.nsrs[0];
193         configPrimitivesProps = cardData;
194         scalingGroupsProps = cardData;
195         displayConfigPrimitives = cardData['service-primitive'];
196         displayScalingGroups = cardData['scaling-group-descriptor'] ? true : false;
197         let sortedJobs = this.props.jobData.sort(function(a,b){
198                     return parseInt(b['job-id']) - parseInt(a['job-id']);
199                   });
200         if (displayConfigPrimitives) {
201           configPrimitiveComponent = (
202             <div className="flex nsConfigPrimitiveContainer">
203               <NsrConfigPrimitives data={configPrimitivesProps} hasAccess={hasAccess}  />
204               <div style={{display:'flex', flexDirection: 'column',     flex: '1 1 40%'}}>
205                 <div className="launchpadCard_title">
206                   JOB LIST
207                 </div>
208                 <div className="scrollContainer">
209                   {sortedJobs.map(function(job, i){
210                     if(job["triggered-by"] == 'ns-primitive') {
211                       return <JobListCard type="nsr" job-id={job['job-id']} cardData={cardData} key={job['job-id'] + '-' + 'nsr'} {...job} />
212                     }
213                   })
214                   .concat(sortedJobs.map(function(job) {
215                     if(!job.hasOwnProperty('job-name') && (job["triggered-by"] == 'ns-primitive')) {
216                       return job.vnfr.map(function(v, h){
217                         //That match the currently selected job id
218                         if(v.id == cardData.id) {
219                           return v.primitive.map(function(p, i) {
220                             return <JobListCard type="vnfr" job-id={job['job-id']} cardData={cardData} key={job['job-id'] + '-' + 'vnfr' + '-' + h} {...p} />
221                           })
222                         }
223                       })
224                     }
225                   }))
226                 }
227                 </div>
228               </div>
229             </div>
230           );
231         }
232         if (displayScalingGroups) {
233           scalingGroupComponent = (
234             <div className="flex nsrScalingGroupContainer">
235               <NsrScalingGroups data={scalingGroupsProps} />
236             </div>
237           );
238         }
239
240         // Virtual Links tab content
241         displayNSVirtualLinks = true;
242         nsVirtualLinksProps = cardData;
243         if (displayNSVirtualLinks) {
244           nsVirtualLinksComponent = (
245             <div className='flex nsVirtualLinksContainer'>
246               <NSVirtualLinks data={nsVirtualLinksProps} />
247             </div>
248           );
249         };
250
251         components = ParseMP.call(this, cardData["monitoring-param"], "vnfr-id");
252         break;
253     }
254     let mgmt_interface = cardData["dashboard-url"];
255     let mgmtHTML;
256     let metricsAndParams = [];
257
258
259     let nfviMetrics = null //<LpCardNfviMetrics data={cardData["nfvi-metrics"]} />;
260     metricsAndParams.push(<div className="monitoringParams" key="mp">
261                           {components.map(function(c, k) {
262                             return <div key={k} className="mpSlide">{c.title}{c.component}</div>
263                           })}
264                           </div>)
265     metricsAndParams.push((<div key="nvfi" className="nfvi-metrics">
266       { nfviMetrics }
267       <EpaParams data={cardData["epa-params"]} />
268     </div>))
269
270
271
272     if(mgmt_interface) {
273       mgmtHTML = <a href={mgmt_interface} target="_blank">Open Application Dashboard</a>;
274     }
275       if(this.props.isLoading) {
276         html = <DashboardCard className="loading" showHeader={true} title={cardData["short-name"]}><LoadingIndicator size={10} show={true} /></DashboardCard>
277       } else {
278         let glyphValue = (!this.props.recordDetailsToggleValue) ? "chevron-left" : "chevron-right";
279
280         if (this.props.type == 'nsr') {
281           tabList.push(
282             <Tab key={cardData.id}>NS Data</Tab>
283           )
284         } else if (this.props.type == 'vnfr') {
285           tabList.push(
286             <Tab key={cardData.id}>VNF Data</Tab>
287           )
288         }
289
290         tabPanels.push(
291           <TabPanel key={cardData.id + '-panel'}>
292
293               <div className="launchpadCard_title" style={{textAlign:'right'}}><span style={{float:'left'}}>MONITORING PARAMETERS</span>
294                 {mgmtHTML}
295               </div>
296               {metricsAndParams}
297               <div className="cardSectionFooter">
298               </div>
299           </TabPanel>
300         )
301
302
303         if (this.props.type == 'nsr') {
304           if (scalingGroupComponent) {
305             tabList.push(
306             <Tab key={cardData.id + '-sg'}>Scaling Groups</Tab>
307           );
308
309           tabPanels.push(
310               <TabPanel key={cardData.id + '-sg-panel'}>
311                   <div>
312                     {scalingGroupComponent}
313                   </div>
314                   <div className="cardSectionFooter">
315                   </div>
316               </TabPanel>
317             );
318           }
319           if(cardData.hasOwnProperty('vnfd-placement-group-maps')
320              || cardData.hasOwnProperty('nsd-placement-group-maps')) {
321             tabList.push(
322                <Tab key='placement_groups'>
323                 Placement
324                </Tab>
325              );
326             tabPanels.push(
327                <TabPanel key='placement_groups_panel'>
328                   <div>
329                     <PlacementGroupsInfo nsr={cardData} navRef={this.props.navRef} />
330                   </div>
331               </TabPanel>
332              );
333           }
334         }
335
336         if (configPrimitiveComponent) {
337           let primitivesTabTitle = '';
338           if (this.props.type == 'nsr') {
339             primitivesTabTitle = 'Service Primitive';
340           } else if (this.props.type == 'vnfr') {
341             primitivesTabTitle = 'Config Primitive'
342           }
343
344           tabList.push(
345             <Tab key={cardData.id + '-cp'}>{primitivesTabTitle}</Tab>
346           );
347
348           tabPanels.push(
349             <TabPanel key={cardData.id + '-cp-panel'}>
350               <div className="configPrimitives">
351                 {configPrimitiveComponent}
352               </div>
353               <div className="cardSectionFooter">
354               </div>
355             </TabPanel>
356           )
357         }
358
359         if (nsVirtualLinksComponent) {
360           let nsVirtualLinksTabTitle = 'Virtual Links';
361           tabList.push(
362               <Tab key={cardData.id + '-nsvl'}>{nsVirtualLinksTabTitle}</Tab>
363           );
364
365           tabPanels.push(
366             <TabPanel key={cardData.id + '-nsvl-panel'}>
367               <div className='nsVirtualLinks'>
368                 {nsVirtualLinksComponent}
369               </div>
370               <div className="cardSectionFooter">
371               </div>
372             </TabPanel>
373           );
374         }
375
376         if (consoleUrlsComponent) {
377           let consoleUrlsTabTitle = '';
378           consoleUrlsTabTitle = 'VDU Console Links';
379
380           tabList.push(
381             <Tab key={cardData.id + '-vducl'}>{consoleUrlsTabTitle}</Tab>
382           );
383
384           tabPanels.push(
385             <TabPanel key={cardData.id + '-vducl-panel'}>
386               <div className="consoleUrls">
387                 {consoleUrlsComponent}
388               </div>
389               <div className="cardSectionFooter">
390               </div>
391             </TabPanel>
392           )
393         }
394
395         if (displayVolumesTab) {
396
397           tabList.push(
398             <Tab key={cardData.id + '-volumes'}>Volumes</Tab>
399           );
400
401           tabPanels.push(
402             <TabPanel key={cardData.id + '-volumes-panel'}>
403               {volumesHTML}
404               <div className="cardSectionFooter">
405               </div>
406             </TabPanel>
407           )
408         }
409
410         html = (
411             <DashboardCard className="recordCard" showHeader={true} title={cardData["short-name"]}>
412               <a onClick={this.props.recordDetailsToggleFn} className={"recordViewToggle " + (this.props.recordDetailsToggleValue ? "on": null)}><span className="oi" data-glyph={glyphValue} title="Toggle Details Panel" aria-hidden="true"></span></a>
413               <Tabs onSelect={this.handleSelect}>
414                 <TabList>
415                     {tabList}
416                 </TabList>
417                 {tabPanels}
418               </Tabs>
419             </DashboardCard>
420         );
421       }
422     return html;
423   }
424 }
425 RecordCard.defaultProps = {
426   type: "default",
427   data: {},
428   isLoading: true,
429   jobData: []
430 }
431 RecordCard.contextTypes = {
432     router: React.PropTypes.object,
433     userProfile: React.PropTypes.object
434 };
435
436 export default SkyquakeComponent(RecordCard);