Преглед изворни кода

fix(dashboard): Fix saving new entities when using UUIDs

Fixes #3616
Michael Bromley пре 6 месеци
родитељ
комит
d880112b7e

+ 5 - 2
packages/dashboard/src/lib/framework/form-engine/use-generated-form.tsx

@@ -7,7 +7,7 @@ import { useChannel } from '../../hooks/use-channel.js';
 import { useServerConfig } from '../../hooks/use-server-config.js';
 import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
 import { createFormSchemaFromFields, getDefaultValuesFromFields } from './form-schema-tools.js';
-import { transformRelationFields } from './utils.js';
+import { removeEmptyIdFields, transformRelationFields } from './utils.js';
 
 export interface GeneratedFormOptions<
     T extends TypedDocumentNode<any, any>,
@@ -64,7 +64,10 @@ export function useGeneratedForm<
     };
     if (onSubmit) {
         submitHandler = (event: FormEvent) => {
-            form.handleSubmit(onSubmit as any)(event);
+            const onSubmitWrapper = (values: any) => {
+                onSubmit(removeEmptyIdFields(values, updateFields));
+            };
+            form.handleSubmit(onSubmitWrapper)(event);
         };
     }
 

+ 37 - 0
packages/dashboard/src/lib/framework/form-engine/utils.spec.ts

@@ -0,0 +1,37 @@
+import { graphql, VariablesOf } from 'gql.tada';
+import { describe, expect, it } from 'vitest';
+
+import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
+
+import { removeEmptyIdFields } from './utils.js';
+
+const createProductDocument = graphql(`
+    mutation CreateProduct($input: CreateProductInput!) {
+        createProduct(input: $input) {
+            id
+        }
+    }
+`);
+
+type CreateProductInput = VariablesOf<typeof createProductDocument>;
+
+describe('removeEmptyIdFields', () => {
+    it('should remove empty translation id field', () => {
+        const values: CreateProductInput = {
+            input: { translations: [{ id: '', languageCode: 'en' }] },
+        };
+        const fields = getOperationVariablesFields(createProductDocument);
+        const result = removeEmptyIdFields(values, fields);
+
+        expect(result).toEqual({ input: { translations: [{ languageCode: 'en' }] } });
+    });
+
+    it('should remove empty featuredAsset id field', () => {
+        const values: CreateProductInput = {
+            input: { featuredAssetId: '', translations: [] },
+        };
+        const fields = getOperationVariablesFields(createProductDocument);
+        const result = removeEmptyIdFields(values, fields);
+        expect(result).toEqual({ input: { translations: [] } });
+    });
+});

+ 47 - 0
packages/dashboard/src/lib/framework/form-engine/utils.ts

@@ -56,3 +56,50 @@ export function transformRelationFields<E extends Record<string, any>>(fields: F
 
     return processedEntity;
 }
+
+/**
+ * @description
+ * Due to the schema types, sometimes "create" mutations will have a default empty "id"
+ * field which can cause issues if we actually send them with a "create" mutation to the server.
+ * This function deletes any empty ID fields on the entity or its nested objects.
+ */
+export function removeEmptyIdFields<T extends Record<string, any>>(values: T, fields: FieldInfo[]): T {
+    if (!values) {
+        return values;
+    }
+
+    // Create a deep copy to avoid mutating the original values
+    const result = structuredClone(values);
+
+    function recursiveRemove(obj: any, fieldDefs: FieldInfo[]) {
+        if (Array.isArray(obj)) {
+            for (const item of obj) {
+                recursiveRemove(item, fieldDefs);
+            }
+        } else if (typeof obj === 'object' && obj !== null) {
+            for (const field of fieldDefs) {
+                // Remove empty string ID fields at this level
+                if (field.type === 'ID' && typeof obj[field.name] === 'string' && obj[field.name] === '') {
+                    delete obj[field.name];
+                }
+                // If the field is an object or array, recurse into it
+                if (Array.isArray(obj[field.name])) {
+                    if (field.typeInfo) {
+                        for (const item of obj[field.name]) {
+                            recursiveRemove(item, field.typeInfo);
+                        }
+                    }
+                } else if (
+                    typeof obj[field.name] === 'object' &&
+                    obj[field.name] !== null &&
+                    field.typeInfo
+                ) {
+                    recursiveRemove(obj[field.name], field.typeInfo);
+                }
+            }
+        }
+    }
+
+    recursiveRemove(result, fields);
+    return result;
+}