2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-13 18:45:40 +00:00

[UI] Adjustable column width (#9744)

* Add prop to column def

* Enable resizable columns

* Enable cell wrapping if required

* Tweak CompanyTable

* Remove old setting

* Tweak for PartTable
This commit is contained in:
Oliver
2025-06-07 19:15:33 +10:00
committed by GitHub
parent 638cb23923
commit 4660b9477b
7 changed files with 32 additions and 24 deletions

View File

@ -25,7 +25,6 @@ The *Display Settings* screen shows general display configuration options:
{{ usersetting("PART_SHOW_QUANTITY_IN_FORMS") }}
{{ usersetting("DISPLAY_SCHEDULE_TAB") }}
{{ usersetting("DISPLAY_STOCKTAKE_TAB") }}
{{ usersetting("TABLE_STRING_MAX_LENGTH") }}
{{ usersetting("ENABLE_LAST_BREADCRUMB") }}
### Search Settings

View File

@ -225,12 +225,6 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
'default': True,
'validator': bool,
},
'TABLE_STRING_MAX_LENGTH': {
'name': _('Table String Length'),
'description': _('Maximum length limit for strings displayed in table views'),
'validator': [int, MinValueValidator(0)],
'default': 100,
},
'ENABLE_LAST_BREADCRUMB': {
'name': _('Show Last Breadcrumb'),
'description': _('Show the current page in breadcrumbs'),

View File

@ -56,7 +56,6 @@ export default function UserSettings() {
'PART_SHOW_QUANTITY_IN_FORMS',
'DISPLAY_SCHEDULE_TAB',
'DISPLAY_STOCKTAKE_TAB',
'TABLE_STRING_MAX_LENGTH',
'ENABLE_LAST_BREADCRUMB'
]}
/>

View File

@ -16,6 +16,7 @@ import type { ApiFormFieldType } from '@lib/types/Forms';
* @param filter - A custom filter function
* @param filtering - Whether the column is filterable
* @param width - The width of the column
* @param resizable - Whether the column is resizable (defaults to true)
* @param noWrap - Whether the column should wrap
* @param ellipsis - Whether the column should be ellipsized
* @param textAlign - The text alignment of the column
@ -36,6 +37,7 @@ export type TableColumnProps<T = any> = {
filter?: any;
filtering?: boolean;
width?: number;
resizable?: boolean;
noWrap?: boolean;
ellipsis?: boolean;
textAlign?: 'left' | 'center' | 'right';

View File

@ -9,7 +9,8 @@ import {
DataTable,
type DataTableCellClickHandler,
type DataTableRowExpansionProps,
type DataTableSortStatus
type DataTableSortStatus,
useDataTableColumns
} from 'mantine-datatable';
import type React from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
@ -147,6 +148,19 @@ export function InvenTreeTable<T extends Record<string, any>>({
const navigate = useNavigate();
const { showContextMenu } = useContextMenu();
// Key used for caching table data
const cacheKey = useMemo(() => {
const key: string = `table-${tableState.tableKey}`;
// Remove anything after (and including) "mantine"
const mantineIndex = key.indexOf('-mantine');
if (mantineIndex >= 0) {
return key.substring(0, mantineIndex);
} else {
return key;
}
}, [tableState.tableKey]);
// Construct table filters - note that we can introspect filter labels from column names
const filters: TableFilter[] = useMemo(() => {
return (
@ -164,7 +178,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
// Request OPTIONS data from the API, before we load the table
const tableOptionQuery = useQuery({
enabled: !!url && !tableData,
queryKey: ['options', url, tableState.tableKey, props.enableColumnCaching],
queryKey: ['options', url, cacheKey, props.enableColumnCaching],
retry: 3,
refetchOnMount: true,
gcTime: 5000,
@ -202,8 +216,6 @@ export function InvenTreeTable<T extends Record<string, any>>({
}
});
const cacheKey = tableState.tableKey.replaceAll('-', '');
setFieldNames(names);
setTableColumnNames(cacheKey)(names);
}
@ -230,8 +242,6 @@ export function InvenTreeTable<T extends Record<string, any>>({
return;
}
const cacheKey = tableState.tableKey.replaceAll('-', '');
// First check the local cache
const cachedNames = getTableColumnNames(cacheKey);
@ -242,7 +252,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
}
tableOptionQuery.refetch();
}, [url, props.params, props.enableColumnCaching]);
}, [cacheKey, url, props.params, props.enableColumnCaching]);
// Build table properties based on provided props (and default props)
const tableProps: InvenTreeTableProps<T> = useMemo(() => {
@ -295,7 +305,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
return {
...col,
hidden: hidden,
noWrap: true,
resizable: col.resizable ?? true,
title: col.title ?? fieldNames[col.accessor] ?? `${col.accessor}`
};
});
@ -306,6 +316,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
accessor: '--actions--',
title: ' ',
hidden: false,
resizable: false,
switchable: false,
width: 50,
render: (record: any, index?: number | undefined) => (
@ -342,6 +353,12 @@ export function InvenTreeTable<T extends Record<string, any>>({
);
}
// Final state of the table columns
const tableColumns = useDataTableColumns({
key: cacheKey,
columns: dataColumns
});
// Reset the pagination state when the search term changes
useEffect(() => {
tableState.setPage(1);
@ -759,20 +776,15 @@ export function InvenTreeTable<T extends Record<string, any>>({
enableSelection ? onSelectedRecordsChange : undefined
}
rowExpansion={rowExpansion}
// rowStyle={rowStyleCallback}
fetching={isFetching}
noRecordsText={missingRecordsText}
records={tableState.records}
columns={dataColumns}
storeColumnsKey={cacheKey}
columns={tableColumns.effectiveColumns}
onCellClick={supportsCellClick ? handleCellClick : undefined}
noHeader={tableProps.noHeader ?? false}
defaultColumnProps={{
noWrap: true,
textAlign: 'left',
cellsStyle: () => (theme) => ({
// TODO @SchrodingersGat : Need a better way of handling "wide" cells,
overflow: 'hidden'
})
textAlign: 'left'
}}
onCellContextMenu={
supportsContextMenu ? handleCellContextMenu : undefined

View File

@ -43,6 +43,7 @@ export function CompanyTable({
{
accessor: 'name',
sortable: true,
switchable: false,
render: (record: any) => {
return (
<Group gap='xs' wrap='nowrap'>

View File

@ -35,6 +35,7 @@ function partTableColumns(): TableColumn[] {
title: t`Part`,
sortable: true,
noWrap: true,
switchable: false,
render: (record: any) => PartColumn({ part: record })
},
{