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:
@ -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
|
||||
|
@ -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'),
|
||||
|
@ -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'
|
||||
]}
|
||||
/>
|
||||
|
@ -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';
|
||||
|
@ -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
|
||||
|
@ -43,6 +43,7 @@ export function CompanyTable({
|
||||
{
|
||||
accessor: 'name',
|
||||
sortable: true,
|
||||
switchable: false,
|
||||
render: (record: any) => {
|
||||
return (
|
||||
<Group gap='xs' wrap='nowrap'>
|
||||
|
@ -35,6 +35,7 @@ function partTableColumns(): TableColumn[] {
|
||||
title: t`Part`,
|
||||
sortable: true,
|
||||
noWrap: true,
|
||||
switchable: false,
|
||||
render: (record: any) => PartColumn({ part: record })
|
||||
},
|
||||
{
|
||||
|
Reference in New Issue
Block a user