From df01b311617f1b6bd51bedae1d15034cf636e316 Mon Sep 17 00:00:00 2001 From: Eric Luce <37158449+eluce2@users.noreply.github.com> Date: Fri, 19 Dec 2025 16:25:52 -0600 Subject: [PATCH 1/2] include all fields by default --- .../typegen/src/fmodata/generateODataTypes.ts | 15 ++ packages/typegen/src/types.ts | 8 + packages/typegen/web/src/App.tsx | 1 + .../web/src/components/ConfigEditor.tsx | 12 + .../src/components/MetadataFieldsDialog.tsx | 220 +++++++++++++++--- .../src/components/MetadataTablesEditor.tsx | 31 ++- 6 files changed, 250 insertions(+), 37 deletions(-) diff --git a/packages/typegen/src/fmodata/generateODataTypes.ts b/packages/typegen/src/fmodata/generateODataTypes.ts index ad7dc9db..a3cb3bff 100644 --- a/packages/typegen/src/fmodata/generateODataTypes.ts +++ b/packages/typegen/src/fmodata/generateODataTypes.ts @@ -159,6 +159,7 @@ function generateTableOccurrence( existingFields?: ParsedTableOccurrence, alwaysOverrideFieldNames?: boolean, importAliases?: Map, // Map base name -> alias (e.g., "textField" -> "tf") + includeAllFieldsByDefault?: boolean, ): GeneratedTO { const fmtId = entityType["@TableID"]; const keyFields = entityType.$Key || []; @@ -232,6 +233,12 @@ function generateTableOccurrence( } } + // Determine includeAllFieldsByDefault: table-level override takes precedence, then top-level, default to true + const effectiveIncludeAllFieldsByDefault = + tableOverride?.includeAllFieldsByDefault ?? + includeAllFieldsByDefault ?? + true; + // Generate field builder definitions const fieldLines: string[] = []; const fieldEntries = Array.from(fields.entries()); @@ -250,6 +257,11 @@ function generateTableOccurrence( continue; } + // If includeAllFieldsByDefault is false, only include fields explicitly listed + if (!effectiveIncludeAllFieldsByDefault && !fieldOverride) { + continue; + } + validFieldEntries.push(entry); } @@ -933,6 +945,7 @@ export async function generateODataTypes( clearOldFiles = true, tables, alwaysOverrideFieldNames = true, + includeAllFieldsByDefault = true, } = config; const outputPath = path ?? "schema"; @@ -993,6 +1006,7 @@ export async function generateODataTypes( undefined, tableAlwaysOverrideFieldNames, undefined, + includeAllFieldsByDefault, ); generatedTOs.push({ ...generated, @@ -1052,6 +1066,7 @@ export async function generateODataTypes( existingFields, tableAlwaysOverrideFieldNames, existingFields.importAliases, + includeAllFieldsByDefault, ) : generated; diff --git a/packages/typegen/src/types.ts b/packages/typegen/src/types.ts index 81ab2558..8b1cc39c 100644 --- a/packages/typegen/src/types.ts +++ b/packages/typegen/src/types.ts @@ -128,6 +128,10 @@ const tableConfig = z.object({ description: "If undefined, the top-level setting will be used. If true, field names will always be updated to match metadata, even when matching by entity ID. If false, existing field names are preserved when matching by entity ID.", }), + includeAllFieldsByDefault: z.boolean().optional().meta({ + description: + "If true, all fields will be included by default. If false, only fields that are explicitly listed in the `fields` array will be included.", + }), }); const typegenConfigSingleBase = z.discriminatedUnion("type", [ @@ -182,6 +186,10 @@ const typegenConfigSingleBase = z.discriminatedUnion("type", [ description: "Required array of tables to generate. Only the tables specified here will be downloaded and generated. Each table can have field-level overrides for excluding fields, renaming variables, and overriding field types.", }), + includeAllFieldsByDefault: z.boolean().default(true).optional().meta({ + description: + "If true, all fields will be included by default. If false, only fields that are explicitly listed in the `fields` array will be included.", + }), }), ]); diff --git a/packages/typegen/web/src/App.tsx b/packages/typegen/web/src/App.tsx index bd4cd394..8724576a 100644 --- a/packages/typegen/web/src/App.tsx +++ b/packages/typegen/web/src/App.tsx @@ -62,6 +62,7 @@ function createFmodataConfig(): SingleConfig { }, tables: [], alwaysOverrideFieldNames: true, + includeAllFieldsByDefault: true, }; } diff --git a/packages/typegen/web/src/components/ConfigEditor.tsx b/packages/typegen/web/src/components/ConfigEditor.tsx index c62e1769..dd9a1f0f 100644 --- a/packages/typegen/web/src/components/ConfigEditor.tsx +++ b/packages/typegen/web/src/components/ConfigEditor.tsx @@ -320,6 +320,18 @@ export function ConfigEditor({ index, onRemove }: ConfigEditorProps) { /> )} /> + ( + + )} + /> )} diff --git a/packages/typegen/web/src/components/MetadataFieldsDialog.tsx b/packages/typegen/web/src/components/MetadataFieldsDialog.tsx index cb2a69d4..62bdcc20 100644 --- a/packages/typegen/web/src/components/MetadataFieldsDialog.tsx +++ b/packages/typegen/web/src/components/MetadataFieldsDialog.tsx @@ -143,6 +143,12 @@ export function MetadataFieldsDialog({ name: `config.${configIndex}.tables` as const, }); + // Get the top-level includeAllFieldsByDefault value for display + const topLevelIncludeAllFieldsByDefault = useWatch({ + control, + name: `config.${configIndex}.includeAllFieldsByDefault` as const, + }); + // Use a ref to store the latest fieldsConfig to avoid unstable dependencies const fieldsConfigRef = useRef(EMPTY_FIELDS_CONFIG); @@ -219,6 +225,13 @@ export function MetadataFieldsDialog({ (t) => t?.tableName === tableName, ); + // Get effective includeAllFieldsByDefault value + const tableConfig = currentTables[tableIndex]; + const effectiveIncludeAllFieldsByDefault = + tableConfig?.includeAllFieldsByDefault ?? + topLevelIncludeAllFieldsByDefault ?? + true; + if (tableIndex < 0) { // Table doesn't exist in config yet if (exclude) { @@ -231,6 +244,16 @@ export function MetadataFieldsDialog({ ], { shouldDirty: true }, ); + } else if (!effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is false, add field to array to include it + setValue( + `config.${configIndex}.tables` as any, + [ + ...currentTables, + { tableName, fields: [{ fieldName }] }, + ], + { shouldDirty: true }, + ); } return; } @@ -266,41 +289,61 @@ export function MetadataFieldsDialog({ }); } } else { - // Remove exclude (or remove entire entry if no other config) - if (fieldIndex >= 0) { - const fieldConfig = currentFields[fieldIndex]!; - const { exclude: _, ...rest } = fieldConfig; + // Include the field + if (effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is true, remove field from array (or just remove exclude property) + if (fieldIndex >= 0) { + const fieldConfig = currentFields[fieldIndex]!; + const { exclude: _, ...rest } = fieldConfig; - if (Object.keys(rest).length === 1 && rest.fieldName) { - // Only fieldName left, remove entire field entry - const newFields = currentFields.filter((_, i) => i !== fieldIndex); - const newTables = [...currentTables]; + if (Object.keys(rest).length === 1 && rest.fieldName) { + // Only fieldName left, remove entire field entry + const newFields = currentFields.filter((_, i) => i !== fieldIndex); + const newTables = [...currentTables]; - if ( - newFields.length === 0 && - Object.keys(newTables[tableIndex]!).length === 2 - ) { - // Only tableName and fields left, remove entire table entry - const filteredTables = currentTables.filter( - (_, i) => i !== tableIndex, - ); - setValue( - `config.${configIndex}.tables` as any, - filteredTables.length > 0 ? filteredTables : undefined, - { shouldDirty: true }, - ); + if ( + newFields.length === 0 && + Object.keys(newTables[tableIndex]!).length === 2 + ) { + // Only tableName and fields left, remove entire table entry + const filteredTables = currentTables.filter( + (_, i) => i !== tableIndex, + ); + setValue( + `config.${configIndex}.tables` as any, + filteredTables.length > 0 ? filteredTables : undefined, + { shouldDirty: true }, + ); + } else { + // Keep table but update fields + newTables[tableIndex] = { + ...newTables[tableIndex]!, + fields: newFields.length > 0 ? newFields : undefined, + }; + setValue(`config.${configIndex}.tables` as any, newTables, { + shouldDirty: true, + }); + } } else { - // Keep table but update fields + // Keep other properties + const newFields = [...currentFields]; + newFields[fieldIndex] = rest as any; + const newTables = [...currentTables]; newTables[tableIndex] = { ...newTables[tableIndex]!, - fields: newFields.length > 0 ? newFields : undefined, + fields: newFields, }; setValue(`config.${configIndex}.tables` as any, newTables, { shouldDirty: true, }); } - } else { - // Keep other properties + } + } else { + // If includeAllFieldsByDefault is false, add field to array to include it + if (fieldIndex >= 0) { + // Field exists, just remove exclude property + const fieldConfig = currentFields[fieldIndex]!; + const { exclude: _, ...rest } = fieldConfig; const newFields = [...currentFields]; newFields[fieldIndex] = rest as any; const newTables = [...currentTables]; @@ -311,11 +354,28 @@ export function MetadataFieldsDialog({ setValue(`config.${configIndex}.tables` as any, newTables, { shouldDirty: true, }); + } else { + // Add field to array + const newTables = [...currentTables]; + newTables[tableIndex] = { + ...newTables[tableIndex]!, + fields: [...currentFields, { fieldName }], + }; + setValue(`config.${configIndex}.tables` as any, newTables, { + shouldDirty: true, + }); } } } }, - [configType, configIndex, tableName, allTablesConfig, setValue], + [ + configType, + configIndex, + tableName, + allTablesConfig, + setValue, + topLevelIncludeAllFieldsByDefault, + ], ); // Get the field name for variableName - table should exist due to ensuredTableIndex above @@ -330,6 +390,10 @@ export function MetadataFieldsDialog({ const alwaysOverrideFieldNamesFieldName = `config.${configIndex}.tables.${currentTableIndex >= 0 ? currentTableIndex : 0}.alwaysOverrideFieldNames` as any; + // Get the field name for includeAllFieldsByDefault - table should exist due to ensuredTableIndex above + const includeAllFieldsByDefaultFieldName = + `config.${configIndex}.tables.${currentTableIndex >= 0 ? currentTableIndex : 0}.includeAllFieldsByDefault` as any; + // Helper to set field type override - use ref to avoid dependency on fieldsConfig const setFieldTypeOverride = useCallback( (fieldName: string, typeOverride: string | undefined) => { @@ -444,6 +508,11 @@ export function MetadataFieldsDialog({ [configType, configIndex, tableName, allTablesConfig, setValue], ); + // Get the effective includeAllFieldsByDefault value (table-level override or top-level default) + const effectiveIncludeAllFieldsByDefault = useMemo(() => { + return tableConfig?.includeAllFieldsByDefault ?? topLevelIncludeAllFieldsByDefault ?? true; + }, [tableConfig?.includeAllFieldsByDefault, topLevelIncludeAllFieldsByDefault]); + // Get fields for the selected table const fieldsData = useMemo(() => { if ( @@ -487,7 +556,22 @@ export function MetadataFieldsDialog({ const fieldConfig = Array.isArray(fieldsConfig) ? fieldsConfig.find((f) => f?.fieldName === fieldName) : undefined; - const isExcluded = fieldConfig?.exclude === true; + + // Determine if field is excluded: + // - If explicitly excluded (exclude === true), always exclude + // - If includeAllFieldsByDefault is false, exclude if field is not in fields array + // - Otherwise, include by default + let isExcluded: boolean; + if (fieldConfig?.exclude === true) { + isExcluded = true; + } else if (!effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is false, only include fields explicitly in the array + isExcluded = !fieldConfig; + } else { + // Default behavior: include all unless explicitly excluded + isExcluded = false; + } + const typeOverride = fieldConfig?.typeOverride; const isPrimaryKey = keyFields.includes(fieldName); @@ -522,7 +606,22 @@ export function MetadataFieldsDialog({ const fieldConfig = Array.isArray(fieldsConfig) ? fieldsConfig.find((f) => f?.fieldName === fieldName) : undefined; - const isExcluded = fieldConfig?.exclude === true; + + // Determine if field is excluded: + // - If explicitly excluded (exclude === true), always exclude + // - If includeAllFieldsByDefault is false, exclude if field is not in fields array + // - Otherwise, include by default + let isExcluded: boolean; + if (fieldConfig?.exclude === true) { + isExcluded = true; + } else if (!effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is false, only include fields explicitly in the array + isExcluded = !fieldConfig; + } else { + // Default behavior: include all unless explicitly excluded + isExcluded = false; + } + const typeOverride = fieldConfig?.typeOverride; const isPrimaryKey = keyFields.includes(fieldName); @@ -540,7 +639,7 @@ export function MetadataFieldsDialog({ } return fields; - }, [tableName, parsedMetadata, fieldsConfig]); + }, [tableName, parsedMetadata, fieldsConfig, effectiveIncludeAllFieldsByDefault]); // Check if all fields are included or excluded const allFieldsIncluded = useMemo(() => { @@ -1082,6 +1181,69 @@ export function MetadataFieldsDialog({ ); }} /> + { + const isDefault = field.value === undefined; + const effectiveValue = field.value ?? topLevelIncludeAllFieldsByDefault ?? true; + return ( + + + Include All Fields By Default{" "} + + + + + + + + ); + }} + /> diff --git a/packages/typegen/web/src/components/MetadataTablesEditor.tsx b/packages/typegen/web/src/components/MetadataTablesEditor.tsx index 4983145a..7ff817df 100644 --- a/packages/typegen/web/src/components/MetadataTablesEditor.tsx +++ b/packages/typegen/web/src/components/MetadataTablesEditor.tsx @@ -63,11 +63,23 @@ function FieldCountCell({ name: `config.${configIndex}.tables` as const, }); + // Get the top-level includeAllFieldsByDefault value + const topLevelIncludeAllFieldsByDefault = useWatch({ + control, + name: `config.${configIndex}.includeAllFieldsByDefault` as const, + }); + const tableConfig = Array.isArray(allTablesConfig) ? allTablesConfig.find((t) => t?.tableName === tableName) : undefined; const fieldsConfig = tableConfig?.fields ?? []; + // Get the effective includeAllFieldsByDefault value (table-level override or top-level default) + const effectiveIncludeAllFieldsByDefault = + tableConfig?.includeAllFieldsByDefault ?? + topLevelIncludeAllFieldsByDefault ?? + true; + const fieldCount = useMemo(() => { if (!parsedMetadata?.entitySets || !parsedMetadata?.entityTypes) { return undefined; @@ -94,14 +106,17 @@ function FieldCountCell({ const includedFieldCount = useMemo(() => { if (fieldCount === undefined) return undefined; - // Count excluded fields - const excludedFields = fieldsConfig.filter( - (f) => f?.exclude === true, - ).length; - - // Total fields minus excluded fields - return fieldCount - excludedFields; - }, [fieldCount, fieldsConfig]); + if (effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is true, count all fields minus explicitly excluded ones + const excludedFields = fieldsConfig.filter( + (f) => f?.exclude === true, + ).length; + return fieldCount - excludedFields; + } else { + // If includeAllFieldsByDefault is false, only count fields explicitly in the array that are not excluded + return fieldsConfig.filter((f) => f?.exclude !== true).length; + } + }, [fieldCount, fieldsConfig, effectiveIncludeAllFieldsByDefault]); if (isLoading) { return ; From e04e52aedee9ce197a95a0c5e32bd03238e0a005 Mon Sep 17 00:00:00 2001 From: Eric Luce <37158449+eluce2@users.noreply.github.com> Date: Sat, 20 Dec 2025 08:01:41 -0600 Subject: [PATCH 2/2] refactor MetadataFieldsDialog to improve field handling and includeAllFieldsByDefault logic --- .../src/components/MetadataFieldsDialog.tsx | 191 +++++++++++++----- 1 file changed, 135 insertions(+), 56 deletions(-) diff --git a/packages/typegen/web/src/components/MetadataFieldsDialog.tsx b/packages/typegen/web/src/components/MetadataFieldsDialog.tsx index 62bdcc20..1983cc7b 100644 --- a/packages/typegen/web/src/components/MetadataFieldsDialog.tsx +++ b/packages/typegen/web/src/components/MetadataFieldsDialog.tsx @@ -248,10 +248,7 @@ export function MetadataFieldsDialog({ // If includeAllFieldsByDefault is false, add field to array to include it setValue( `config.${configIndex}.tables` as any, - [ - ...currentTables, - { tableName, fields: [{ fieldName }] }, - ], + [...currentTables, { tableName, fields: [{ fieldName }] }], { shouldDirty: true }, ); } @@ -298,13 +295,18 @@ export function MetadataFieldsDialog({ if (Object.keys(rest).length === 1 && rest.fieldName) { // Only fieldName left, remove entire field entry - const newFields = currentFields.filter((_, i) => i !== fieldIndex); + const newFields = currentFields.filter( + (_, i) => i !== fieldIndex, + ); const newTables = [...currentTables]; - if ( - newFields.length === 0 && - Object.keys(newTables[tableIndex]!).length === 2 - ) { + const table = newTables[tableIndex]!; + const tableKeys = Object.keys(table); + const hasOnlyTableNameAndFields = + tableKeys.length === 2 && + tableKeys.includes("tableName") && + tableKeys.includes("fields"); + if (newFields.length === 0 && hasOnlyTableNameAndFields) { // Only tableName and fields left, remove entire table entry const filteredTables = currentTables.filter( (_, i) => i !== tableIndex, @@ -466,10 +468,13 @@ export function MetadataFieldsDialog({ const newFields = currentFields.filter((_, i) => i !== fieldIndex); const newTables = [...currentTables]; - if ( - newFields.length === 0 && - Object.keys(newTables[tableIndex]!).length === 2 - ) { + const table = newTables[tableIndex]!; + const tableKeys = Object.keys(table); + const hasOnlyTableNameAndFields = + tableKeys.length === 2 && + tableKeys.includes("tableName") && + tableKeys.includes("fields"); + if (newFields.length === 0 && hasOnlyTableNameAndFields) { // Only tableName and fields left, remove entire table entry const filteredTables = currentTables.filter( (_, i) => i !== tableIndex, @@ -510,8 +515,15 @@ export function MetadataFieldsDialog({ // Get the effective includeAllFieldsByDefault value (table-level override or top-level default) const effectiveIncludeAllFieldsByDefault = useMemo(() => { - return tableConfig?.includeAllFieldsByDefault ?? topLevelIncludeAllFieldsByDefault ?? true; - }, [tableConfig?.includeAllFieldsByDefault, topLevelIncludeAllFieldsByDefault]); + return ( + tableConfig?.includeAllFieldsByDefault ?? + topLevelIncludeAllFieldsByDefault ?? + true + ); + }, [ + tableConfig?.includeAllFieldsByDefault, + topLevelIncludeAllFieldsByDefault, + ]); // Get fields for the selected table const fieldsData = useMemo(() => { @@ -556,7 +568,7 @@ export function MetadataFieldsDialog({ const fieldConfig = Array.isArray(fieldsConfig) ? fieldsConfig.find((f) => f?.fieldName === fieldName) : undefined; - + // Determine if field is excluded: // - If explicitly excluded (exclude === true), always exclude // - If includeAllFieldsByDefault is false, exclude if field is not in fields array @@ -571,7 +583,7 @@ export function MetadataFieldsDialog({ // Default behavior: include all unless explicitly excluded isExcluded = false; } - + const typeOverride = fieldConfig?.typeOverride; const isPrimaryKey = keyFields.includes(fieldName); @@ -606,7 +618,7 @@ export function MetadataFieldsDialog({ const fieldConfig = Array.isArray(fieldsConfig) ? fieldsConfig.find((f) => f?.fieldName === fieldName) : undefined; - + // Determine if field is excluded: // - If explicitly excluded (exclude === true), always exclude // - If includeAllFieldsByDefault is false, exclude if field is not in fields array @@ -621,7 +633,7 @@ export function MetadataFieldsDialog({ // Default behavior: include all unless explicitly excluded isExcluded = false; } - + const typeOverride = fieldConfig?.typeOverride; const isPrimaryKey = keyFields.includes(fieldName); @@ -639,7 +651,12 @@ export function MetadataFieldsDialog({ } return fields; - }, [tableName, parsedMetadata, fieldsConfig, effectiveIncludeAllFieldsByDefault]); + }, [ + tableName, + parsedMetadata, + fieldsConfig, + effectiveIncludeAllFieldsByDefault, + ]); // Check if all fields are included or excluded const allFieldsIncluded = useMemo(() => { @@ -659,57 +676,116 @@ export function MetadataFieldsDialog({ (t) => t?.tableName === tableName, ); - if (tableIndex < 0) { - // Table doesn't exist in config, nothing to do - return; - } + // Get effective includeAllFieldsByDefault value + const tableConfig = tableIndex >= 0 ? currentTables[tableIndex] : undefined; + const effectiveIncludeAllFieldsByDefault = + tableConfig?.includeAllFieldsByDefault ?? + topLevelIncludeAllFieldsByDefault ?? + true; - const currentFields = currentTables[tableIndex]?.fields ?? []; + const currentFields = + tableIndex >= 0 ? (currentTables[tableIndex]?.fields ?? []) : []; const allFieldNames = fieldsData.map((f) => f.fieldName); - // Remove exclude flags from all fields - const newFields = currentFields - .map((fieldConfig) => { - const fieldName = fieldConfig?.fieldName; - if (fieldName && allFieldNames.includes(fieldName)) { - const { exclude: _, ...rest } = fieldConfig; - // If only fieldName is left, don't include it - if (Object.keys(rest).length === 1 && rest.fieldName) { - return null; + let newFields: any[]; + let newTables: any[]; + + if (effectiveIncludeAllFieldsByDefault) { + // If includeAllFieldsByDefault is true, remove all field entries (or just remove exclude flags) + // since all fields are included by default + newFields = currentFields + .map((fieldConfig) => { + const fieldName = fieldConfig?.fieldName; + if (fieldName && allFieldNames.includes(fieldName)) { + const { exclude: _, ...rest } = fieldConfig; + // If only fieldName is left, don't include it + if (Object.keys(rest).length === 1 && rest.fieldName) { + return null; + } + return Object.keys(rest).length > 1 ? rest : null; } - return Object.keys(rest).length > 1 ? rest : null; + return fieldConfig; + }) + .filter((f) => f !== null) as any[]; + + newTables = [...currentTables]; + if (tableIndex < 0) { + // Table doesn't exist, but with includeAllFieldsByDefault=true, we don't need to add it + return; + } + + if (newFields.length === 0) { + // No fields left, remove fields array or entire table entry if only tableName and fields + const table = newTables[tableIndex]!; + const tableKeys = Object.keys(table); + const hasOnlyTableNameAndFields = + tableKeys.length === 2 && + tableKeys.includes("tableName") && + tableKeys.includes("fields"); + if (hasOnlyTableNameAndFields) { + const filteredTables = currentTables.filter( + (_, i) => i !== tableIndex, + ); + setValue( + `config.${configIndex}.tables` as any, + filteredTables.length > 0 ? filteredTables : undefined, + { shouldDirty: true }, + ); + } else { + newTables[tableIndex] = { + ...newTables[tableIndex]!, + fields: undefined, + }; + setValue(`config.${configIndex}.tables` as any, newTables, { + shouldDirty: true, + }); + } + } else { + newTables[tableIndex] = { + ...newTables[tableIndex]!, + fields: newFields, + }; + setValue(`config.${configIndex}.tables` as any, newTables, { + shouldDirty: true, + }); + } + } else { + // If includeAllFieldsByDefault is false, add all fields to the array (or ensure they're all there) + // Create a map of existing field configs + const fieldConfigMap = new Map( + currentFields.map((f) => [f?.fieldName, f]), + ); + + // Ensure all fields are in the array without exclude flags + newFields = allFieldNames.map((fieldName) => { + const existing = fieldConfigMap.get(fieldName); + if (existing) { + // Remove exclude flag if present + const { exclude: _, ...rest } = existing; + return rest; } - return fieldConfig; - }) - .filter((f) => f !== null) as any[]; - - const newTables = [...currentTables]; - if (newFields.length === 0) { - // No fields left, remove fields array or entire table entry if only tableName and fields - if (Object.keys(newTables[tableIndex]!).length === 2) { - const filteredTables = currentTables.filter((_, i) => i !== tableIndex); + // Add new field entry + return { fieldName }; + }); + + if (tableIndex < 0) { + // Table doesn't exist, add it with all fields setValue( `config.${configIndex}.tables` as any, - filteredTables.length > 0 ? filteredTables : undefined, + [...currentTables, { tableName, fields: newFields }], { shouldDirty: true }, ); } else { + // Update existing table + newTables = [...currentTables]; newTables[tableIndex] = { ...newTables[tableIndex]!, - fields: undefined, + fields: newFields, }; setValue(`config.${configIndex}.tables` as any, newTables, { shouldDirty: true, }); } - } else { - newTables[tableIndex] = { - ...newTables[tableIndex]!, - fields: newFields, - }; - setValue(`config.${configIndex}.tables` as any, newTables, { - shouldDirty: true, - }); } }, [ configType, @@ -718,6 +794,7 @@ export function MetadataFieldsDialog({ allTablesConfig, setValue, fieldsData, + topLevelIncludeAllFieldsByDefault, ]); // Helper to exclude all fields @@ -1189,7 +1266,8 @@ export function MetadataFieldsDialog({ } render={({ field }) => { const isDefault = field.value === undefined; - const effectiveValue = field.value ?? topLevelIncludeAllFieldsByDefault ?? true; + const effectiveValue = + field.value ?? topLevelIncludeAllFieldsByDefault ?? true; return ( @@ -1228,7 +1306,8 @@ export function MetadataFieldsDialog({ className="italic text-muted-foreground" > Use Top-Level Setting - {isDefault && ` (${effectiveValue ? "Include All" : "Only Explicit"})`} + {isDefault && + ` (${effectiveValue ? "Include All" : "Only Explicit"})`} Include All Fields By Default