diff --git a/specifyweb/frontend/js_src/lib/components/FormCells/FormTable.tsx b/specifyweb/frontend/js_src/lib/components/FormCells/FormTable.tsx index baf13a48768..ed0f9728cf5 100644 --- a/specifyweb/frontend/js_src/lib/components/FormCells/FormTable.tsx +++ b/specifyweb/frontend/js_src/lib/components/FormCells/FormTable.tsx @@ -9,7 +9,7 @@ import { f } from '../../utils/functools'; import type { IR, RA } from '../../utils/types'; import { sortFunction } from '../../utils/utils'; import { Button } from '../Atoms/Button'; -import { columnDefinitionsToCss, DataEntry } from '../Atoms/DataEntry'; +import { DataEntry } from '../Atoms/DataEntry'; import { icons } from '../Atoms/Icons'; import { Link } from '../Atoms/Link'; import { useAttachment } from '../Attachments/Plugin'; @@ -41,6 +41,10 @@ import { AttachmentPluginSkeleton } from '../SkeletonLoaders/AttachmentPlugin'; import { relationshipIsToMany } from '../WbPlanView/mappingHelpers'; import { COJODialog } from './COJODialog'; import { FormCell } from './index'; +import { + FormTableColumnResizeHandle, + useFormTableColumns, +} from './useFormTableColumns'; const cellToLabel = ( table: SpecifyTable, @@ -59,7 +63,7 @@ const cellToLabel = ( }); const cellClassName = - 'sticky top-0 bg-[color:var(--form-foreground)] z-10 h-full -mx-1 pl-1 pt-1'; + 'sticky top-0 bg-[color:var(--form-foreground)] z-10 h-full -mx-1 px-1 py-1 border-b border-gray-500'; // REFACTOR: split this component into smaller /** @@ -111,17 +115,20 @@ export function FormTable({ } ); - const resources = - sortConfig === undefined - ? // Note, resources might be sorted by the back-end - unsortedResources - : Array.from(unsortedResources).sort( - sortFunction( - // FEATURE: handle related fields - (resource) => resource.get(sortConfig.sortField), - !sortConfig.ascending - ) - ); + const resources = React.useMemo( + () => + sortConfig === undefined + ? // Note, resources might be sorted by the back-end + unsortedResources + : Array.from(unsortedResources).sort( + sortFunction( + // FEATURE: handle related fields + (resource) => resource.get(sortConfig.sortField), + !sortConfig.ascending + ) + ), + [sortConfig, unsortedResources] + ); // When added a new resource, focus that row const addedResource = React.useRef | undefined>( @@ -243,10 +250,22 @@ export function FormTable({ mode !== 'view' && typeof handleDelete === 'function'; const displayViewButton = !isDependent; - const scrollerRef = React.useRef(null); + const columnSizing = useFormTableColumns({ + flexibleSubGridColumnWidth, + hasResources: resources.length > 0, + isCollapsed, + measurementKey: unsortedResources, + sortConfig, + viewDefinition: collapsedViewDefinition, + }); + const { + gridRef: scrollerRef, + gridTemplateColumns, + scrollContainerRef, + } = columnSizing; const { isFetching, handleScroll } = useInfiniteScroll( handleFetchMore, - scrollerRef + scrollContainerRef ); const [maxHeight] = userPreferences.use('form', 'formTable', 'maxHeight'); @@ -290,23 +309,22 @@ export function FormTable({ isCollapsed ? 'hidden' : showSubviewBorders - ? 'overflow-x-auto border border-gray-500 border-t-0 rounded-b pl-1 pr-1 pb-1' - : 'overflow-x-auto pl-1 pr-1 pb-1' + ? 'overflow-auto border border-gray-500 border-t-0 rounded-b pl-1 pr-1 pb-1' + : 'overflow-auto pl-1 pr-1 pb-1' } + ref={scrollContainerRef} + style={{ maxHeight: `${maxHeight}px` }} onScroll={handleScroll} > @@ -322,6 +340,7 @@ export function FormTable({ {commonText.expand()} {collapsedViewDefinition.rows[0].map((cell, index) => { + const columnIndex = index; const { text, title } = cellToLabel( relationship.relatedTable, cell @@ -331,12 +350,27 @@ export function FormTable({ const fieldName = isSortable ? cell.fieldNames?.join(backboneFieldSeparator) : undefined; + const label = ( + + {text} + + ); return ( ({ > {isSortable && typeof fieldName === 'string' ? ( setSortConfig({ sortField: fieldName, @@ -351,18 +386,30 @@ export function FormTable({ }) } > - {text} - + {label} + + + ) : ( - text + label )} + ); })} +