Просмотр исходного кода

- Fixes network dropdown on wizard options
- Fixes various layout issues
- Adds azure property special parsing

George Vrancianu 8 лет назад
Родитель
Сommit
64fcb6f7fb

+ 14 - 3
src/actions/ConnectionsActions/ConnectionsActions.js

@@ -70,6 +70,18 @@ ConnectionsActions.loadProviders.listen(() => {
     .catch(ConnectionsActions.loadProviders.failed);
 })
 
+ConnectionsActions.loadNetworks.listen((endpoint) => {
+  let projectId = Reflux.GlobalState.userStore.currentUser.project.id
+  let targetEnv = btoa(JSON.stringify(Reflux.GlobalState.wizardStore.destination_environment))
+  let url = `${servicesUrl.coriolis}/${projectId}/endpoints/${endpoint.id}/networks?env=${targetEnv}`
+
+  Api.sendAjaxRequest({
+    url: url,
+    method: "GET"
+  }).then(ConnectionsActions.loadNetworks.completed, ConnectionsActions.loadNetworks.failed)
+    .catch(ConnectionsActions.loadNetworks.failed);
+})
+
 ConnectionsActions.newEndpoint.listen((data, callback = null) => {
   if (useSecret) {
     let barbicanPayload = {
@@ -165,12 +177,11 @@ ConnectionsActions.saveEditEndpoint.listen((connection, data, callback = null) =
     method: "PUT",
     data: payload
   }).then((response) => {
-    ConnectionsActions.saveEditEndpoint.success(response)
-    if (callback) {
+    if (typeof callback === "function") {
       callback()
     }
+    ConnectionsActions.saveEditEndpoint.success(response)
   }, ConnectionsActions.saveEditEndpoint.failed)
-    .catch(ConnectionsActions.saveEditEndpoint.failed);
 })
 
 ConnectionsActions.validateConnection.listen((endpoint, callback) => {

+ 98 - 74
src/components/AddCloudConnection/AddCloudConnection.js

@@ -46,16 +46,15 @@ class AddCloudConnection extends Reflux.Component {
     this.store = ConnectionsStore
 
     this.state = {
-      type: props.type,
-      connection: props.connection,
-      connectionName: "",
-      description: null,
-      currentCloud: this.props.cloud,
-      currentCloudData: null,
-      validateEndpoint: false,
-      isConnecting: false,
-      requiredFields: [],
-      cloudFormsSubmitted: false
+      type: props.type, // type of operation: new/edit
+      connection: props.connection, // connection object (on edit)
+      connectionName: "", // connection name field
+      description: null, // connection description field
+      currentCloud: this.props.cloud, // chosen cloud - if adding a new endpoint
+      currentCloudData: null, // endpoint field data
+      validateEndpoint: false, // holds the endpoint object when validation
+      requiredFields: [], // array that holds all the endpoint required fields - used for field validation
+      cloudFormsSubmitted: false // flag that indicates if the form has been submitte - used for field validation
     }
   }
 
@@ -86,14 +85,25 @@ class AddCloudConnection extends Reflux.Component {
     }
   }
 
+  /**
+   * Handles change `name` property
+   * @param e
+   */
   handleChangeName(e) {
     this.setState({ connectionName: e.target.value })
   }
 
+  /**
+   * Handles change `description` property
+   * @param e
+   */
   handleChangeDescription(e) {
     this.setState({ description: e.target.value })
   }
 
+  /**
+   * Function called upon saving an endpoint - handles both new and edit operations
+   */
   handleSave() {
     let valid = true
 
@@ -115,6 +125,7 @@ class AddCloudConnection extends Reflux.Component {
           credentials[key] = credentials[key].value
         }
       }
+      // If endpoint is new
       if (this.state.type == "new") {
         ConnectionsActions.newEndpoint({
           name: this.state.connectionName,
@@ -129,22 +140,31 @@ class AddCloudConnection extends Reflux.Component {
           })
         })
         this.props.addHandle(this.state.connectionName);
-      } else {
+      } else { // If editing an endpoint
         ConnectionsActions.editEndpoint(this.state.connection, {
           name: this.state.connectionName,
           description: this.state.description,
           connection_info: credentials
-        }, () => {
+        }, (response) => {
+          console.log(response)
+          this.setState({
+            validateEndpoint: response.data.endpoint,
+            type: "edit",
+            connection: response.data.endpoint
+          })
           this.props.updateHandle({
             name: this.state.connectionName,
             description: this.state.description
           })
         })
-        this.props.closeHandle()
       }
     }
   }
 
