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

Fix disabled 'Update' button in replica edit modal

This happens, for example, when editing a replica with Openstack as the
source provider. The issue was caused by not properly handling object
validation in the case of nested objects inside replica's source or
destination environment.
Sergiu Miclea 3 лет назад
Родитель
Сommit
f11aa4e2b9

+ 3 - 8
src/components/modules/TransferModule/TransferItemModal/TransferItemModal.tsx

@@ -51,6 +51,7 @@ import minionPoolStore from '@src/stores/MinionPoolStore'
 import WizardScripts from '@src/components/modules/WizardModule/WizardScripts'
 import networkStore from '@src/stores/NetworkStore'
 import { ThemeProps } from '@src/components/Theme'
+import ObjectUtils from '@src/utils/ObjectUtils'
 
 const PanelContent = styled.div<any>`
   display: flex;
@@ -392,10 +393,7 @@ class TransferItemModal extends React.Component<Props, State> {
     const envData = getFieldChangeOptions({
       providerName: endpoint.type,
       schema: type === 'source' ? providerStore.sourceSchema : providerStore.destinationSchema,
-      data: {
-        ...env,
-        ...stateEnv,
-      },
+      data: ObjectUtils.mergeDeep(env, stateEnv),
       field: field || null,
       type,
       parentFieldName,
@@ -458,10 +456,7 @@ class TransferItemModal extends React.Component<Props, State> {
     const env = type === 'source' ? this.props.replica.source_environment : this.props.replica.destination_environment
     const data = type === 'source' ? this.state.sourceData : this.state.destinationData
     const schema = type === 'source' ? providerStore.sourceSchema : providerStore.destinationSchema
-    const invalidFields = findInvalidFields({
-      ...env,
-      ...data,
-    }, schema)
+    const invalidFields = findInvalidFields(ObjectUtils.mergeDeep(env, data), schema)
 
     this.setState({ updateDisabled: invalidFields.length > 0 })
   }

+ 44 - 4
src/utils/ObjectUtils.ts

@@ -24,7 +24,11 @@ class ObjectUtils {
     return value != null
   }
 
-  static flatten(object: any, appendParentPath?: boolean, parent?: string): any {
+  static flatten(
+    object: any,
+    appendParentPath?: boolean,
+    parent?: string,
+  ): any {
     let result: any = {}
 
     Object.keys(object).forEach(k => {
@@ -72,10 +76,16 @@ class ObjectUtils {
   }
 
   static async wait(ms: number) {
-    return new Promise<void>(r => { setTimeout(() => r(), ms) })
+    return new Promise<void>(r => {
+      setTimeout(() => r(), ms)
+    })
   }
 
-  static async waitFor(predicate: () => boolean, timeoutMs: number = 15000, tryEvery: number = 1000) {
+  static async waitFor(
+    predicate: () => boolean,
+    timeoutMs: number = 15000,
+    tryEvery: number = 1000,
+  ) {
     const startTime = new Date().getTime()
     const testLoop = async () => {
       if (predicate()) {
@@ -100,7 +110,11 @@ class ObjectUtils {
     return value.charAt(0).toUpperCase() + value.slice(1)
   }
 
-  static async retry(retryFunction: () => Promise<any>, retryEvery: number = 1000, retryCount: number = 3): Promise<any> {
+  static async retry(
+    retryFunction: () => Promise<any>,
+    retryEvery: number = 1000,
+    retryCount: number = 3,
+  ): Promise<any> {
     let currentTry = 0
     const retryLoop = async (): Promise<any> => {
       try {
@@ -122,6 +136,32 @@ class ObjectUtils {
 
     return retryLoop()
   }
+
+  static isObject(item: any) {
+    return item && typeof item === 'object' && !Array.isArray(item)
+  }
+
+  static mergeDeep(target: any, ...sources: any[]): any {
+    if (!sources.length) {
+      return target
+    }
+    const source = sources.shift()
+
+    if (this.isObject(target) && this.isObject(source)) {
+      Object.keys(source).forEach(key => {
+        if (this.isObject(source[key])) {
+          if (!target[key]) {
+            Object.assign(target, { [key]: {} })
+          }
+          this.mergeDeep(target[key], source[key])
+        } else {
+          Object.assign(target, { [key]: source[key] })
+        }
+      })
+    }
+
+    return this.mergeDeep(target, ...sources)
+  }
 }
 
 export default ObjectUtils