ソースを参照

Add instance with no ID protection

Previously, the UI entered an infinite loop if there was an instance
with no ID and that instance was the last in the chunk of instances
returned for an endpoint.

With this commit, if there are instances with no ID, they are skipped
and an error is shown in the UI with their name.

This commit also lays the groundwork for future instance validation.
Sergiu Miclea 4 年 前
コミット
2bb1a70b43
2 ファイル変更30 行追加10 行削除
  1. 11 2
      src/sources/InstanceSource.ts
  2. 19 8
      src/stores/InstanceStore.ts

+ 11 - 2
src/sources/InstanceSource.ts

@@ -30,7 +30,7 @@ class InstanceSource {
     searchText?: string,
     searchText?: string,
     env?: any,
     env?: any,
     cache?: boolean,
     cache?: boolean,
-  ): Promise<Instance[]> {
+  ): Promise<[Instance[], Instance[]]> {
     let url = `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances`
     let url = `${configLoader.config.servicesUrls.coriolis}/${Api.projectId}/endpoints/${endpointId}/instances`
     let queryParams: { [prop: string]: string | number } = {}
     let queryParams: { [prop: string]: string | number } = {}
 
 
@@ -65,7 +65,16 @@ class InstanceSource {
     url = `${url}${keys.length > 0 ? '?' : ''}${keys.map(p => `${p}=${queryParams[p]}`).join('&')}`
     url = `${url}${keys.length > 0 ? '?' : ''}${keys.map(p => `${p}=${queryParams[p]}`).join('&')}`
 
 
     const response = await Api.send({ url, cancelId, cache })
     const response = await Api.send({ url, cancelId, cache })
-    return response.data.instances
+    const rawinstances: Instance[] = response.data.instances
+    const invalidInstances: Instance[] = []
+    const instances = rawinstances.filter(instance => {
+      if (!instance.id) {
+        invalidInstances.push(instance)
+        return false
+      }
+      return true
+    })
+    return [instances, invalidInstances]
   }
   }
 
 
   async loadInstances(endpointId: string, cache?: boolean | null): Promise<Instance[]> {
   async loadInstances(endpointId: string, cache?: boolean | null): Promise<Instance[]> {

+ 19 - 8
src/stores/InstanceStore.ts

@@ -22,6 +22,7 @@ import InstanceSource from '../sources/InstanceSource'
 import ApiCaller from '../utils/ApiCaller'
 import ApiCaller from '../utils/ApiCaller'
 import configLoader from '../utils/Config'
 import configLoader from '../utils/Config'
 import { ProviderTypes } from '../@types/Providers'
 import { ProviderTypes } from '../@types/Providers'
+import notificationStore from './NotificationStore'
 
 
 class InstanceStore {
 class InstanceStore {
   @observable instancesLoading = false
   @observable instancesLoading = false
@@ -99,11 +100,15 @@ class InstanceStore {
 
 
     const loadNextChunk = async (lastEndpointId?: string) => {
     const loadNextChunk = async (lastEndpointId?: string) => {
       const currentEndpointId = endpoint.id
       const currentEndpointId = endpoint.id
-      const instances = await InstanceSource.loadInstancesChunk(currentEndpointId, chunkCount, lastEndpointId, `${endpoint.id}-chunk`, undefined, env, useCache)
+      const [instances, invalidInstances] = await InstanceSource.loadInstancesChunk(currentEndpointId, chunkCount, lastEndpointId, `${endpoint.id}-chunk`, undefined, env, useCache)
       if (currentEndpointId !== this.lastEndpointId) {
       if (currentEndpointId !== this.lastEndpointId) {
         return
         return
       }
       }
-      const shouldContinue = this.loadInstancesInChunksSuccess(instances, chunkCount, reload)
+      if (invalidInstances.length) {
+        notificationStore.alert(`There are one or more instances with invalid data (i.e. missing ID): ${invalidInstances.map(i => i.name || i.instance_name).join(', ')}`, 'error')
+      }
+
+      const shouldContinue = this.loadInstancesInChunksSuccess(instances, instances.length + invalidInstances.length, chunkCount, reload)
       if (shouldContinue) {
       if (shouldContinue) {
         loadNextChunk(instances[instances.length - 1].id)
         loadNextChunk(instances[instances.length - 1].id)
       }
       }
@@ -112,7 +117,10 @@ class InstanceStore {
   }
   }
 
 
   @action loadInstancesInChunksSuccess(
   @action loadInstancesInChunksSuccess(
-    instances: Instance[], chunkCount: number, reload?: boolean,
+    instances: Instance[],
+    instancesCount: number,
+    chunkCount: number,
+    reload?: boolean,
   ): boolean {
   ): boolean {
     this.backgroundInstances = [...this.backgroundInstances, ...instances]
     this.backgroundInstances = [...this.backgroundInstances, ...instances]
     if (reload) {
     if (reload) {
@@ -120,7 +128,7 @@ class InstanceStore {
     }
     }
     this.instancesLoading = false
     this.instancesLoading = false
 
 
-    if (instances.length < chunkCount) {
+    if (instancesCount < chunkCount) {
       this.backgroundChunksLoading = false
       this.backgroundChunksLoading = false
       return false
       return false
     }
     }
@@ -180,7 +188,7 @@ class InstanceStore {
       .max(chunkSize[endpoint.type] || chunkSize.default, this.instancesPerPage)
       .max(chunkSize[endpoint.type] || chunkSize.default, this.instancesPerPage)
 
 
     const loadNextChunk = async (lastEndpointId?: string) => {
     const loadNextChunk = async (lastEndpointId?: string) => {
-      const instances = await InstanceSource.loadInstancesChunk(
+      const [instances, invalidInstances] = await InstanceSource.loadInstancesChunk(
         endpoint.id,
         endpoint.id,
         chunkCount,
         chunkCount,
         lastEndpointId,
         lastEndpointId,
@@ -193,7 +201,10 @@ class InstanceStore {
           this.searchedInstances = []
           this.searchedInstances = []
         })
         })
       }
       }
-      const shouldContinue = this.searchInstancesSuccess(instances, chunkCount)
+      if (invalidInstances.length) {
+        notificationStore.alert(`There are one or more instances with invalid data (i.e. missing ID): ${invalidInstances.map(i => i.name || i.instance_name).join(', ')}`, 'error')
+      }
+      const shouldContinue = this.searchInstancesSuccess(instances, instances.length + invalidInstances.length, chunkCount)
       if (shouldContinue) {
       if (shouldContinue) {
         loadNextChunk(instances[instances.length - 1].id)
         loadNextChunk(instances[instances.length - 1].id)
       }
       }
@@ -201,11 +212,11 @@ class InstanceStore {
     loadNextChunk()
     loadNextChunk()
   }
   }
 
 
-  @action searchInstancesSuccess(instances: Instance[], chunkCount: number): boolean {
+  @action searchInstancesSuccess(instances: Instance[], instancesCount: number, chunkCount: number): boolean {
     this.searchedInstances = [...this.searchedInstances, ...instances]
     this.searchedInstances = [...this.searchedInstances, ...instances]
     this.searching = false
     this.searching = false
     this.searchNotFound = Boolean(this.searchedInstances.length === 0)
     this.searchNotFound = Boolean(this.searchedInstances.length === 0)
-    if (instances.length < chunkCount) {
+    if (instancesCount < chunkCount) {
       this.searchChunksLoading = false
       this.searchChunksLoading = false
       return false
       return false
     }
     }