瀏覽代碼

Merge pull request #592 from smiclea/instances

Add support for duplicated instance names
Nashwan Azhari 5 年之前
父節點
當前提交
1410fc7a09

+ 7 - 1
src/@types/Instance.ts

@@ -47,9 +47,15 @@ export type Instance = {
   },
 }
 
+export type InstanceBase = {
+  id: string
+} & Partial<Instance>
+
 export type InstanceScript = {
   global?: string | null,
-  instanceName?: string | null,
+  instanceId?: string | null,
   scriptContent: string,
   fileName: string,
 }
+
+export const shortenId = (id: string) => id.replace(/(^.*?)-.*-(.*$)/, '$1-...-$2')

+ 4 - 4
src/components/molecules/MainDetailsTable/MainDetailsTable.tsx

@@ -285,7 +285,7 @@ class MainDetailsTable extends React.Component<Props, State> {
       }
 
       rows.push(this.renderRow(
-        `${instance.instance_name || instance.name}-${sourceName}-${destinationKey}`,
+        `${instance.instance_name || instance.id}-${sourceName}-${destinationKey}`,
         'storage',
         sourceName,
         destinationName,
@@ -360,7 +360,7 @@ class MainDetailsTable extends React.Component<Props, State> {
         }
 
         rows.push(this.renderRow(
-          `${instance.instance_name || instance.name}-${nic.network_name}`,
+          `${instance.instance_name || instance.id}-${nic.network_name}`,
           'network',
           nic.mac_address,
           destinationNetworkName,
@@ -400,7 +400,7 @@ class MainDetailsTable extends React.Component<Props, State> {
     } else if (this.props.item?.type === 'migration' && this.props.item.last_execution_status === 'RUNNING') {
       destinationName = 'Waiting for migration to finish'
     }
-    const instanceName = instance.instance_name || instance.name
+    const instanceName = instance.instance_name || instance.id
     return this.renderRow(
       instanceName,
       'instance',
@@ -425,7 +425,7 @@ class MainDetailsTable extends React.Component<Props, State> {
         </Header>
         {this.props.instancesDetails.map(instance => (
           <InstanceInfo key={instance.name}>
-            <InstanceName data-test-id={`${TEST_ID}-instanceName-${instance.name}`}>{instance.name}</InstanceName>
+            <InstanceName>{instance.name}</InstanceName>
             <InstanceBody>
               {this.renderInstanceDetails(instance)}
               {this.renderNetworks(instance)}

+ 6 - 2
src/components/molecules/PropertiesTable/PropertiesTable.tsx

@@ -205,8 +205,12 @@ class PropertiesTable extends React.Component<Props> {
         width={this.props.width}
       >
         {this.props.properties.map(prop => (
-          <Row key={prop.name} data-test-id={`${baseId}-row-${prop.name}`}>
-            <Column header data-test-id={`${baseId}-header`}><span title={this.getName(prop.name)}>{this.getName(prop.name)}</span></Column>
+          <Row key={prop.name}>
+            <Column header>
+              <span title={this.getName(prop.label || prop.name)}>
+                {this.getName(prop.label || prop.name)}
+              </span>
+            </Column>
             <Column input>{this.renderInput(prop)}</Column>
           </Row>
         ))}

+ 2 - 1
src/components/organisms/AssessmentDetailsContent/AssessmentDetailsContent.tsx

@@ -217,7 +217,8 @@ class AssessmentDetailsContent extends React.Component<Props> {
     }
 
     if (this.props.instances.length > 0
-      && !this.props.instances.find(i => i.name === `${vm.properties.displayName}`)) {
+      && !this.props.instances.find(i => i.name === vm.properties.displayName
+        || i.instance_name === vm.properties.displayName)) {
       return false
     }
 

+ 0 - 23
src/components/organisms/MainDetails/MainDetails.tsx

@@ -155,29 +155,6 @@ class MainDetails extends React.Component<Props, State> {
     return endpoint
   }
 
-  getConnectedVms(networkId: string) {
-    if (this.props.instancesDetailsLoading) {
-      return 'Loading...'
-    }
-
-    if (!this.props.item) {
-      return '-'
-    }
-
-    const vms: string[] = []
-
-    this.props.instancesDetails.forEach(instanceDet => {
-      if (
-        instanceDet.devices && instanceDet.devices.nics && instanceDet.devices.nics.find
-        && instanceDet.devices.nics.find(n => n.network_name === networkId)
-      ) {
-        vms.push(instanceDet.instance_name || instanceDet.name)
-      }
-    })
-
-    return vms.length === 0 ? 'Failed to read network configuration for the original instance' : vms.map(vm => <div data-test-id={`vm-${vm}`} style={{ marginBottom: '8px' }}>{vm}<br /></div>)
-  }
-
   renderLastExecutionTime() {
     return this.props.item ? this.renderValue(DateUtils.getLocalTime(this.props.item.updated_at).format('YYYY-MM-DD HH:mm:ss')) : '-'
   }

+ 3 - 2
src/components/organisms/ReplicaMigrationOptions/ReplicaMigrationOptions.tsx

@@ -161,7 +161,7 @@ class ReplicaMigrationOptions extends React.Component<Props, State> {
   handleCanceScript(global: string | null, instanceName: string | null) {
     this.setState(prevState => ({
       uploadedScripts: prevState.uploadedScripts
-        .filter(s => (global ? s.global !== global : s.instanceName !== instanceName)),
+        .filter(s => (global ? s.global !== global : s.instanceId !== instanceName)),
     }))
   }
 
@@ -200,7 +200,8 @@ class ReplicaMigrationOptions extends React.Component<Props, State> {
     }
 
     const properties: Field[] = this.props.instances.map(instance => ({
-      name: instance.instance_name || instance.name,
+      name: instance.instance_name || instance.id,
+      label: instance.name,
       type: 'string',
       enum: minionPools.map(minionPool => ({
         name: minionPool.pool_name,

+ 17 - 6
src/components/organisms/WizardInstances/WizardInstances.tsx

@@ -96,14 +96,19 @@ export const Image = styled.div<any>`
 `
 const Label = styled.div<any>`
   flex-grow: 1;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  overflow: hidden;
   margin: 0 16px;
+  display: flex;
+  flex-direction: column;
+`
+const LabelTitle = styled.div``
+const LabelSubtitle = styled.div`
+  color: ${Palette.grayscale[4]};
+  overflow-wrap: anywhere;
 `
 const Details = styled.div<any>`
-  font-size: 14px;
   color: ${Palette.grayscale[4]};
+  min-width: 160px;
+  text-align: right;
 `
 const FiltersWrapper = styled.div<any>`
   padding: 8px 0 0 8px;
@@ -308,6 +313,7 @@ class WizardInstances extends React.Component<Props, State> {
           const selected = Boolean(this.props.selectedInstances
             && this.props.selectedInstances.find(i => i.id === instance.id))
           const flavorName = instance.flavor_name ? ` | ${instance.flavor_name}` : ''
+          const instanceId = instance.instance_name || instance.id
           return (
             <Instance
               key={instance.id}
@@ -325,8 +331,13 @@ class WizardInstances extends React.Component<Props, State> {
               />
               <InstanceContent data-test-id="wInstances-instanceItem">
                 <Image />
-                <Label data-test-id="wInstances-itemName">{instance.instance_name || instance.name}</Label>
-                <Details data-test-id="wInstances-itemDetails">{`${instance.num_cpu} vCPU | ${instance.memory_mb} MB RAM${flavorName}`}</Details>
+                <Label>
+                  <LabelTitle>{instance.name}</LabelTitle>
+                  {instanceId !== instance.name ? (
+                    <LabelSubtitle>{instanceId}</LabelSubtitle>
+                  ) : null}
+                </Label>
+                <Details>{`${instance.num_cpu} vCPU | ${instance.memory_mb} MB RAM${flavorName}`}</Details>
               </InstanceContent>
             </Instance>
           )

+ 8 - 7
src/components/organisms/WizardNetworks/WizardNetworks.tsx

@@ -22,7 +22,7 @@ import Dropdown from '../../molecules/Dropdown'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
-import type { Instance, Nic as NicType } from '../../../@types/Instance'
+import { Instance, Nic as NicType, shortenId } from '../../../@types/Instance'
 import type { Network, NetworkMap, SecurityGroup } from '../../../@types/Network'
 
 import networkImage from './images/network.svg'
@@ -249,7 +249,7 @@ class WizardNetworks extends React.Component<Props> {
     return (
       <NicsWrapper>
         {nics.map(nic => {
-          const connectedTo = this.props.instancesDetails.filter(i => {
+          const connectedToInstances = this.props.instancesDetails.filter(i => {
             if (!i.devices || !i.devices.nics) {
               return false
             }
@@ -257,17 +257,18 @@ class WizardNetworks extends React.Component<Props> {
               return true
             }
             return false
-          }).map(i => i.instance_name || i.name)
+          }).map(instance => `${instance.name} (${shortenId(instance.instance_name || instance.id)})`)
+
           const selectedNetwork = this.props.selectedNetworks
             && this.props.selectedNetworks.find(n => n.sourceNic.network_name === nic.network_name)
           return (
             <Nic key={nic.id} data-test-id="networkItem">
               <NetworkImage />
               <NetworkTitle width={this.props.titleWidth || 320}>
-                <NetworkName data-test-id={`wNetworks-networkName-${nic.id}`}>{nic.network_name}</NetworkName>
-                {connectedTo.length ? (
-                  <NetworkSubtitle data-test-id={`wNetworks-connectedTo-${nic.id}`}>
-                    {`Connected to ${connectedTo.join(', ')}`}
+                <NetworkName>{nic.network_name}</NetworkName>
+                {connectedToInstances.length ? (
+                  <NetworkSubtitle>
+                    {`Connected to ${connectedToInstances.join(', ')}`}
                   </NetworkSubtitle>
                 ) : null}
               </NetworkTitle>

+ 4 - 2
src/components/organisms/WizardOptions/WizardOptions.tsx

@@ -243,9 +243,11 @@ class WizardOptions extends React.Component<Props> {
   getDefaultAdvancedFieldsSchema() {
     const fieldsSchema: Field[] = []
 
-    if (this.props.minionPools.length && this.props.selectedInstances) {
+    if (this.props.minionPools.length && this.props.selectedInstances
+      && this.props.selectedInstances.length) {
       const properties: Field[] = this.props.selectedInstances.map(instance => ({
-        name: instance.instance_name || instance.name,
+        name: instance.instance_name || instance.id,
+        label: instance.name,
         type: 'string',
         enum: this.props.minionPools.map(minionPool => ({
           name: minionPool.pool_name,

+ 10 - 9
src/components/organisms/WizardScripts/WizardScripts.tsx

@@ -148,7 +148,7 @@ class WizardScripts extends React.Component<Props> {
   async handleFileUpload(
     files: FileList | null,
     global: string | null,
-    instanceName: string | null,
+    instanceId: string | null,
   ) {
     if (!files || !files.length) {
       return
@@ -156,7 +156,7 @@ class WizardScripts extends React.Component<Props> {
     const fileName = files[0].name
     const scriptContent = await FileUtils.readTextFromFirstFile(files)
     this.props.onScriptUpload({
-      instanceName,
+      instanceId,
       global,
       fileName,
       scriptContent: scriptContent || '',
@@ -165,13 +165,13 @@ class WizardScripts extends React.Component<Props> {
 
   renderScriptItem(
     global: string | null,
-    instanceName: string | null,
+    instanceId: string | null,
     title: string,
     subtitle?: string,
   ) {
     const uploadedScript = this.props.uploadedScripts.find(
-      s => (s.instanceName
-        ? s.instanceName === instanceName : s.global ? s.global === global : false),
+      s => (s.instanceId
+        ? s.instanceId === instanceId : s.global ? s.global === global : false),
     )
 
     return (
@@ -192,7 +192,7 @@ class WizardScripts extends React.Component<Props> {
             <InputCloseStyled
               show
               onClick={() => {
-                this.props.onCancelScript(global, instanceName)
+                this.props.onCancelScript(global, instanceId)
                 const ref = this.fileInputRefs[title]
                 if (ref) {
                   ref.inputRef.value = ''
@@ -215,7 +215,7 @@ class WizardScripts extends React.Component<Props> {
         <FakeFileInput
           type="file"
           ref={(r: HTMLInputElement) => { this.fileInputRefs[title] = { inputRef: r } }}
-          onChange={e => { this.handleFileUpload(e.target.files, global, instanceName) }}
+          onChange={e => { this.handleFileUpload(e.target.files, global, instanceId) }}
         />
       </Script>
     )
@@ -264,12 +264,13 @@ class WizardScripts extends React.Component<Props> {
         </Heading>
         <Scripts>
           {this.props.instances.map(instance => {
-            const title = instance.instance_name || instance.name
+            const id = instance.instance_name || instance.id
+            const title = instance.name
             const osLabel = instance.os_type ? instance.os_type === 'windows' ? 'Windows' : instance.os_type === 'linux' ? 'Linux' : instance.os_type : ''
             const osType = osLabel ? `${osLabel} OS | ` : ''
             const subtitle = `${osType}${instance.num_cpu} vCPU | ${instance.memory_mb} MB RAM`
 
-            return this.renderScriptItem(null, title, title, subtitle)
+            return this.renderScriptItem(null, id, title, subtitle)
           })}
         </Scripts>
       </Group>

+ 8 - 12
src/components/organisms/WizardStorage/WizardStorage.tsx

@@ -22,7 +22,7 @@ import InfoIcon from '../../atoms/InfoIcon'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
-import type { Instance, Disk } from '../../../@types/Instance'
+import { Instance, Disk, shortenId } from '../../../@types/Instance'
 import type { StorageBackend, StorageMap } from '../../../@types/Endpoint'
 
 import backendImage from './images/backend.svg'
@@ -245,7 +245,7 @@ class WizardStorage extends React.Component<Props> {
         <StorageSection>{title}</StorageSection>
         <StorageItems>
           {usableDisks.map(disk => {
-            const connectedTo = this.props.instancesDetails.filter(i => {
+            const connectedToInstances = this.props.instancesDetails.filter(i => {
               if (!i.devices || !i.devices.disks) {
                 return false
               }
@@ -253,7 +253,8 @@ class WizardStorage extends React.Component<Props> {
                 return true
               }
               return false
-            }).map(i => i.instance_name || i.name)
+            }).map(instance => `${instance.name} (${shortenId(instance.instance_name || instance.id)})`)
+
             const selectedStorage = storageMap && storageMap.find(s => s.type === type
                 && String(s.source[diskFieldName]) === String(disk[diskFieldName]))
             const selectedItem = selectedStorage ? selectedStorage.target : null
@@ -262,17 +263,12 @@ class WizardStorage extends React.Component<Props> {
               <StorageItem key={disk[diskFieldName]}>
                 <StorageImage backend={type === 'backend'} />
                 <StorageTitle width={this.props.titleWidth || 320}>
-                  <StorageName
-                    data-test-id={`${TEST_ID}-${type}-source`}
-                    title={diskNameParsed[1] ? disk[diskFieldName] : null}
-                  >
+                  <StorageName title={diskNameParsed[1] ? disk[diskFieldName] : null}>
                     {diskNameParsed[0]}
                   </StorageName>
-                  {connectedTo.length ? (
-                    <StorageSubtitle
-                      data-test-id={`${TEST_ID}-${type}-connectedTo`}
-                    >
-                      {`Connected to ${connectedTo.join(', ')}`}
+                  {connectedToInstances.length ? (
+                    <StorageSubtitle>
+                      {`Connected to ${connectedToInstances.join(', ')}`}
                     </StorageSubtitle>
                   ) : null}
                 </StorageTitle>

+ 22 - 13
src/components/organisms/WizardSummary/WizardSummary.tsx

@@ -114,6 +114,10 @@ const InstanceRowTitle = styled.div<any>`
 const InstanceRowSubtitle = styled.div<any>`
   font-size: 10px;
   color: ${Palette.grayscale[5]};
+  margin-bottom: 4px;
+  &:last-child {
+    margin-bottom: 0;
+  }
 `
 const SourceNetwork = styled.div<any>`
   width: 50%;
@@ -371,16 +375,20 @@ class WizardSummary extends React.Component<Props> {
         <ObjectTableTitle>
           Instance OSMorphing Minion Pool Mappings
         </ObjectTableTitle>
-        {Object.keys(mappings).map(instanceName => (
-          <Option key={instanceName}>
-            <OptionLabel title={instanceName}>
-              {instanceName}
-            </OptionLabel>
-            <OptionValue title={mappings[instanceName]}>
-              {getMinionPoolName(mappings[instanceName])}
-            </OptionValue>
-          </Option>
-        ))}
+        {Object.keys(mappings).map(instanceId => {
+          const instanceName = this.props.instancesDetails
+            .find(i => i.instance_name === instanceId || i.id === instanceId)?.name || instanceId
+          return (
+            <Option key={instanceId}>
+              <OptionLabel title={instanceName}>
+                {instanceName}
+              </OptionLabel>
+              <OptionValue title={mappings[instanceId]}>
+                {getMinionPoolName(mappings[instanceId])}
+              </OptionValue>
+            </Option>
+          )
+        })}
       </ObjectTable>
     )
   }
@@ -558,7 +566,8 @@ class WizardSummary extends React.Component<Props> {
             const flavorName = instance.flavor_name ? `/${instance.flavor_name}` : ''
             return (
               <Row key={instance.id}>
-                <InstanceRowTitle data-test-id={`wSummary-instance-${instance.id}`}>{instance.name}</InstanceRowTitle>
+                <InstanceRowTitle>{instance.name}</InstanceRowTitle>
+                <InstanceRowSubtitle>{instance.instance_name || instance.id}</InstanceRowSubtitle>
                 <InstanceRowSubtitle>{`${instance.num_cpu}vCPU/${instance.memory_mb}MB${flavorName}`}</InstanceRowSubtitle>
               </Row>
             )
@@ -579,7 +588,7 @@ class WizardSummary extends React.Component<Props> {
         <Table>
           {this.props.uploadedUserScripts.map(s => (
             <Row
-              key={s.instanceName || s.global || undefined}
+              key={s.instanceId || s.global || undefined}
               style={{
                 flexDirection: 'row',
                 justifyContent: 'space-between',
@@ -588,7 +597,7 @@ class WizardSummary extends React.Component<Props> {
               }}
             >
               <InstanceRowTitle>{
-                s.global ? s.global === 'windows' ? 'Global Windows Script' : 'Global Linux Script' : s.instanceName
+                s.global ? s.global === 'windows' ? 'Global Windows Script' : 'Global Linux Script' : s.instanceId
               }
               </InstanceRowTitle>
               <ScriptFileName title={s.fileName}>{s.fileName}</ScriptFileName>

+ 10 - 7
src/components/pages/AssessmentDetailsPage/AssessmentDetailsPage.tsx

@@ -150,7 +150,8 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
     }
     return azureStore.assessedVms.filter(vm => {
       if (vm.properties.datacenterManagementServerName.toLowerCase() === sourceHost.toLowerCase()
-        && instanceStore.instances.find(i => i.name === `${vm.properties.displayName}`)) {
+        && instanceStore.instances.find(i => i.name === vm.properties.displayName
+          || i.instance_name === vm.properties.displayName)) {
         return true
       }
       return false
@@ -167,7 +168,8 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
 
   handleVmSelectedChange(vm: VmItem, selected: boolean) {
     let selectedVms = this.getLocalData().selectedVms
-    const instanceInfo = instanceStore.instances.find(i => i.name === vm.properties.displayName)
+    const instanceInfo = instanceStore.instances.find(i => i.name === vm.properties.displayName
+      || i.instance_name === vm.properties.displayName)
     if (selected) {
       selectedVms = [
         ...selectedVms,
@@ -435,7 +437,8 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
   loadInstancesDetails() {
     const localData = this.getLocalData()
     const selectedVms = localData.selectedVms
-    const instancesInfo = instanceStore.instances.filter(i => selectedVms.find(m => i.name === m))
+    const instancesInfo = instanceStore.instances.filter(i => selectedVms
+      .find(m => i.instance_name === m || i.name === m))
     instanceStore.clearInstancesDetails()
     const sourceEndpointId = this.getSourceEndpointId()
     if (!sourceEndpointId) {
@@ -443,7 +446,7 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
     }
     instanceStore.loadInstancesDetails({
       endpointId: sourceEndpointId,
-      instancesInfo,
+      instances: instancesInfo,
       // cache: true,
       skipLog: true,
       env: {
@@ -457,12 +460,12 @@ class AssessmentDetailsPage extends React.Component<Props, State> {
   handleMigrationExecute(fieldValues: { [prop: string]: any }) {
     const selectedVms = this.getLocalData().selectedVms
     const selectedInstances = instanceStore.instancesDetails
-      .filter(i => selectedVms.find(m => i.name === m))
+      .filter(i => selectedVms.find(m => i.name === m || i.instance_name === m))
     const vmSizes: any = {}
     const localData = this.getLocalData()
     selectedInstances.forEach(i => {
-      const vm = selectedVms.find(m => i.name === m)
-      const selectedVmSize = localData.selectedVmSizes[i.name]
+      const vm = selectedVms.find(m => i.name === m || i.instance_name === m)
+      const selectedVmSize = localData.selectedVmSizes[i.instance_name || i.name]
       if (vm && azureStore.vmSizes.find(s => s === selectedVmSize)) {
         vmSizes[i.instance_name || i.name] = selectedVmSize
       }

+ 1 - 1
src/components/pages/MigrationDetailsPage/MigrationDetailsPage.tsx

@@ -159,7 +159,7 @@ class MigrationDetailsPage extends React.Component<Props, State> {
       .find(e => e.id === details.destination_endpoint_id)
     instanceStore.loadInstancesDetails({
       endpointId: details.origin_endpoint_id,
-      instancesInfo: details.instances.map(n => ({ name: n })),
+      instances: details.instances.map(n => ({ id: n })),
       cache,
       quietError: false,
       env: details.source_environment,

+ 1 - 1
src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.tsx

@@ -214,7 +214,7 @@ class ReplicaDetailsPage extends React.Component<Props, State> {
       .find(e => e.id === replica.destination_endpoint_id)
     instanceStore.loadInstancesDetails({
       endpointId: replica.origin_endpoint_id,
-      instancesInfo: replica.instances.map(n => ({ name: n })),
+      instances: replica.instances.map(n => ({ id: n })),
       cache,
       quietError: false,
       env: replica.source_environment,

+ 3 - 3
src/components/pages/ReplicasPage/ReplicasPage.tsx

@@ -159,8 +159,8 @@ class ReplicasPage extends React.Component<{ history: any }, State> {
       .map(replica => migrationStore.migrateReplica(
         replica.id,
         fields,
-        uploadedScripts.filter(s => !s.instanceName
-          || replica.instances.find(i => i === s.instanceName)),
+        uploadedScripts.filter(s => !s.instanceId
+          || replica.instances.find(i => i === s.instanceId)),
         replica.instance_osmorphing_minion_pool_mappings || {},
       )))
     notificationStore.alert('Migrations successfully created from replicas.', 'success')
@@ -226,7 +226,7 @@ class ReplicasPage extends React.Component<{ history: any }, State> {
   handleShowCreateMigrationsModal() {
     instanceStore.loadInstancesDetailsBulk(replicaStore.replicas.map(r => ({
       endpointId: r.origin_endpoint_id,
-      instanceNames: r.instances,
+      instanceIds: r.instances,
       env: r.source_environment,
     })))
 

+ 1 - 2
src/components/pages/WizardPage/WizardPage.tsx

@@ -503,8 +503,7 @@ class WizardPage extends React.Component<Props, State> {
     if (wizardStore.data.source && wizardStore.data.selectedInstances && wizardStore.data.target) {
       instanceStore.loadInstancesDetails({
         endpointId: wizardStore.data.source.id,
-        instancesInfo:
-          wizardStore.data.selectedInstances as { name: string, instance_name?: string }[],
+        instances: wizardStore.data.selectedInstances,
         env: wizardStore.data.sourceOptions,
         cache,
         targetProvider: wizardStore.data.target.type,

+ 2 - 2
src/plugins/endpoint/default/OptionsSchemaPlugin.ts

@@ -266,11 +266,11 @@ export default class OptionsSchemaParser {
         payload.global[script.global || ''] = script.scriptContent
       })
     }
-    const instanceScripts = uploadedUserScripts.filter(s => s.instanceName)
+    const instanceScripts = uploadedUserScripts.filter(s => s.instanceId)
     if (instanceScripts.length) {
       payload.instances = {}
       instanceScripts.forEach(script => {
-        payload.instances[script.instanceName || ''] = script.scriptContent
+        payload.instances[script.instanceId || ''] = script.scriptContent
       })
     }
     return payload

+ 3 - 3
src/sources/InstanceSource.ts

@@ -77,7 +77,7 @@ class InstanceSource {
 
   async loadInstanceDetails(opts: {
     endpointId: string,
-    instanceName: string,
+    instanceId: string,
     targetProvider?: ProviderTypes | null,
     reqId: number,
     quietError?: boolean,
@@ -86,9 +86,9 @@ class InstanceSource {
     skipLog?: boolean | null,
   }): Promise<{ instance?: Instance, reqId: number }> {
     const {
-      endpointId, instanceName, targetProvider, reqId, quietError, env, cache, skipLog,
+      endpointId, instanceId, targetProvider, reqId, quietError, env, cache, skipLog,
     } = opts
-    let url = `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances/${DomUtils.encodeToBase64Url(instanceName)}`
+    let url = `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances/${DomUtils.encodeToBase64Url(instanceId)}`
     if (env) {
       url += `?env=${DomUtils.encodeToBase64Url(env)}`
     }

+ 5 - 5
src/sources/WizardSource.ts

@@ -42,7 +42,7 @@ class WizardSource {
       origin_endpoint_id: data.source ? data.source.id : 'null',
       destination_endpoint_id: data.target ? data.target.id : 'null',
       network_map: destParser.getNetworkMap(data.networks),
-      instances: data.selectedInstances ? data.selectedInstances.map(i => i.instance_name || i.name) : 'null',
+      instances: data.selectedInstances ? data.selectedInstances.map(i => i.instance_name || i.id) : 'null',
       storage_mappings: destParser.getStorageMap(defaultStorage, storageMap),
       notes: data.destOptions ? data.destOptions.description || '' : '',
     }
@@ -68,9 +68,9 @@ class WizardSource {
 
     const poolMappings = destEnv[INSTANCE_OSMORPHING_MINION_POOL_MAPPINGS]
     if (poolMappings) {
-      Object.keys(poolMappings).forEach(instanceName => {
-        if (poolMappings[instanceName]
-          && payload[type].instances.find((i: string) => i === instanceName)) {
+      Object.keys(poolMappings).forEach(instanceId => {
+        if (poolMappings[instanceId]
+          && payload[type].instances.find((i: string) => i === instanceId)) {
           if (!payload[type][
             INSTANCE_OSMORPHING_MINION_POOL_MAPPINGS
           ]) {
@@ -80,7 +80,7 @@ class WizardSource {
           }
           payload[type][
             INSTANCE_OSMORPHING_MINION_POOL_MAPPINGS
-          ][instanceName] = poolMappings[instanceName]
+          ][instanceId] = poolMappings[instanceId]
         }
       })
     }

+ 18 - 16
src/stores/InstanceStore.ts

@@ -16,7 +16,7 @@ import {
   observable, runInAction, computed, action,
 } from 'mobx'
 
-import type { Instance } from '../@types/Instance'
+import type { Instance, InstanceBase } from '../@types/Instance'
 import type { Endpoint } from '../@types/Endpoint'
 import InstanceSource from '../sources/InstanceSource'
 import ApiCaller from '../utils/ApiCaller'
@@ -241,7 +241,7 @@ class InstanceStore {
   @action async loadInstancesDetailsBulk(
     instanceInfos: {
       endpointId: string,
-      instanceNames: string[],
+      instanceIds: string[],
       env?: any,
     }[],
   ) {
@@ -251,10 +251,10 @@ class InstanceStore {
     InstanceSource.cancelInstancesDetailsRequests(this.reqId - 1)
     try {
       await Promise.all(instanceInfos.map(async i => {
-        await Promise.all(i.instanceNames.map(async name => {
+        await Promise.all(i.instanceIds.map(async instanceId => {
           const instanceDetails = await InstanceSource.loadInstanceDetails({
             endpointId: i.endpointId,
-            instanceName: name,
+            instanceId,
             reqId: this.reqId,
             quietError: false,
             env: i.env,
@@ -265,10 +265,11 @@ class InstanceStore {
             return
           }
           runInAction(() => {
-            this.instancesDetails = this.instancesDetails.filter(id => (id.name || id.instance_name || '') !== name)
+            this.instancesDetails = this.instancesDetails
+              .filter(id => (id.instance_name || id.id) !== instanceId)
             this.instancesDetails.push(instance)
-            this.instancesDetails = this.instancesDetails.slice().sort(n => (n.name || n.instance_name || '')
-              .localeCompare(n.name || n.instance_name || ''))
+            this.instancesDetails = this.instancesDetails.slice()
+              .sort(n => n.name.localeCompare(n.name))
           })
         }))
       }))
@@ -279,7 +280,7 @@ class InstanceStore {
 
   @action async addInstanceDetails(opts: {
     endpointId: string,
-    instanceInfo: {name: string, instance_name?: string | null},
+    instanceInfo: InstanceBase,
     cache?: boolean,
     quietError?: boolean,
     env?: any,
@@ -291,7 +292,7 @@ class InstanceStore {
     this.loadingInstancesDetails = true
     const resp = await InstanceSource.loadInstanceDetails({
       endpointId,
-      instanceName: instanceInfo.instance_name || instanceInfo.name,
+      instanceId: instanceInfo.instance_name || instanceInfo.id,
       targetProvider,
       reqId: this.reqId,
       quietError,
@@ -323,7 +324,7 @@ class InstanceStore {
 
   @action async loadInstancesDetails(opts: {
     endpointId: string,
-    instancesInfo: {name: string, instance_name?: string | null}[],
+    instances: InstanceBase[],
     cache?: boolean,
     quietError?: boolean,
     skipLog?: boolean,
@@ -331,17 +332,18 @@ class InstanceStore {
     targetProvider?: ProviderTypes | null,
   }): Promise<void> {
     const {
-      endpointId, instancesInfo, cache, quietError, env, targetProvider, skipLog,
+      endpointId, instances, cache, quietError, env, targetProvider, skipLog,
     } = opts
     // Use reqId to be able to uniquely identify the request
     // so all but the latest request can be igonred and canceled
     this.reqId = !this.reqId ? 1 : this.reqId + 1
     InstanceSource.cancelInstancesDetailsRequests(this.reqId - 1)
 
-    instancesInfo
-      .sort((a, b) => (a.instance_name || a.name).localeCompare(b.instance_name || b.name))
+    instances
+      .sort((a, b) => (a.instance_name || a.name || a.id)
+        .localeCompare(b.instance_name || b.name || b.id))
 
-    const count = instancesInfo.length
+    const count = instances.length
     if (count === 0) {
       return
     }
@@ -351,11 +353,11 @@ class InstanceStore {
     this.instancesDetailsRemaining = count
 
     await new Promise(resolve => {
-      Promise.all(instancesInfo.map(async instanceInfo => {
+      Promise.all(instances.map(async instanceInfo => {
         try {
           const resp = await InstanceSource.loadInstanceDetails({
             endpointId,
-            instanceName: instanceInfo.instance_name || instanceInfo.name,
+            instanceId: instanceInfo.instance_name || instanceInfo.id,
             targetProvider,
             reqId: this.reqId,
             quietError,

+ 1 - 1
src/stores/WizardStore.ts

@@ -315,7 +315,7 @@ class WizardStore {
 
   @action cancelUploadedScript(global: string | null, instanceName: string | null) {
     this.uploadedUserScripts = this.uploadedUserScripts
-      .filter(s => (global ? s.global !== global : s.instanceName !== instanceName))
+      .filter(s => (global ? s.global !== global : s.instanceId !== instanceName))
   }
 
   @action uploadUserScript(instanceScript: InstanceScript) {