From 76cfb442a47818144cd75c467799f5e1a906cddc Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 14 Jan 2026 10:44:27 +1100 Subject: [PATCH] [UI] Bug fix for table column reordering (#11131) * [UI] Bug fix for table column reordering - Ref: https://github.com/icflorescu/mantine-datatable/issues/759 - Adds hash to column cache key based on provided columns - Prevent infinite loop for react hooks * Remove previous cache approach * Remove unused code --- src/frontend/src/functions/tables.tsx | 12 +++++++ src/frontend/src/tables/InvenTreeTable.tsx | 31 +++++++------------ .../src/tables/build/BuildOutputTable.tsx | 2 -- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/frontend/src/functions/tables.tsx b/src/frontend/src/functions/tables.tsx index 0abe409b2b..04142f2c5a 100644 --- a/src/frontend/src/functions/tables.tsx +++ b/src/frontend/src/functions/tables.tsx @@ -24,3 +24,15 @@ export function shortenString({ return `${str.slice(0, N)} ... ${str.slice(-N)}`; } + +/** + * Generate a short hash from a long string + */ +export function hashString(str: string): string { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = (hash << 5) - hash + str.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + return hash.toString(36); +} diff --git a/src/frontend/src/tables/InvenTreeTable.tsx b/src/frontend/src/tables/InvenTreeTable.tsx index d262348d82..64d6c93876 100644 --- a/src/frontend/src/tables/InvenTreeTable.tsx +++ b/src/frontend/src/tables/InvenTreeTable.tsx @@ -29,6 +29,7 @@ import { Boundary } from '../components/Boundary'; import { useApi } from '../contexts/ApiContext'; import { extractAvailableFields, mapFields } from '../functions/forms'; import { showApiErrorMessage } from '../functions/notifications'; +import { hashString } from '../functions/tables'; import { useLocalState } from '../states/LocalState'; import { useUserSettingsState } from '../states/SettingsStates'; import { useStoredTableState } from '../states/StoredTableState'; @@ -101,7 +102,7 @@ export function InvenTreeTable>({ // Key used for caching table data const cacheKey = useMemo(() => { - const key: string = `table-${tableState.tableKey}`; + const key: string = `tbl-${tableState.tableKey}`; // Remove anything after (and including) "mantine" const mantineIndex = key.indexOf('-mantine'); @@ -244,6 +245,12 @@ export function InvenTreeTable>({ [tableState.setSelectedRecords] ); + // A hash of the current column configuration + // This is a workaround to fix an issue with mantine-datatable where + // the columns do not update correctly when they are changed dynamically + // Ref: https://github.com/icflorescu/mantine-datatable/issues/759 + const [columnHash, setColumnHash] = useState(''); + // Update column visibility when hiddenColumns change const dataColumns: any = useMemo(() => { let cols: TableColumn[] = columns.filter((col) => col?.hidden != true); @@ -296,6 +303,9 @@ export function InvenTreeTable>({ }); } + const columnNames: string = cols.map((col) => col.accessor).join(','); + setColumnHash(hashString(columnNames)); + return cols; }, [ columns, @@ -328,28 +338,11 @@ export function InvenTreeTable>({ // Final state of the table columns const tableColumns = useDataTableColumns({ - key: cacheKey, + key: `${cacheKey}-${columnHash}`, columns: dataColumns, getInitialValueInEffect: false }); - // Cache the "ordering" of the columns - const dataColumnsOrder: string[] = useMemo(() => { - return dataColumns.map((col: any) => col.accessor); - }, [dataColumns]); - - // Ensure that the "actions" column is always at the end of the list - // This effect is necessary as sometimes the underlying mantine-datatable columns change - useEffect(() => { - // Update the columns order only if it has changed - if ( - JSON.stringify(tableColumns.columnsOrder) != - JSON.stringify(dataColumnsOrder) - ) { - tableColumns.setColumnsOrder(dataColumnsOrder); - } - }, [cacheKey, dataColumnsOrder]); - // Reset the pagination state when the search term changes useEffect(() => { tableState.setPage(1); diff --git a/src/frontend/src/tables/build/BuildOutputTable.tsx b/src/frontend/src/tables/build/BuildOutputTable.tsx index 35f86c6993..7d3921d247 100644 --- a/src/frontend/src/tables/build/BuildOutputTable.tsx +++ b/src/frontend/src/tables/build/BuildOutputTable.tsx @@ -18,7 +18,6 @@ import { } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; import { ActionButton } from '@lib/components/ActionButton'; import { AddItemButton } from '@lib/components/AddItemButton'; @@ -151,7 +150,6 @@ export default function BuildOutputTable({ }: Readonly<{ build: any; refreshBuild: () => void }>) { const api = useApi(); const user = useUserState(); - const navigate = useNavigate(); const table = useTable('build-outputs'); const buildId: number = useMemo(() => {