diff --git a/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts b/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts index 0c405b0cb38..c60f8707562 100644 --- a/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts +++ b/specifyweb/frontend/js_src/lib/components/Merging/autoMerge.ts @@ -54,6 +54,78 @@ export function autoMerge( ); } +export async function buildInitialMergedResource( + table: SpecifyTable, + resources: RA>, + shouldAutoPopulate: boolean, + targetId?: number +): Promise> { + return ( + shouldAutoPopulate + ? await postMergeResource( + resources, + autoMerge(table, resources, false, targetId) + ) + : addMissingFields( + table.name, + getPreservedFieldsWithoutAutoPopulate(table, resources, targetId) + ) + ) as SerializedResource; +} + +const preservedFieldsWithoutAutoPopulate: Partial< + RR< + keyof Tables, + ( + resources: RA>, + targetId?: number + ) => Partial> + > +> = { + Agent: (resources, targetId) => ({ + agentType: parseNumber( + getSharedNumberFieldValue(resources, 'agentType') ?? + getTargetResource(resources, targetId)?.agentType + ), + }), +}; + +const getPreservedFieldsWithoutAutoPopulate = ( + table: SpecifyTable, + resources: RA>, + targetId?: number +): Partial> => + preservedFieldsWithoutAutoPopulate[table.name]?.(resources, targetId) ?? {}; + +const getTargetResource = ( + resources: RA>, + targetId?: number +): SerializedResource | undefined => + targetId === undefined + ? resources[0] + : (resources.find(({ id }) => id === targetId) ?? resources[0]); + +const getSharedNumberFieldValue = ( + resources: RA>, + fieldName: string +): number | undefined => { + const values = f.unique( + resources + .map((resource) => parseNumber(resource[fieldName])) + .filter((value) => value !== undefined) + ); + return values.length === 1 ? values[0] : undefined; +}; + +const parseNumber = ( + value: boolean | number | string | null | undefined +): number | undefined => + typeof value === 'number' + ? value + : typeof value === 'string' + ? f.parseInt(value) + : undefined; + /** * Sort from newest to oldest */ diff --git a/specifyweb/frontend/js_src/lib/components/Merging/index.tsx b/specifyweb/frontend/js_src/lib/components/Merging/index.tsx index 2c3f280a947..130d9d530fb 100644 --- a/specifyweb/frontend/js_src/lib/components/Merging/index.tsx +++ b/specifyweb/frontend/js_src/lib/components/Merging/index.tsx @@ -22,7 +22,6 @@ import { icons } from '../Atoms/Icons'; import { Link } from '../Atoms/Link'; import { Submit } from '../Atoms/Submit'; import { LoadingContext } from '../Core/Contexts'; -import { addMissingFields } from '../DataModel/addMissingFields'; import { runAllFieldChecks } from '../DataModel/businessRules'; import type { AnySchema, SerializedResource } from '../DataModel/helperTypes'; import type { SpecifyResource } from '../DataModel/legacyTypes'; @@ -35,7 +34,11 @@ import { Dialog, dialogClassNames } from '../Molecules/Dialog'; import { userPreferences } from '../Preferences/userPreferences'; import { formatUrl } from '../Router/queryString'; import { OverlayContext, OverlayLocation } from '../Router/Router'; -import { autoMerge, postMergeResource } from './autoMerge'; +import { + autoMerge, + buildInitialMergedResource, + postMergeResource, +} from './autoMerge'; import { CompareRecords } from './Compare'; import { recordMergingTableSpec } from './definitions'; import { InvalidMergeRecordsDialog } from './InvalidMergeRecords'; @@ -225,15 +228,12 @@ function Merging({ 'autoPopulate' ); - const mergedPayload = shouldAutoPopulate - ? await postMergeResource( - initialRecords.current, - autoMerge(table, initialRecords.current, false, target.id) - ) - : addMissingFields( - table.name, - {} as Partial> - ); + const mergedPayload = await buildInitialMergedResource( + table, + initialRecords.current, + shouldAutoPopulate, + target.id + ); const mergedResource = deserializeResource( mergedPayload as SerializedResource diff --git a/specifyweb/frontend/js_src/lib/hooks/useParserDefaultValue.tsx b/specifyweb/frontend/js_src/lib/hooks/useParserDefaultValue.tsx index 353d957e442..c5f71128221 100644 --- a/specifyweb/frontend/js_src/lib/hooks/useParserDefaultValue.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/useParserDefaultValue.tsx @@ -35,9 +35,12 @@ export function useParserDefaultValue( * Don't auto set numeric to "0", unless it is the default value * in the form definition */ + const parserUsesNumberValue = + parser.type === 'number' || typeof parser.value === 'number'; + const hasDefault = parser.value !== undefined && - (parser.type !== 'number' || parser.value !== 0); + (!parserUsesNumberValue || parser.value !== 0); const fieldValue = resource.get(field.name) as | boolean @@ -54,7 +57,7 @@ export function useParserDefaultValue( * should overwrite that of the resource */ resource.isNew() && - (parser.type !== 'number' || + (!parserUsesNumberValue || typeof fieldValue !== 'number' || fieldValue === 0) && ((parser.type !== 'text' && parser.type !== 'date') ||