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