From 0d1176ebab298f9c3a7ef8d209a076f1bcb1a123 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:23:53 -0500 Subject: [PATCH 1/3] feat(attachments): handle multiple formats --- .../SelectUploadPath.tsx | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/SelectUploadPath.tsx b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/SelectUploadPath.tsx index 6954dd98726..90e34edfd66 100644 --- a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/SelectUploadPath.tsx +++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/SelectUploadPath.tsx @@ -62,16 +62,28 @@ export function generateUploadSpec( const field = queryFieldSpec.getField(); const queryResultsFormatter = ( value: number | string | null | undefined - ): string | undefined => - value === undefined || value === null || field?.isRelationship === true - ? undefined - : syncFieldFormat( - field, - value.toString(), - queryFieldSpec.parser, - undefined, - true - ); + ): string | undefined => { + if (value === undefined || value === null || field?.isRelationship === true) + return undefined; + + const rawValue = value.toString(); + const fieldFormatter = field?.getUiFormatter(); + if (fieldFormatter !== undefined) + // Catalog number formatting can vary by Collection Object Type. The + // query field only has the schema-level formatter, so preserve database + // values that do not match that formatter instead of dropping them. + return fieldFormatter.format(rawValue) ?? rawValue; + + return ( + syncFieldFormat( + field, + rawValue, + queryFieldSpec.parser, + undefined, + true + ) ?? rawValue + ); + }; return { staticPathKey, formatQueryResults: queryResultsFormatter, From 42768eae0ff1db66e4e6de488d4cf8934500e916 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:24:08 -0500 Subject: [PATCH 2/3] test(attachments): verify format is preserved --- .../__tests__/SelectUploadPath.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/__tests__/SelectUploadPath.test.ts diff --git a/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/__tests__/SelectUploadPath.test.ts b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/__tests__/SelectUploadPath.test.ts new file mode 100644 index 00000000000..551626a52e2 --- /dev/null +++ b/specifyweb/frontend/js_src/lib/components/AttachmentsBulkImport/__tests__/SelectUploadPath.test.ts @@ -0,0 +1,20 @@ +import { requireContext } from '../../../tests/helpers'; +import { generateUploadSpec } from '../SelectUploadPath'; + +requireContext(); + +describe('generateUploadSpec catalog number result formatting', () => { + test('preserves catalog numbers that do not match the schema formatter', () => + expect( + generateUploadSpec('collectionObjectCatalogNumber').formatQueryResults!( + 'F-250750' + ) + ).toBe('F-250750')); + + test('keeps canonical formatting for values accepted by the schema formatter', () => + expect( + generateUploadSpec('collectionObjectCatalogNumber').formatQueryResults!( + '123' + ) + ).toBe('000000123')); +}); From 523b6ef4732891f06bd67d71a31250bed4c5142a Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Thu, 22 Oct 2026 21:28:48 +0000 Subject: [PATCH 3/3] Lint code with ESLint and Prettier Triggered by 7bedf1e4b8eb842b243a583bb17b773c14fb2b6f on branch refs/heads/issue-8653 --- specifyweb/frontend/js_src/lib/components/DataModel/tables.ts | 4 ++-- .../frontend/js_src/lib/hooks/usePaginatedCollection.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts b/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts index da35afb63e8..5826da28fad 100644 --- a/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts +++ b/specifyweb/frontend/js_src/lib/components/DataModel/tables.ts @@ -249,8 +249,8 @@ export const getTableById = ( tableId: number ): SpecifyTable => (Object.values(genericTables).find((table) => table.tableId === tableId) as - SpecifyTable | undefined) ?? - error(`Table with id ${tableId} does not exist`); + | SpecifyTable + | undefined) ?? error(`Table with id ${tableId} does not exist`); // If this is true, then you can use {domainfilter:true} when fetching that table export const hasHierarchyField = (table: SpecifyTable): boolean => diff --git a/specifyweb/frontend/js_src/lib/hooks/usePaginatedCollection.tsx b/specifyweb/frontend/js_src/lib/hooks/usePaginatedCollection.tsx index 8016ff6942f..f4013573cb2 100644 --- a/specifyweb/frontend/js_src/lib/hooks/usePaginatedCollection.tsx +++ b/specifyweb/frontend/js_src/lib/hooks/usePaginatedCollection.tsx @@ -29,9 +29,9 @@ export function usePaginatedCollection({ const [results, setResults] = useTriggerState< RA | undefined >(initialRecords); - + const resultsRef = React.useRef(results); - + const handleSetResults: GetOrSet< RA | undefined >[typeof SET] = React.useCallback(