+  /**
+   * Handler to choose the cloud which the endpoint will be assigned to
+   * @param cloud
+   */
   chooseCloud(cloud) {
     let currentCloudData = {}
     if (this.state.currentCloudData !== null) {
@@ -172,10 +192,16 @@ class AddCloudConnection extends Reflux.Component {
     }, this.setDefaultValues)
   }
 
+  /**
+   * Function that goes back from endpoint validation to edit mode
+   */
   backToEdit() {
     this.setState({ validateEndpoint: null })
   }
 
+  /**
+   * Handles back operation when adding a new endpoint and want to switch cloud. Resets all previous cloud data.
+   */
   handleBack() {
     this.setState({
       currentCloudData: null,
@@ -186,6 +212,9 @@ class AddCloudConnection extends Reflux.Component {
     })
   }
 
+  /**
+   * Sets default values for cloud fields
+   */
   setDefaultValues() {
     this.state.currentCloud.endpoint.fields.forEach(field => {
       let currentCloudData = this.state.currentCloudData
@@ -218,6 +247,11 @@ class AddCloudConnection extends Reflux.Component {
     }, this)
   }
 
+  /**
+   * Checks wether the field is valid. Only goes through validation if field is required
+   * @param field
+   * @returns {boolean}
+   */
   isValid(field) {
     if (field.required && this.state.cloudFormsSubmitted) {
       if (this.state.currentCloudData[field.name].length == 0) {
@@ -230,10 +264,32 @@ class AddCloudConnection extends Reflux.Component {
     }
   }
 
+  /**
+   * Handles cancel edit/add endpoint
+   */
   handleCancel() {
     this.props.closeHandle();
   }
 
+  /**
+   * Handler to change the endpoint field
+   * @param e
+   * @param field
+   */
+  handleCloudFieldChange(e, field) {
+    let currentCloudData = this.state.currentCloudData
+    if (field.type == 'dropdown') {
+      currentCloudData[field.name] = e
+    } else {
+      currentCloudData[field.name] = e.target.value
+    }
+    this.setState({ currentCloudData: currentCloudData })
+  }
+
+  /**
+   * Renders the cloud list
+   * @returns {XML}
+   */
   renderCloudList() {
     let clouds = this.state.allClouds.map((cloud, index) => {
       let colorType = ""
@@ -263,6 +319,11 @@ class AddCloudConnection extends Reflux.Component {
     )
   }
 
+  /**
+   * Renders individual cloud fields
+   * @param field
+   * @returns {*}
+   */
   renderField(field) {
     let returnValue
     switch (field.type) {
@@ -337,86 +398,49 @@ class AddCloudConnection extends Reflux.Component {
     return returnValue
   }
 
-  handleCloudFieldChange(e, field) {
-    let currentCloudData = this.state.currentCloudData
-    if (field.type == 'dropdown') {
-      currentCloudData[field.name] = e
-    } else {
-      currentCloudData[field.name] = e.target.value
-    }
-    this.setState({ currentCloudData: currentCloudData })
-  }
-
+  /**
+   * Renders the new/edit endpoint form
+   * @param cloud
+   * @returns {XML}
+   */
   renderCloudFields(cloud) {
     if (this.state.currentCloudData == null) {
       this.setState({ currentCloudData: {} })
     }
-    if (!this.state.isConnecting) {
-      let fields = cloud.endpoint.fields.map(field => this.renderField(field), this)
-      return (
-        <div className={s.container}>
-          <div className={s.cloudImage}>
-            <div className={" icon large-cloud " + this.state.currentCloud.name}></div>
-          </div>
-          <div className={"form-group " + (this.state.cloudFormsSubmitted &&
-            this.state.connectionName.trim().length == 0 ? s.error : "")}
-          >
-            <input
-              type="text"
-              placeholder="Endpoint Name *"
-              onChange={(e) => this.handleChangeName(e)}
-              value={this.state.connectionName}
-            />
-          </div>
-          <div className="form-group">
-            <textarea
-              placeholder="Endpoint Description"
-              onChange={(e) => this.handleChangeDescription(e)}
-              value={this.state.description}
-            ></textarea>
-          </div>
-          <div className={s.cloudFields + (cloud.endpoint.fields.length > 6 ? " " + s.larger : "")}>
-            {fields}
-          </div>
-          <div className={s.buttons}>
-            {this.state.type == "new" ? (
-              <button className={s.leftBtn + " gray"} onClick={(e) => this.handleBack(e)}>Back</button>
-            ) : (
-              <button className={s.leftBtn + " gray"} onClick={(e) => this.handleCancel(e)}>Cancel</button>
-            )}
-            <button className={s.rightBtn} onClick={(e) => this.handleSave(e)}>Save</button>
-          </div>
-        </div>
-      )
-    } else {
-      return (
-        <div className={s.connecting}>
-          <LoadingIcon />
-          <div className={s.text}>Connecting ...</div>
-        </div>)
-    }
-  }
+    let fields = cloud.endpoint.fields.map(field => this.renderField(field), this)
 
-  renderSaveConnection() {
     return (
       <div className={s.container}>
         <div className={s.cloudImage}>
           <div className={" icon large-cloud " + this.state.currentCloud.name}></div>
         </div>
-        <div className="form-group">
+        <div className={"form-group " + (this.state.cloudFormsSubmitted &&
+          this.state.connectionName.trim().length == 0 ? s.error : "")}
+        >
           <input
             type="text"
-            placeholder="Connection name"
+            placeholder="Endpoint Name *"
             onChange={(e) => this.handleChangeName(e)}
             value={this.state.connectionName}
           />
         </div>
         <div className="form-group">
-          <textarea onChange={(e) => this.handleChangeDescription(e)} value={this.state.description}></textarea>
+          <textarea
+            placeholder="Endpoint Description"
+            onChange={(e) => this.handleChangeDescription(e)}
+            value={this.state.description}
+          ></textarea>
+        </div>
+        <div className={s.cloudFields + (cloud.endpoint.fields.length > 6 ? " " + s.larger : "")}>
+          {fields}
         </div>
         <div className={s.buttons}>
-          <button className={s.leftBtn + " gray"} onClick={(e) => this.handleBack(e)}>Back</button>
-          <button className={s.rightBtn} onClick={(e) => this.handleSave(e)}>Add</button>
+          {this.state.type == "new" ? (
+            <button className={s.leftBtn + " gray"} onClick={(e) => this.handleBack(e)}>Back</button>
+          ) : (
+            <button className={s.leftBtn + " gray"} onClick={(e) => this.handleCancel(e)}>Cancel</button>
+          )}
+          <button className={s.rightBtn} onClick={(e) => this.handleSave(e)}>Save</button>
         </div>
       </div>
     )

+ 1 - 1
src/components/CloudConnectionAuth/CloudConnectionAuth.js

@@ -18,7 +18,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React, { Component, PropTypes } from 'react';
 import withStyles from 'isomorphic-style-loader/lib/withStyles';
 import s from './CloudConnectionAuth.scss';
-import { defaultLabels } from '../../config'
+import { defaultLabels } from '../../constants/CloudLabels';
 import LoadingIcon from "../LoadingIcon/LoadingIcon";
 
 

+ 1 - 1
src/components/CloudConnectionDetail/CloudConnectionDetail.js

@@ -20,7 +20,7 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles';
 import s from './CloudConnectionDetail.scss';
 import Moment from 'react-moment';
 import LoadingIcon from '../LoadingIcon';
-import { defaultLabels } from '../../config';
+import { defaultLabels } from '../../constants/CloudLabels';
 import Helper from '../Helper';
 
 const title = 'connection details';

+ 6 - 0
src/components/ValidateEndpoint/ValidateEndpoint.scss

@@ -46,6 +46,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
         float: right;
       }
     }
+    &:after {
+      display: block;
+      content: " ";
+      clear: both;
+      height: 0;
+    }
   }
   .hidden {
     opacity: 0;

+ 27 - 23
src/components/WizardNetworks/WizardNetworks.js

@@ -39,7 +39,7 @@ class WizardNetworks extends Component {
   constructor(props) {
     super(props)
 
-    this.networkOptions = [] // [{ label: "Create new", value: null }]
+    this.networkOptions = null // [{ label: "Create new", value: null }]
     ConnectionsActions.loadNetworks(this.props.data.targetCloud.credential)
 
     props.data.selectedInstances.forEach((vm) => {
@@ -132,30 +132,34 @@ class WizardNetworks extends Component {
   render() {
     if (this.state.networks != null) {
       let networks = this.state.networks.map((network, index) => {
-        if (network.selected || true) {
-          return (
-            <div className="item" key={"networks_" + index}>
-              <div className="cell cell-icon">
-                <div className="icon network"></div>
-                <span className="details">
-                  {network.network_name}
-                </span>
-              </div>
-              <div className="cell">
-                <div className="arrow"></div>
-              </div>
-              <div className="cell">
-                <Dropdown
-                  options={this.networkOptions}
-                  onChange={(e) => this.handleChangeNetwork(e, network)}
-                  value={network.migrateNetwork}
-                />
-              </div>
-            </div>
-          )
+        let networkDropdown
+        if (this.networkOptions == null) {
+          networkDropdown = "Searching for networks ..."
+        } else if (this.networkOptions.length) {
+          networkDropdown = (<Dropdown
+            options={this.networkOptions}
+            onChange={(e) => this.handleChangeNetwork(e, network)}
+            value={network.migrateNetwork}
+          />)
         } else {
-          return null
+          networkDropdown = "Could not find networks"
         }
+        return (
+          <div className="item" key={"networks_" + index}>
+            <div className="cell cell-icon">
+              <div className="icon network"></div>
+              <span className="details">
+                {network.network_name}
+              </span>
+            </div>
+            <div className="cell">
+              <div className="arrow"></div>
+            </div>
+            <div className="cell">
+              {networkDropdown}
+            </div>
+          </div>
+        )
       }, this)
 
       return (

+ 2 - 1
src/components/WizardOptions/WizardOptions.js

@@ -86,7 +86,8 @@ class WizardOptions extends Reflux.Component {
   }
 
   isValid(field) {
-    if (field.required && this.state.formSubmitted && field.name != "network_map") {
+    if (field.required && this.state.formSubmitted && field.name != "network_map"
+      && field.name != "destination_network") {
       if (!this.state.destination_environment[field.name]) {
         return false
       } else {

+ 1 - 1
src/components/WizardSummary/WizardSummary.js

@@ -20,7 +20,7 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles';
 import s from './WizardSummary.scss';
 import moment from 'moment';
 import TextTruncate from 'react-text-truncate';
-import { defaultLabels } from '../../config';
+import { defaultLabels } from '../../constants/CloudLabels';
 
 
 const title = 'Summary';

+ 1 - 27
src/config.sample.js

@@ -126,30 +126,4 @@ export const auth = {
     key: process.env.TWITTER_CONSUMER_KEY || 'Ie20AZvLJI2lQD5Dsgxgjauns',
     secret: process.env.TWITTER_CONSUMER_SECRET || 'KTZ6cxoKnEakQCeSpZlaUCJWGAlTEBJj0y2EMkUBujA7zWSvaQ',
   },
-};
-
-export const defaultLabels = {
-  username: "Username",
-  password: "Password",
-  host: "Host",
-  port: "Port",
-  allow_untrusted: "Allow untrusted",
-  identity_api_version: "Identity Version",
-  auth_url: "Auth URL",
-  user_domain_name: "User Domain Name",
-  project_name: "Project Name",
-  project_domain_name: "Project Domain Name",
-  flavor_name: "Flavor Name",
-  hypervisor_type: "Hypervisor Type",
-  container_format: "Container Format",
-  disk_format: "Disk Format",
-  glance_upload: "Glance Upload",
-  keypair_name: "Keypair name",
-  fip_pool_name: "Floating IP Pool",
-  migr_fip_pool_name: "Migration Floating IP Pool",
-  migr_flavor_name: "Migration Flavor Name",
-  migr_image_name: "Migration Image Name",
-  migr_image_name_map: "Migration Image Name Map",
-  delete_disks_on_vm_termination: "Delete disks on VM termination",
-  set_dhcp: "Set DHCP",
-}
+};

+ 46 - 0
src/constants/CloudLabels.js

@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2017  Cloudbase Solutions SRL
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+export const defaultLabels = {
+  username: "Username",
+  password: "Password",
+  host: "Host",
+  port: "Port",
+  allow_untrusted: "Allow untrusted",
+  identity_api_version: "Identity Version",
+  auth_url: "Auth URL",
+  user_domain_name: "User Domain Name",
+  project_name: "Project Name",
+  project_domain_name: "Project Domain Name",
+  flavor_name: "Flavor Name",
+  hypervisor_type: "Hypervisor Type",
+  container_format: "Container Format",
+  disk_format: "Disk Format",
+  glance_upload: "Glance Upload",
+  keypair_name: "Keypair name",
+  fip_pool_name: "Floating IP Pool",
+  migr_fip_pool_name: "Migration Floating IP Pool",
+  migr_flavor_name: "Migration Flavor Name",
+  migr_image_name: "Migration Image Name",
+  migr_image_name_map: "Migration Image Name Map",
+  delete_disks_on_vm_termination: "Delete disks on VM termination",
+  set_dhcp: "Set DHCP",
+  vm_size: "Vm size",
+  location: "Location",
+  resource_group: "Resource Group",
+  worker_size: "Worker Size"
+}

+ 110 - 60
src/stores/ConnectionsStore/ConnectionsStore.js

@@ -23,7 +23,7 @@ import Reflux from 'reflux';
 import ConnectionsActions from '../../actions/ConnectionsActions';
 import WizardActions from '../../actions/WizardActions';
 import MigrationActions from '../../actions/MigrationActions';
-import {defaultLabels} from '../../config'
+import { defaultLabels } from '../../constants/CloudLabels';
 import Api from '../../components/ApiCaller'
 import {servicesUrl, providerType} from '../../config';
 
@@ -123,16 +123,18 @@ class ConnectionsStore extends Reflux.Store
       let provider = this.state.allClouds.filter(cloud => cloud.name == providerName)[0]
       if (response.data.schemas.connection_info_schema) {
         provider[type] = {}
-        provider[type].fields = ConnectionsStore.processCloud(response.data.schemas.connection_info_schema.oneOf[0])
+        provider[type].fields = ConnectionsStore.processCloud(
+          response.data.schemas.connection_info_schema, providerName)
       }
 
       if (response.data.schemas.destination_environment_schema) {
         provider[type] = {}
-        provider[type].fields = ConnectionsStore.processCloud(response.data.schemas.destination_environment_schema.oneOf[0])
+        provider[type].fields = ConnectionsStore.processCloud(
+          response.data.schemas.destination_environment_schema.oneOf[0], providerName, 'destination_env')
       }
       ConnectionsActions.updateProvider(provider)
-    }, ConnectionsActions.loadProviders.failed)
-      .catch(ConnectionsActions.loadProviders.failed);
+    }, ConnectionsActions.updateProvider.failed)
+      .catch(ConnectionsActions.updateProvider.failed);
   }
 
   onUpdateProvider(provider) {
@@ -288,69 +290,117 @@ class ConnectionsStore extends Reflux.Store
     ConnectionsActions.assignConnectionProvider()
   }
 
-  static processCloud(cloudData) {
-    let fields = []
-    let sortedFields = [{}, {}]
-    for (var propName in cloudData.properties) {
-      let field = {
-        name: propName,
-        label: defaultLabels[propName] ? defaultLabels[propName] : propName
+  static processCloud(cloudData, providerName = null, type = 'connection') {
+    if (providerName != "azure" && providerName != null) {
+      cloudData = cloudData.oneOf[0]
+    }
+
+    if (providerName == "azure" && type == "connection") {
+      let subscriptionId = {
+        subscription_id: cloudData.properties.subscription_id
+      }
+      let userCredentialFields = {
+        properties: { subscription_id: cloudData.properties.subscription_id },
+        required: cloudData.properties.user_credentials.required
       }
 
-      if (cloudData.properties[propName].default) {
-        field.default = cloudData.properties[propName].default
+      for (var i in cloudData.properties.user_credentials.properties) {
+        userCredentialFields.properties[i] = cloudData.properties.user_credentials.properties[i]
       }
-      switch (cloudData.properties[propName].type) {
-        case "boolean":
-          field.type = "dropdown"
-          field.options = [
-            {label: field.label + ": Yes", value: "true", default: cloudData.properties[propName].default == "true"},
-            {label: field.label + ": No", value: "false", default: cloudData.properties[propName].default == "false"}
-          ]
-
-          break
-
-        case "string":
-          field.type = "text"
-          break
-
-        case "integer":
-          if (cloudData.properties[propName].minimum && cloudData.properties[propName].maximum) {
-            field.type = "dropdown"
-            field.options = []
-            for (let i = cloudData.properties[propName].minimum; i<= cloudData.properties[propName].maximum; i++) {
-              field.options.push({
-                label: field.label + ": " + i,
-                value: i,
-                default: cloudData.properties[propName].default === i},
-              )
-            }
-          } else {
-            field.type = "text"
+
+      let servicePrincipalCredentialFields = {
+        properties: { subscription_id: cloudData.properties.subscription_id },
+        required: cloudData.properties.service_principal_credentials.required
+      }
+      for (var i in cloudData.properties.service_principal_credentials.properties) {
+        servicePrincipalCredentialFields.properties[i] = cloudData.properties.service_principal_credentials.properties[i]
+      }
+
+      let newCloudData = {
+        type: "switch-radio",
+        name: "login_type",
+        options: [
+          {
+            label: "User Credentials",
+            value: "user_credentials",
+            fields: this.processCloud(userCredentialFields)
+          },
+          {
+            label: "Service Principal Credentials",
+            value: "service_principal_credentials",
+            fields: this.processCloud(servicePrincipalCredentialFields)
           }
-          break
+        ]
       }
 
-      if (field.name == 'username') {
-        field.required = true
-        sortedFields[0] = field
-      } else if (field.name == 'password') {
-        field.type = "password"
-        field.required = true
-        sortedFields[1] = field
-      } else if (cloudData.required.indexOf(field.name) > -1) {
-        field.required = true
-        sortedFields.push(field)
-      } else {
-        fields.push(field)
+      return [newCloudData]
+    } else {
+      let fields = []
+      let sortedFields = [{}, {}]
+      for (var propName in cloudData.properties) {
+        let field = {
+          name: propName,
+          label: defaultLabels[propName] ? defaultLabels[propName] : propName
+        }
+
+        if (cloudData.properties[propName].default) {
+          field.default = cloudData.properties[propName].default
+        }
+        switch (cloudData.properties[propName].type) {
+          case "boolean":
+            field.type = "dropdown"
+            field.options = [
+              {label: field.label + ": Yes", value: "true", default: cloudData.properties[propName].default == "true"},
+              {label: field.label + ": No", value: "false", default: cloudData.properties[propName].default == "false"}
+            ]
+
+            break
+
+          case "string":
+            field.type = "text"
+            break
+
+          case "integer":
+            if (cloudData.properties[propName].minimum && cloudData.properties[propName].maximum) {
+              field.type = "dropdown"
+              field.options = []
+              for (let i = cloudData.properties[propName].minimum; i <= cloudData.properties[propName].maximum; i++) {
+                field.options.push({
+                    label: field.label + ": " + i,
+                    value: i,
+                    default: cloudData.properties[propName].default === i
+                  },
+                )
+              }
+            } else {
+              field.type = "text"
+            }
+            break
+        }
+
+        if (field.name == 'username') {
+          field.required = true
+          sortedFields[0] = field
+        } else if (field.name == 'password') {
+          field.type = "password"
+          field.required = true
+          sortedFields[1] = field
+        } else if (cloudData.required.indexOf(field.name) > -1) {
+          field.required = true
+          sortedFields.push(field)
+        } else {
+          fields.push(field)
+        }
       }
+      //in case we don't have username and password
+      if (Object.keys(sortedFields[0]).length === 0 && Object.keys(sortedFields[0]).length === 0) {
+        sortedFields.shift()
+        sortedFields.shift()
+      }
+      console.log("sortedFields.concat(fields)", sortedFields.concat(fields))
+
+      return sortedFields.concat(fields)
     }
-    //in case we don't have username and password
-    if (Object.keys(sortedFields[0]).length === 0 && Object.keys(sortedFields[0]).length === 0) {
-      sortedFields.shift()
-      sortedFields.shift()
-    }
-    return sortedFields.concat(fields)
   }
 }
 

+ 5 - 12
src/stores/WizardStore/WizardStore.js

@@ -22,7 +22,7 @@ import ConnectionsActions from '../../actions/ConnectionsActions';
 import { servicesUrl, itemsPerPage } from '../../config';
 import Api from '../../components/ApiCaller';
 
-class UsersStore extends Reflux.Store
+class WizardStore extends Reflux.Store
 {
   blankState = {
     sourceCloud: null,
@@ -133,19 +133,10 @@ class UsersStore extends Reflux.Store
     this.setState({ selectedInstances: selectedInstances })
   }
 
-  onLoadNetworks(endpoint) {
+  onLoadNetworks() {
     this.setState({
       targetNetworks: null
     })
-    let projectId = Reflux.GlobalState.userStore.currentUser.project.id
-    let targetEnv = btoa(JSON.stringify(this.state.destination_environment))
-    let url = `${servicesUrl.coriolis}/${projectId}/endpoints/${endpoint.id}/networks?env=${targetEnv}`
-
-    Api.sendAjaxRequest({
-      url: url,
-      method: "GET"
-    }).then(ConnectionsActions.loadNetworks.completed, ConnectionsActions.loadNetworks.failed)
-      .catch(ConnectionsActions.loadNetworks.failed);
   }
 
   onLoadNetworksCompleted(response) {
@@ -167,4 +158,6 @@ class UsersStore extends Reflux.Store
 
 }
 
-export default UsersStore;
+WizardStore.id = "wizardStore"
+
+export default WizardStore;