update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / launchpad / src / nsListPanel / nsListPanel.jsx
1
2 import React from 'react';
3 import { Link } from 'react-router';
4
5 import DashboardCard from 'widgets/dashboard_card/dashboard_card.jsx';
6 import LaunchpadFleetActions from'../launchpadFleetActions';
7 import LaunchpadFleetStore from '../launchpadFleetStore';
8 import UpTime from 'widgets/uptime/uptime.jsx';
9 import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
10 import ROLES from 'utils/roleConstants.js';
11 const PROJECT_ROLES = ROLES.PROJECT;
12 /*
13  * TODO: Handle when page is loading. See recordView for ref
14  */
15
16
17 /*
18  * key -  NSR property name
19  * label - Text to display for the header column label
20  * colClass - class to add for rendering this column
21  * transform: function to call to display the value for the property
22  */
23 const FIELD_KEYS = [
24     {
25         // was using 'short-name'
26         key: 'name',
27         label: 'NS Name',
28         colClass: 'nsColNsName',
29         transform: function(nsr, key) {
30             let val = nsr[key];
31             let title = '"' + val + '" Click to open the viewport dashboard.';
32             let sdnpresent = nsr['sdn-account'] ? true: false;
33             return (
34                 <Link className="nsViewportLink"
35                     to={{pathname: '/viewport', query: {id: nsr.id,
36                         sdnpresent: sdnpresent}}}
37                     title={title}>
38                     {val}
39                 </Link>
40             )
41         }
42     },
43     {
44         key: 'nsd_name',
45         label: 'nsd',
46         colClass: 'nsColNsdName',
47         transform: function(nsr, key) {
48             let val=nsr[key];
49             return (
50                 <span title={val}>{val}</span>
51             );
52         }
53     },
54     {
55         key: 'operational-status',
56         label: 'Status',
57         colClass: 'nsColStatus',
58         transform: function(nsr, key, isLoading) {
59             let val = null;
60             if(isLoading) {
61                 if (nsr['operational-status'] == 'running') {
62                     if(nsr['config-status'] == 'configuring') {
63                         val = 'Configuring'
64                     } else {
65                         val = 'Configuration Failed'
66                     }
67                 } else {
68                     val = nsr['operational-status'];
69                 }
70             } else {
71                 val = 'Active'
72             }
73             return (
74                 <span title={val} style={{'textTransform': 'capitalize'}}>{val}</span>);
75         }
76     },
77     {
78         key: 'create-time',
79         label: 'Uptime',
80         colClass: 'nsColUptime',
81         transform: function(nsr, key) {
82             let val = nsr[key];
83             return (<UpTime initialTime={val} run={true} />);
84         }
85     }
86 ];
87
88 /*
89  * Render the network service grid header row
90  */
91 class NsListHeader extends React.Component {
92
93     render() {
94         const {fieldKeys, ...props} = this.props;
95         return (
96             <div className="nsListHeaderRow">
97                 {fieldKeys.map( (field, index) =>
98                     <div className={"nsListHeaderField " + field.colClass}
99                         key={index} >
100                         {field.label}
101                     </div>
102                 )}
103                 <div className="nsListHeaderField nsColAction"></div>
104             </div>
105         );
106     }
107 }
108
109 /*
110  * Render a row for the network service
111  */
112 class NsListItem extends React.Component {
113
114     constructor(props) {
115         super(props);
116         this.state = {};
117         this.state.isLoading = this.isLoading(props)
118         this.state.failed = false;
119     }
120
121     renderFieldBody(nsr, field, isLoading) {
122         return field.transform(nsr, field.key, isLoading);
123     }
124
125     columnStyle(field) {
126         return {
127             'width': field.width
128         }
129     }
130
131     classNames(isCardOpen) {
132         return "nsListItemRow" + (isCardOpen ? " openedCard" : "");
133     }
134
135
136     openDashboard(nsr_id) {
137         window.location.href = '//' + window.location.hostname +
138             ':' + window.location.port + '/index.html' +
139             window.location.search +
140             window.location.hash + '/' + nsr_id + '/detail';
141         launchpadFleetStore.closeSocket();
142     }
143
144     componentWillReceiveProps(props) {
145         this.setState({
146             isLoading:  this.isLoading(props)
147         })
148     }
149     isLoading(props) {
150         return !((props.nsr['operational-status'] == 'running') && (props.nsr['config-status'] == 'configured'))
151     }
152     actionButton(glyphValue, title, onClick) {
153         return (
154            <div className="actionButton"  onClick={onClick}>
155             <span className="oi" data-glyph={glyphValue}
156             title={title} aria-hidden="true"></span>
157            </div>
158         );
159     }
160
161     render() {
162         let failed = this.state.failed;
163         let isLoading =  this.state.isLoading || failed;
164         const {nsr, isCardOpen, fieldKeys, ...props} = this.props;
165         const self = this;
166         return (
167             <div className={this.classNames(isCardOpen)} data-id={nsr.id}>
168                 {fieldKeys.map( (field, index) =>
169                     <div className={"nsListItemField " + field.colClass}
170                         key={index} >
171                         <div className="cellValue">
172                         {self.renderFieldBody(nsr, field, isLoading)}
173                         </div>
174                     </div>
175                 )}
176                 <div className="nsListItemField nsColAction">
177                     <div className="cellValue">
178                     {
179                         (isCardOpen)
180                             ? this.actionButton("circle-x",
181                                 "Close network service card",
182                                 function() {
183                                     LaunchpadFleetActions.closeNsrCard(nsr.id);
184                                 })
185                             : this.actionButton("arrow-circle-right",
186                                 "Open network service card",
187                                 function() {
188                                     LaunchpadFleetActions.openNsrCard(nsr.id);
189                                 })
190                     }
191                     </div>
192                 </div>
193             </div>
194         );
195     }
196 }
197
198 /*
199  * Used for development/debugging layout
200  */
201 class EmptyNsListItem extends React.Component {
202     render() {
203         const {fieldKeys, ...props} = this.props;
204         return (
205             <div className={"nsListItemRow"} >
206                 {fieldKeys.map( (field, index) =>
207                     <div className={"nsListItemField " + field.colClass}
208                         key={index} >
209                     </div>
210                 )}
211                 <div className="nsListItemField nsColAction">
212                 </div>
213             </div>
214         );
215     }
216 }
217
218 /*
219  * Used for development/debugging layout
220  */
221 class MockNsListItem extends React.Component {
222
223     simNsr() {
224         return {
225             name: 'Grue',
226             nsd_name: 'Dungeon X',
227             'operational-status': 'Hunting',
228             'create-time': 1163507750
229         };
230     }
231     render() {
232         const {fieldKeys, mockNsr, isCardOpen, ...props} = this.props;
233         let nsr = mockNsr;
234         if (!nsr) {
235             nsr = this.simNsr();
236         }
237         return (<NsListItem nsr={nsr}
238             fieldKeys={fieldKeys}
239             isCardOpen={isCardOpen}
240             />
241         );
242     }
243 }
244 MockNsListItem.defaultProps = {
245     isCardOpen: false
246 }
247
248
249 class NsList extends React.Component {
250
251     emptyRows(count) {
252         let emptyRows = [];
253         for (var i=0; i < count; i++) {
254             emptyRows.push(
255                 <EmptyNsListItem key={ "empty_"+i}
256                     fieldKeys={this.props.fieldKeys} />
257                 );
258         }
259         return emptyRows;
260     }
261
262     mockNsRows(count) {
263         let mockNsRows = [];
264         let isCardOpen = false;
265         for (var i=0; i < count; i++) {
266             isCardOpen = !isCardOpen;
267             mockNsRows.push(
268                 <MockNsListItem key={ "empty_"+i}
269                     fieldKeys={this.props.fieldKeys} isCardOpen={isCardOpen} />
270                 );
271         }
272         return mockNsRows;
273     }
274
275     render() {
276         const {nsrs, openedNsrIDs, fieldKeys, ...props} = this.props;
277         return (
278             <div className="nsList">
279                 <NsListHeader fieldKeys={fieldKeys} />
280                 <div className="nsList-body">
281                     <div className="nsList-body_content">
282                         {nsrs.map((nsr, index) =>
283                             <NsListItem key={nsr.id} nsr={nsr}
284                                 fieldKeys={fieldKeys}
285                                 isCardOpen={openedNsrIDs.includes(nsr.id)} />
286                         )}
287                         {this.mockNsRows(this.props.mockNsRows)}
288                         {this.emptyRows(this.props.emptyRows)}
289                     </div>
290                 </div>
291             </div>
292         );
293     }
294 }
295
296 NsList.defaultProps = {
297     mockNsRows: 0,
298     emptyRows: 0
299 }
300
301
302 export default class NsListPanel extends React.Component {
303
304     handleInstantiateNetworkService = () => {
305         this.context.router.push({pathname:'instantiate'});
306     }
307     handleShowHideToggle(newState) {
308         return function() {
309             LaunchpadFleetActions.setNsListPanelVisible(newState);
310         }
311     }
312     panelToolbar() {
313         let plusButton = require("style/img/launchpad-add-fleet-icon.png");
314
315         return (
316             <div className="nsListPanelToolbar">
317
318                 <div className="button"
319                     onClick={this.handleInstantiateNetworkService} >
320                     <img src={plusButton}/>
321                     <span>Instantiate Service</span>
322                 </div>
323             </div>
324         );
325     }
326
327     render() {
328         const {nsrs, openedNsrIDs, emptyRows, isVisible, ...props} = this.props;
329         const fieldKeys = FIELD_KEYS;
330         let glyphValue = (isVisible) ? "chevron-left" : "chevron-right";
331
332         let totalNSRs = nsrs && nsrs.length;
333         let runningNSRs = 0;
334         let failedNSRs = 0;
335         let scalingOutNSRs = 0;
336         let scalingInNSRs = 0;
337         let initializingNSRs = 0;
338
339         nsrs && nsrs.map((nsr) => {
340             nsr['operational-status'] == 'running' && runningNSRs++;
341             nsr['operational-status'] == 'failed' && failedNSRs++;
342             nsr['operational-status'] == 'scaling-out' && scalingOutNSRs++;
343             nsr['operational-status'] == 'scaling-in' && scalingInNSRs++;
344             (
345                 nsr['operational-status'] == 'init' ||
346                 nsr['operational-status'] == 'vl-init-phase' ||
347                 nsr['operational-status'] == 'vnf-init-phase'
348             ) && initializingNSRs++;
349         });
350
351
352         if (isVisible) {
353
354             let title = (
355                 <div>
356                     NETWORK SERVICES
357                     <div className='nsrSummary'>
358                         <span className='nsrSummaryItem'>Total: {totalNSRs}</span>
359                         <span className='nsrSummaryItem'>Running: {runningNSRs}</span>
360                         <span className='nsrSummaryItem'>Failed: {failedNSRs}</span>
361                         <span className='nsrSummaryItem'>Scaling Out: {scalingOutNSRs}</span>
362                         <span className='nsrSummaryItem'>Scaling In: {scalingInNSRs}</span>
363                         <span className='nsrSummaryItem'>Initializing: {initializingNSRs}</span>
364                     </div>
365                 </div>
366             );
367
368
369             return (
370                 <DashboardCard className="nsListPanel" showHeader={true}
371                     title={title}>
372                     {isRBACValid(this.context.userProfile, [PROJECT_ROLES.LCM_ADMIN, PROJECT_ROLES.PROJECT_ADMIN]) ? this.panelToolbar() : null}
373                     <a onClick={this.handleShowHideToggle(!isVisible)}
374                         className={"nsListPanelToggle"}>
375                         <span className="oi"
376                             data-glyph={glyphValue}
377                             title="Toggle Details Panel"
378                             aria-hidden="true"></span></a>
379                     <NsList nsrs={nsrs} openedNsrIDs={openedNsrIDs}
380                         fieldKeys={fieldKeys} emptyRows={emptyRows} />
381                 </DashboardCard>
382
383
384             );
385         } else {
386             return (
387                 <DashboardCard className="leftMinimizedNsListPanel" showHeader={true}
388                             title="|">
389                 <a onClick={this.handleShowHideToggle(!isVisible)}
390                         className={"nsListPanelToggle"}>
391                         <span className="oi"
392                             data-glyph={glyphValue}
393                             title="Toggle Details Panel"
394                             aria-hidden="true"></span></a>
395                 </DashboardCard>
396             );
397         }
398     }
399 }
400 NsListPanel.contextTypes = {
401     router: React.PropTypes.object,
402     userProfile: React.PropTypes.object
403 };
404 NsListPanel.defaultProps = {
405     isVisible: true
406 }