4 * Copyright 2016 RIFT.IO Inc
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import React, {Component} from 'react';
20 import ReactDOM from 'react-dom';
21 import SelectOption from 'widgets/form_controls/selectOption.jsx';
22 import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
23 import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
24 import TextInput from 'widgets/form_controls/textInput.jsx';
25 import './instantiateInputParams.scss';
27 export default class InstantiateInputParams extends Component {
31 nsConfigHTML = (props) => {
33 <div className="configure-nsd_section">
34 <div className="inputControls">
35 <TextInput label="Instance Name" type="text" pattern="^[a-zA-Z0-9_]*$" style={{textAlign:'left'}} onChange={props.updateName} value={props.name}/>
36 <label>Select VIM Account
37 <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} onChange={props.nsFn.updateSelectedCloudAccount} />
40 isOpenMano(props.selectedCloudAccount) ? this.dataCentersHTML(props.dataCenters[selectedCloudAccount.name], props.nsFn.updateSelectedDataCenter) : null
46 vnfCloudAccountsHTML = (props) => {
48 let dataCenters = props.dataCenters;
50 <div className="configure-nsd_section">
51 <h3 className="launchpadCard_title">NS/VNF ACCOUNT PLACEMENTS</h3>
55 nsd['constituent-vnfd'] && nsd['constituent-vnfd'].map(function(v, i) {
56 let defaultValue = false;
57 if(props.vnfdCloudAccounts && props.vnfdCloudAccounts.hasOwnProperty(v['member-vnf-index'])) {
58 defaultValue = props.vnfdCloudAccounts[v['member-vnf-index']]
61 <div className="inputControls" key={i}>
62 <h4 className="inputControls-title">VNFD: {v.name}</h4>
63 <label>Select VIM Account
64 <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} initial={true} onChange={props.vnfFn.updateSelectedCloudAccount.bind(v['member-vnf-index'])} defaultValue={defaultValue} />
67 isOpenMano(defaultValue) ? dataCentersHTML(dataCenters[defaultValue.account.name], props.vnfFn.updateSelectedDataCenter(v['member-vnf-index'])) : null
70 (props.configAgentAccounts && props.configAgentAccounts.length > 0) ?
71 <label>Select Config Agent Account
72 <SelectOption options={props.configAgentAccounts && props.configAgentAccounts.map(function(c) {
77 })} initial={true} onChange={props.vnfFn.updateSelectedConfigAgent(v['member-vnf-index'])} defaultValue={false} />
87 inputParametersHTML = (props) => {
88 let inputParameters = props.inputParameters;
89 return inputParameters && inputParameters.map(function(input, i) {
91 <div className="configure-nsd_section" key={i}>
92 <h3 className="launchpadCard_title">Input Parameters</h3>
93 <div className="inputControls">
94 <TextInput label={ input.label || input.xpath } type="text" onChange={props.updateInputParam.bind(self, i)} />
100 nsPlacementGroupsHTML = (props) => {
101 let nsPlacementGroups = props.nsPlacementGroups;
102 let displayPlacementGroups = props.displayPlacementGroups;
103 if (nsPlacementGroups && nsPlacementGroups.length > 0 && displayPlacementGroups) {
105 <div className="configure-nsd_section">
106 <h3 className="launchpadCard_title">NS Placement Groups</h3>
108 nsPlacementGroups.map(function(input, i) {
110 <div key={i} className="configure-nsd_section-info">
111 <div className="placementGroup_description">
112 <div className="placementGroup_description-name">
113 <strong>{input.name}</strong> contains: {
114 input['member-vnfd'].map((m,i) => {
123 <div><em>{input.requirement}</em></div>
124 <div><strong>Strategy:</strong> {input.strategy}</div>
127 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span> </span>
128 <div style={{display:'none'}}>
129 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
130 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
134 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
135 <div style={{display:'none'}}>
136 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'server-group')} />
137 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
140 <div className="host-aggregate">
142 <span> Host Aggregates <span onClick={props.nsFn.addHostAggregate.bind(self, i)} className="addInput" ><img src={imgAdd} />Add</span></span>
144 input['host-aggregate'].length > 0 ?
145 input['host-aggregate'].map((h,j) => {
146 let key = h.key || '';
147 let value = h.value || '';
150 <div className="input_group" key={j}>
151 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
152 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
153 <span onClick={props.nsFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
168 vnfPlacementGroupsHTML = (props) => {
169 let vnfPlacementGroups = props.vnfPlacementGroups;
170 let displayPlacementGroups = props.displayPlacementGroups;
171 if (vnfPlacementGroups && vnfPlacementGroups.length > 0 && displayPlacementGroups) {
172 return vnfPlacementGroups.map(function(input, i) {
174 <div className="configure-nsd_section" key={i}>
175 <h3 className="launchpadCard_title">{input['vnf-name']} VNF Placement Group</h3>
176 <div className="configure-nsd_section-info">
177 <div className="placementGroup_description">
178 <div className="placementGroup_description-name">
179 <strong>{input.name}</strong> contains: {
180 input['member-vdus'].map((m,i) => {
181 let s = m['member-vdu-ref'];
183 s = ', ' + m['member-vdu-ref']
189 <div><em>{input.requirement}</em></div>
190 <div><strong>Strategy</strong>: {input.strategy}</div>
193 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
194 <div style={{display:'none'}}>
195 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
196 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
200 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
201 <div style={{display:'none'}}>
202 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'server-group')} />
203 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
206 <div className="host-aggregate">
208 <span> Host Aggregates <span onClick={props.vnfFn.addHostAggregate.bind(self, i)} className="addInput"><img src={imgAdd} />Add</span></span>
210 input['host-aggregate'].length > 0 ?
211 input['host-aggregate'].map((h,j) => {
212 let key = h.key || '';
213 let value = h.value || '';
216 <div className="input_group" key={j}>
217 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
218 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
219 <span onClick={props.vnfFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
233 vldsHTML = (props) => {
235 let ipProfileList = props.ipProfileList;
236 let vlds = props.vlds;
238 <div className="configure-nsd_section">
239 <h3 className="launchpadCard_title">VLDs</h3>
240 {vlds && vlds.map(function(v, i) {
241 let currentType = v.type;
242 let isVIM = (currentType == 'vim-network-name');
243 let isUnknown = (currentType == 'unknown') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
245 <div key={self.props.nsd.id + '-' + i} className="inputControls">
246 <h4 className="inputControls-title">VLD: {v['short-name'] ? v['short-name'] : v['name']}</h4>
247 <div className="inputControls-radioGroup">
248 <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
249 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
252 <label className="inputControls-radio">
253 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isVIM && !isUnknown} value='vim-network-name' />
256 <label className="inputControls-radio">
257 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='unknown' />
262 isUnknown ? null : isVIM ?
263 <TextInput label="Network Name" onChange={self.props.vldFn.updateValue(i, currentType)} value={v[currentType]} /> :
266 label="IP PROFILE NAME"
267 options={ipProfileList && ipProfileList.map(function(ip) {
274 v['ip-profile-ref'] ? false : true
276 defaultValue={v['ip-profile-ref']}
277 onChange={self.props.vldFn.updateValue(i, currentType)}>
288 ipProfilesHTML = (props) => {
289 let ipProfileList = props.ipProfileList;
290 return ipProfileList &&
292 <div className="configure-nsd_section">
293 <h3 className="launchpadCard_title">IP Profiles</h3>
296 ipProfileList && ipProfileList.map(function(ip, j) {
297 let ipl = ip['ip-profile-params'];
299 <div className="inputControls" key={j}>
300 <div className="inputControls-title" >
303 <div className="inputControls-radioGroup">
304 <label className="inputControls-radio">
305 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv4'} value='ipv4' />
308 <label className="inputControls-radio">
309 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv6'} value='ipv6' />
312 <label className="inputControls-radio">
313 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'unknown'} value='unknown' />
318 label="subnet address"
319 onChange={props.ipProfileFn.updateProfile(j, 'subnet-address')}
320 value={ipl['subnet-address']}
323 label="gateway address"
324 onChange={props.ipProfileFn.updateProfile(j, 'gateway-address')}
325 value={ipl['gateway-address']}
328 label="security group"
329 onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
330 value={ipl['security-group']}
333 <div style={{display:'flex'}}>
334 DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
337 ipl['dns-server'] && ipl['dns-server'].map(function(dns, k) {
339 <div key={k} style={{display:'flex'}}>
341 onChange={props.ipProfileFn.updateProfile(j,k)}
342 value={ipl['dns-server'][k]}
344 <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
345 <img src={imgRemove} />Remove</span>
351 <div className="inputControls-radioGroup">
352 <label className="inputControls-radio">
355 name={'ip-profile-dhcp' + j }
356 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
357 checked={ipl.hasOwnProperty('dhcp-params') && ipl['dhcp-params'].enabled}
361 <label className="inputControls-radio">
363 name={'ip-profile-dhcp' + j }
364 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
365 checked={!ipl.hasOwnProperty('dhcp-params') || !ipl['dhcp-params'].enabled}
371 (ipl['dhcp-params'] && ipl['dhcp-params'].enabled) ? dhcpHTML(props, ipl, j) : null
378 function dhcpHTML(props, ipl, j){
381 label="DCHP Start Address"
382 onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
383 value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
387 onChange={props.ipProfileFn.updateDHCP(j, 'count')}
388 value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
394 sshKeysHTML = (props) => {
395 let sshKeysList = props.sshKeysList;
396 let sshKeysRef = props.sshKeysRef;
397 if(sshKeysList && sshKeysList.length > 0) {
399 <div className="configure-nsd_section">
400 <h3 className="launchpadCard_title">SSH Authorized Keys</h3>
403 sshKeysRef.map(function(ref, i) {
405 <div key={i} className="inputControls inputControls-sshkeys">
410 options={sshKeysList && sshKeysList.map(function(k) {
416 ref="keyPairSelection"
418 defaultValue={sshKeysList[0].name}
419 onChange={self.props.updateSshKeyRef(i)}>
424 <span onClick={self.props.updateSshKeyRef(i, true)} className="removeInput">
425 <img src={imgRemove} />
433 <div className="inputControls inputControls-sshkeys ">
434 <label style={{display: 'flex', 'flexDirection': 'row'}}>
436 <span onClick={self.props.updateSshKeyRef().bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
446 usersHTML = (props) => {
447 let usersFn = props.usersFn;
448 let usersList = props.usersList && props.usersList.map(function(u, i) {
450 <div className="input_group input_group-users" key={i}>
451 <div className="inputControls">
452 <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
453 <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
454 <TextInput onChange={usersFn.update(i, 'gecos')} label="REAL NAME" value={i.gecos} />
455 <TextInput onChange={usersFn.update(i, 'passwd')} type="password" label="PASSWORD" value={i.passwd} />
461 <div className="configure-nsd_section">
462 <h3 className="launchpadCard_title">USERS</h3>
464 <div className="inputControls inputControls-sshkeys ">
465 <span onClick={usersFn.add} className="addInput">
466 <img src={imgAdd} onClick={usersFn.add} />
475 const props = this.props;
480 <div className="instantiateInputParams">
483 this.nsConfigHTML(props)
487 this.vnfCloudAccountsHTML(props)
491 this.inputParametersHTML(props)
495 this.nsPlacementGroupsHTML(props)
498 //VNF PLACEMENTGROUPS
499 this.vnfPlacementGroupsHTML(props)
506 //IP PROFILE CONFIGURATION
507 this.ipProfilesHTML(props)
510 //SSH KEY ASSIGNMENTS
511 this.sshKeysHTML(props)
515 this.usersHTML(props)
522 function showInput(e){
523 let target = e.target;
524 if(target.parentElement.classList.contains("addInput")) {
525 target = target.parentElement;
527 target.style.display = 'none';
528 target.parentElement.nextElementSibling.style.display = 'flex';
529 // e.target.parentElement.nextElementSibling.children[1].style.display = 'initial';
531 function hideInput(e){
532 let target = e.target;
533 if(target.parentElement.classList.contains("removeInput")) {
534 target = target.parentElement;
536 target.parentElement.style.display = 'none';
537 target.parentElement.previousElementSibling.children[1].style.display = 'inline';
538 target.previousSibling.value = '';
541 function removeDNS(){}
542 function constructCloudAccountOptions(cloudAccounts){
543 let CloudAccountOptions = cloudAccounts && cloudAccounts.map(function(ca, index) {
549 return CloudAccountOptions;
551 function dataCentersHTML(state, onChange) {
552 //Build DataCenter options
553 //Relook at this, why is it an object?
554 let dataCenters = state.dataCenters || [];
555 let DataCenterOptions = {};
557 for (let d in dataCenters) {
558 DataCenterOptions[d] = dataCenters[d].map(function(dc, index) {
566 if (dataCenters.length > 0) {
568 <label>Select Data Center
569 <SelectOption options={DataCenterOptions} onChange={onChange} />
574 function isOpenMano(account) {
577 if (a.constructor.name == 'String') {
580 if(a.hasOwnProperty('account')) {
583 return a['account-type'] == 'openmano';
588 function updateNewSshKeyRefSelection(e) {
590 newRefSelection: e.target.value
593 function resetRef() {
595 newRefSelection: null
598 InstantiateInputParams.defaultProps = {