mirror of
https://github.com/inventree/InvenTree.git
synced 2026-01-28 17:13:44 +00:00
[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
This commit is contained in:
@@ -24,3 +24,15 @@ export function shortenString({
|
|||||||
|
|
||||||
return `${str.slice(0, N)} ... ${str.slice(-N)}`;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { Boundary } from '../components/Boundary';
|
|||||||
import { useApi } from '../contexts/ApiContext';
|
import { useApi } from '../contexts/ApiContext';
|
||||||
import { extractAvailableFields, mapFields } from '../functions/forms';
|
import { extractAvailableFields, mapFields } from '../functions/forms';
|
||||||
import { showApiErrorMessage } from '../functions/notifications';
|
import { showApiErrorMessage } from '../functions/notifications';
|
||||||
|
import { hashString } from '../functions/tables';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useUserSettingsState } from '../states/SettingsStates';
|
import { useUserSettingsState } from '../states/SettingsStates';
|
||||||
import { useStoredTableState } from '../states/StoredTableState';
|
import { useStoredTableState } from '../states/StoredTableState';
|
||||||
@@ -101,7 +102,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
|
|
||||||
// Key used for caching table data
|
// Key used for caching table data
|
||||||
const cacheKey = useMemo(() => {
|
const cacheKey = useMemo(() => {
|
||||||
const key: string = `table-${tableState.tableKey}`;
|
const key: string = `tbl-${tableState.tableKey}`;
|
||||||
|
|
||||||
// Remove anything after (and including) "mantine"
|
// Remove anything after (and including) "mantine"
|
||||||
const mantineIndex = key.indexOf('-mantine');
|
const mantineIndex = key.indexOf('-mantine');
|
||||||
@@ -244,6 +245,12 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
[tableState.setSelectedRecords]
|
[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<string>('');
|
||||||
|
|
||||||
// Update column visibility when hiddenColumns change
|
// Update column visibility when hiddenColumns change
|
||||||
const dataColumns: any = useMemo(() => {
|
const dataColumns: any = useMemo(() => {
|
||||||
let cols: TableColumn[] = columns.filter((col) => col?.hidden != true);
|
let cols: TableColumn[] = columns.filter((col) => col?.hidden != true);
|
||||||
@@ -296,6 +303,9 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const columnNames: string = cols.map((col) => col.accessor).join(',');
|
||||||
|
setColumnHash(hashString(columnNames));
|
||||||
|
|
||||||
return cols;
|
return cols;
|
||||||
}, [
|
}, [
|
||||||
columns,
|
columns,
|
||||||
@@ -328,28 +338,11 @@ export function InvenTreeTable<T extends Record<string, any>>({
|
|||||||
|
|
||||||
// Final state of the table columns
|
// Final state of the table columns
|
||||||
const tableColumns = useDataTableColumns({
|
const tableColumns = useDataTableColumns({
|
||||||
key: cacheKey,
|
key: `${cacheKey}-${columnHash}`,
|
||||||
columns: dataColumns,
|
columns: dataColumns,
|
||||||
getInitialValueInEffect: false
|
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
|
// Reset the pagination state when the search term changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tableState.setPage(1);
|
tableState.setPage(1);
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { ActionButton } from '@lib/components/ActionButton';
|
import { ActionButton } from '@lib/components/ActionButton';
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||||
@@ -151,7 +150,6 @@ export default function BuildOutputTable({
|
|||||||
}: Readonly<{ build: any; refreshBuild: () => void }>) {
|
}: Readonly<{ build: any; refreshBuild: () => void }>) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
const navigate = useNavigate();
|
|
||||||
const table = useTable('build-outputs');
|
const table = useTable('build-outputs');
|
||||||
|
|
||||||
const buildId: number = useMemo(() => {
|
const buildId: number = useMemo(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user