2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Dynamic filters (#9290)

* Add attributes to TableFilter type def

* Refactoring

* Refactor ProjectCodeFilter

* Provide simple string rendering of a dynamic filter

* Refactor ResponsibleFilter

* Further refactoring

* More refactoring

* Fix placeholder value
This commit is contained in:
Oliver 2025-03-13 13:09:37 +11:00 committed by GitHub
parent 7a43c3a83e
commit b25bf5e669
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 153 additions and 209 deletions

View File

@ -6,9 +6,7 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useApi } from '../contexts/ApiContext'; import { useApi } from '../contexts/ApiContext';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import { resolveItem } from '../functions/conversion'; import { resolveItem } from '../functions/conversion';
import { apiUrl } from '../states/ApiState';
import type { TableFilterChoice } from '../tables/Filter'; import type { TableFilterChoice } from '../tables/Filter';
type UseFilterProps = { type UseFilterProps = {
@ -67,42 +65,3 @@ export function useFilters(props: UseFilterProps) {
refresh refresh
}; };
} }
// Provide list of project code filters
export function useProjectCodeFilters() {
return useFilters({
url: apiUrl(ApiEndpoints.project_code_list),
transform: (item) => ({
value: item.pk,
label: item.code
})
});
}
// Provide list of user filters
export function useUserFilters() {
return useFilters({
url: apiUrl(ApiEndpoints.user_list),
params: {
is_active: true
},
transform: (item) => ({
value: item.pk,
label: item.username
})
});
}
// Provide list of owner filters
export function useOwnerFilters() {
return useFilters({
url: apiUrl(ApiEndpoints.owner_list),
params: {
is_active: true
},
transform: (item) => ({
value: item.pk,
label: item.name
})
});
}

View File

@ -4,7 +4,9 @@ import type {
StatusCodeInterface, StatusCodeInterface,
StatusCodeListInterface StatusCodeListInterface
} from '../components/render/StatusRenderer'; } from '../components/render/StatusRenderer';
import type { ModelType } from '../enums/ModelType'; import { ApiEndpoints } from '../enums/ApiEndpoints';
import { ModelType } from '../enums/ModelType';
import { apiUrl } from '../states/ApiState';
import { useGlobalSettingsState } from '../states/SettingsState'; import { useGlobalSettingsState } from '../states/SettingsState';
import { type StatusLookup, useGlobalStatusState } from '../states/StatusState'; import { type StatusLookup, useGlobalStatusState } from '../states/StatusState';
@ -23,8 +25,9 @@ export type TableFilterChoice = {
* choice: A filter which allows selection from a list of (supplied) * choice: A filter which allows selection from a list of (supplied)
* date: A filter which allows selection from a date input * date: A filter which allows selection from a date input
* text: A filter which allows raw text input * text: A filter which allows raw text input
* api: A filter which fetches its options from an API endpoint
*/ */
export type TableFilterType = 'boolean' | 'choice' | 'date' | 'text'; export type TableFilterType = 'boolean' | 'choice' | 'date' | 'text' | 'api';
/** /**
* Interface for the table filter type. Provides a number of options for selecting filter value: * Interface for the table filter type. Provides a number of options for selecting filter value:
@ -39,6 +42,9 @@ export type TableFilterType = 'boolean' | 'choice' | 'date' | 'text';
* value: The current value of the filter * value: The current value of the filter
* displayValue: The current display value of the filter * displayValue: The current display value of the filter
* active: Whether the filter is active (false = hidden, not used) * active: Whether the filter is active (false = hidden, not used)
* apiUrl: The API URL to use for fetching dynamic filter options
* model: The model type to use for fetching dynamic filter options
* modelRenderer: A function to render a simple text version of the model type
*/ */
export type TableFilter = { export type TableFilter = {
name: string; name: string;
@ -51,6 +57,9 @@ export type TableFilter = {
value?: any; value?: any;
displayValue?: any; displayValue?: any;
active?: boolean; active?: boolean;
apiUrl?: string;
model?: ModelType;
modelRenderer?: (instance: any) => string;
}; };
/** /**
@ -247,9 +256,7 @@ export function OrderStatusFilter({
}; };
} }
export function ProjectCodeFilter({ export function ProjectCodeFilter(): TableFilter {
choices
}: { choices: TableFilterChoice[] }): TableFilter {
const globalSettings = useGlobalSettingsState.getState(); const globalSettings = useGlobalSettingsState.getState();
const enabled = globalSettings.isSet('PROJECT_CODES_ENABLED', true); const enabled = globalSettings.isSet('PROJECT_CODES_ENABLED', true);
@ -258,28 +265,73 @@ export function ProjectCodeFilter({
label: t`Project Code`, label: t`Project Code`,
description: t`Filter by project code`, description: t`Filter by project code`,
active: enabled, active: enabled,
choices: choices type: 'api',
apiUrl: apiUrl(ApiEndpoints.project_code_list),
model: ModelType.projectcode,
modelRenderer: (instance) => instance.code
}; };
} }
export function ResponsibleFilter({ export function OwnerFilter({
choices name,
}: { choices: TableFilterChoice[] }): TableFilter { label,
description
}: {
name: string;
label: string;
description: string;
}): TableFilter {
return { return {
name: name,
label: label,
description: description,
type: 'api',
apiUrl: apiUrl(ApiEndpoints.owner_list),
model: ModelType.owner,
modelRenderer: (instance: any) => instance.name
};
}
export function ResponsibleFilter(): TableFilter {
return OwnerFilter({
name: 'assigned_to', name: 'assigned_to',
label: t`Responsible`, label: t`Responsible`,
description: t`Filter by responsible owner`, description: t`Filter by responsible owner`
choices: choices });
}
export function UserFilter({
name,
label,
description
}: {
name?: string;
label?: string;
description?: string;
}): TableFilter {
return {
name: name ?? 'user',
label: label ?? t`User`,
description: description ?? t`Filter by user`,
type: 'api',
apiUrl: apiUrl(ApiEndpoints.user_list),
model: ModelType.user,
modelRenderer: (instance: any) => instance.username
}; };
} }
export function CreatedByFilter({ export function CreatedByFilter(): TableFilter {
choices return UserFilter({
}: { choices: TableFilterChoice[] }): TableFilter {
return {
name: 'created_by', name: 'created_by',
label: t`Created By`, label: t`Created By`,
description: t`Filter by user who created the order`, description: t`Filter by user who created the order`
choices: choices });
}; }
export function IssuedByFilter(): TableFilter {
return UserFilter({
name: 'issued_by',
label: t`Issued By`,
description: t`Filter by user who issued the order`
});
} }

View File

@ -19,6 +19,7 @@ import dayjs from 'dayjs';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { IconCheck } from '@tabler/icons-react'; import { IconCheck } from '@tabler/icons-react';
import { StandaloneField } from '../components/forms/StandaloneField';
import { StylishText } from '../components/items/StylishText'; import { StylishText } from '../components/items/StylishText';
import type { TableState } from '../hooks/UseTable'; import type { TableState } from '../hooks/UseTable';
import { import {
@ -64,13 +65,15 @@ function FilterItem({
} }
function FilterElement({ function FilterElement({
filterType, filterName,
filterProps,
valueOptions, valueOptions,
onValueChange onValueChange
}: { }: {
filterType: TableFilterType; filterName: string;
filterProps: TableFilter;
valueOptions: TableFilterChoice[]; valueOptions: TableFilterChoice[];
onValueChange: (value: string | null) => void; onValueChange: (value: string | null, displayValue?: any) => void;
}) { }) {
const setDateValue = useCallback( const setDateValue = useCallback(
(value: DateValue) => { (value: DateValue) => {
@ -86,7 +89,23 @@ function FilterElement({
const [textValue, setTextValue] = useState<string>(''); const [textValue, setTextValue] = useState<string>('');
switch (filterType) { switch (filterProps.type) {
case 'api':
return (
<StandaloneField
fieldName={`filter_value_${filterName}`}
fieldDefinition={{
field_type: 'related field',
api_url: filterProps.apiUrl,
placeholder: t`Select filter value`,
model: filterProps.model,
label: t`Select filter value`,
onValueChange: (value: any, instance: any) => {
onValueChange(value, filterProps.modelRenderer?.(instance));
}
}}
/>
);
case 'text': case 'text':
return ( return (
<TextInput <TextInput
@ -124,7 +143,7 @@ function FilterElement({
return ( return (
<Select <Select
data={valueOptions} data={valueOptions}
searchable={filterType != 'boolean'} searchable={filterProps.type == 'choice'}
label={t`Value`} label={t`Value`}
placeholder={t`Select filter value`} placeholder={t`Select filter value`}
onChange={(value: string | null) => onValueChange(value)} onChange={(value: string | null) => onValueChange(value)}
@ -177,23 +196,32 @@ function FilterAddGroup({
return getTableFilterOptions(filter); return getTableFilterOptions(filter);
}, [selectedFilter]); }, [selectedFilter]);
// Determine the "type" of filter (default = boolean) // Determine the filter "type" - if it is not supplied
const filterType: TableFilterType = useMemo(() => { const getFilterType = (filter: TableFilter): TableFilterType => {
const filter = availableFilters?.find((flt) => flt.name === selectedFilter); if (filter.type) {
if (filter?.type) {
return filter.type; return filter.type;
} else if (filter?.choices) { } else if (filter.apiUrl && filter.model) {
// If choices are provided, it is a choice filter return 'api';
} else if (filter.choices || filter.choiceFunction) {
return 'choice'; return 'choice';
} else { } else {
// Default fallback
return 'boolean'; return 'boolean';
} }
}, [selectedFilter]); };
// Extract filter definition
const filterProps: TableFilter | undefined = useMemo(() => {
const filter = availableFilters?.find((flt) => flt.name === selectedFilter);
if (filter) {
filter.type = getFilterType(filter);
}
return filter;
}, [availableFilters, selectedFilter]);
const setSelectedValue = useCallback( const setSelectedValue = useCallback(
(value: string | null) => { (value: string | null, displayValue?: any) => {
// Find the matching filter // Find the matching filter
const filter: TableFilter | undefined = availableFilters.find( const filter: TableFilter | undefined = availableFilters.find(
(flt) => flt.name === selectedFilter (flt) => flt.name === selectedFilter
@ -211,7 +239,8 @@ function FilterAddGroup({
const newFilter: TableFilter = { const newFilter: TableFilter = {
...filter, ...filter,
value: value, value: value,
displayValue: valueOptions.find((v) => v.value === value)?.label displayValue:
displayValue ?? valueOptions.find((v) => v.value === value)?.label
}; };
tableState.setActiveFilters([...filters, newFilter]); tableState.setActiveFilters([...filters, newFilter]);
@ -233,9 +262,10 @@ function FilterAddGroup({
onChange={(value: string | null) => setSelectedFilter(value)} onChange={(value: string | null) => setSelectedFilter(value)}
maxDropdownHeight={800} maxDropdownHeight={800}
/> />
{selectedFilter && ( {selectedFilter && filterProps && (
<FilterElement <FilterElement
filterType={filterType} filterName={selectedFilter}
filterProps={filterProps}
valueOptions={valueOptions} valueOptions={valueOptions}
onValueChange={setSelectedValue} onValueChange={setSelectedValue}
/> />

View File

@ -8,13 +8,6 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useBuildOrderFields } from '../../forms/BuildForms'; import { useBuildOrderFields } from '../../forms/BuildForms';
import { shortenString } from '../../functions/tables';
import {
useFilters,
useOwnerFilters,
useProjectCodeFilters,
useUserFilters
} from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -37,6 +30,7 @@ import {
CreatedAfterFilter, CreatedAfterFilter,
CreatedBeforeFilter, CreatedBeforeFilter,
HasProjectCodeFilter, HasProjectCodeFilter,
IssuedByFilter,
MaxDateFilter, MaxDateFilter,
MinDateFilter, MinDateFilter,
OrderStatusFilter, OrderStatusFilter,
@ -128,21 +122,6 @@ export function BuildOrderTable({
]; ];
}, [parentBuildId]); }, [parentBuildId]);
const projectCodeFilters = useProjectCodeFilters();
const ownerFilters = useOwnerFilters();
const userFilters = useUserFilters();
const categoryFilters = useFilters({
url: apiUrl(ApiEndpoints.category_list),
transform: (item) => ({
value: item.pk,
label: shortenString({
str: item.pathstring,
len: 50
})
})
});
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
const filters: TableFilter[] = [ const filters: TableFilter[] = [
OutstandingFilter(), OutstandingFilter(),
@ -171,20 +150,17 @@ export function BuildOrderTable({
}, },
CompletedBeforeFilter(), CompletedBeforeFilter(),
CompletedAfterFilter(), CompletedAfterFilter(),
ProjectCodeFilter({ choices: projectCodeFilters.choices }), ProjectCodeFilter(),
HasProjectCodeFilter(), HasProjectCodeFilter(),
{ IssuedByFilter(),
name: 'issued_by', ResponsibleFilter(),
label: t`Issued By`,
description: t`Filter by user who issued this order`,
choices: userFilters.choices
},
ResponsibleFilter({ choices: ownerFilters.choices }),
{ {
name: 'category', name: 'category',
label: t`Category`, label: t`Category`,
description: t`Filter by part category`, description: t`Filter by part category`,
choices: categoryFilters.choices apiUrl: apiUrl(ApiEndpoints.category_list),
model: ModelType.partcategory,
modelRenderer: (instance: any) => instance.name
} }
]; ];
@ -199,13 +175,7 @@ export function BuildOrderTable({
} }
return filters; return filters;
}, [ }, [partId]);
partId,
categoryFilters.choices,
projectCodeFilters.choices,
ownerFilters.choices,
userFilters.choices
]);
const user = useUserState(); const user = useUserState();

View File

@ -8,11 +8,6 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { usePurchaseOrderFields } from '../../forms/PurchaseOrderForms'; import { usePurchaseOrderFields } from '../../forms/PurchaseOrderForms';
import {
useOwnerFilters,
useProjectCodeFilters,
useUserFilters
} from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -66,10 +61,6 @@ export function PurchaseOrderTable({
const table = useTable('purchase-order'); const table = useTable('purchase-order');
const user = useUserState(); const user = useUserState();
const projectCodeFilters = useProjectCodeFilters();
const responsibleFilters = useOwnerFilters();
const createdByFilters = useUserFilters();
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
return [ return [
OrderStatusFilter({ model: ModelType.purchaseorder }), OrderStatusFilter({ model: ModelType.purchaseorder }),
@ -98,16 +89,12 @@ export function PurchaseOrderTable({
}, },
CompletedBeforeFilter(), CompletedBeforeFilter(),
CompletedAfterFilter(), CompletedAfterFilter(),
ProjectCodeFilter({ choices: projectCodeFilters.choices }), ProjectCodeFilter(),
HasProjectCodeFilter(), HasProjectCodeFilter(),
ResponsibleFilter({ choices: responsibleFilters.choices }), ResponsibleFilter(),
CreatedByFilter({ choices: createdByFilters.choices }) CreatedByFilter()
]; ];
}, [ }, []);
projectCodeFilters.choices,
responsibleFilters.choices,
createdByFilters.choices
]);
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {
return [ return [

View File

@ -8,11 +8,6 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useReturnOrderFields } from '../../forms/ReturnOrderForms'; import { useReturnOrderFields } from '../../forms/ReturnOrderForms';
import {
useOwnerFilters,
useProjectCodeFilters,
useUserFilters
} from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -63,10 +58,6 @@ export function ReturnOrderTable({
const table = useTable(!!partId ? 'returnorders-part' : 'returnorders-index'); const table = useTable(!!partId ? 'returnorders-part' : 'returnorders-index');
const user = useUserState(); const user = useUserState();
const projectCodeFilters = useProjectCodeFilters();
const responsibleFilters = useOwnerFilters();
const createdByFilters = useUserFilters();
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
const filters: TableFilter[] = [ const filters: TableFilter[] = [
OrderStatusFilter({ model: ModelType.returnorder }), OrderStatusFilter({ model: ModelType.returnorder }),
@ -96,9 +87,9 @@ export function ReturnOrderTable({
CompletedBeforeFilter(), CompletedBeforeFilter(),
CompletedAfterFilter(), CompletedAfterFilter(),
HasProjectCodeFilter(), HasProjectCodeFilter(),
ProjectCodeFilter({ choices: projectCodeFilters.choices }), ProjectCodeFilter(),
ResponsibleFilter({ choices: responsibleFilters.choices }), ResponsibleFilter(),
CreatedByFilter({ choices: createdByFilters.choices }) CreatedByFilter()
]; ];
if (!!partId) { if (!!partId) {
@ -111,12 +102,7 @@ export function ReturnOrderTable({
} }
return filters; return filters;
}, [ }, [partId]);
partId,
projectCodeFilters.choices,
responsibleFilters.choices,
createdByFilters.choices
]);
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {
return [ return [

View File

@ -9,11 +9,6 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useSalesOrderFields } from '../../forms/SalesOrderForms'; import { useSalesOrderFields } from '../../forms/SalesOrderForms';
import {
useOwnerFilters,
useProjectCodeFilters,
useUserFilters
} from '../../hooks/UseFilter';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -64,10 +59,6 @@ export function SalesOrderTable({
const table = useTable(!!partId ? 'salesorder-part' : 'salesorder-index'); const table = useTable(!!partId ? 'salesorder-part' : 'salesorder-index');
const user = useUserState(); const user = useUserState();
const projectCodeFilters = useProjectCodeFilters();
const responsibleFilters = useOwnerFilters();
const createdByFilters = useUserFilters();
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
const filters: TableFilter[] = [ const filters: TableFilter[] = [
OrderStatusFilter({ model: ModelType.salesorder }), OrderStatusFilter({ model: ModelType.salesorder }),
@ -97,9 +88,9 @@ export function SalesOrderTable({
CompletedBeforeFilter(), CompletedBeforeFilter(),
CompletedAfterFilter(), CompletedAfterFilter(),
HasProjectCodeFilter(), HasProjectCodeFilter(),
ProjectCodeFilter({ choices: projectCodeFilters.choices }), ProjectCodeFilter(),
ResponsibleFilter({ choices: responsibleFilters.choices }), ResponsibleFilter(),
CreatedByFilter({ choices: createdByFilters.choices }) CreatedByFilter()
]; ];
if (!!partId) { if (!!partId) {
@ -112,12 +103,7 @@ export function SalesOrderTable({
} }
return filters; return filters;
}, [ }, [partId]);
partId,
projectCodeFilters.choices,
responsibleFilters.choices,
createdByFilters.choices
]);
const salesOrderFields = useSalesOrderFields({}); const salesOrderFields = useSalesOrderFields({});

View File

@ -21,14 +21,13 @@ import { RenderUser } from '../../components/render/User';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { shortenString } from '../../functions/tables'; import { shortenString } from '../../functions/tables';
import { useUserFilters } from '../../hooks/UseFilter';
import { useDeleteApiFormModal } from '../../hooks/UseForm'; import { useDeleteApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useGlobalSettingsState } from '../../states/SettingsState'; import { useGlobalSettingsState } from '../../states/SettingsState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import type { TableColumn } from '../Column'; import type { TableColumn } from '../Column';
import type { TableFilter } from '../Filter'; import { type TableFilter, UserFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction } from '../RowActions'; import { RowDeleteAction } from '../RowActions';
@ -148,8 +147,6 @@ export default function BarcodeScanHistoryTable() {
const globalSettings = useGlobalSettingsState(); const globalSettings = useGlobalSettingsState();
const userFilters = useUserFilters();
const [opened, { open, close }] = useDisclosure(false); const [opened, { open, close }] = useDisclosure(false);
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
@ -204,19 +201,14 @@ export default function BarcodeScanHistoryTable() {
const filters: TableFilter[] = useMemo(() => { const filters: TableFilter[] = useMemo(() => {
return [ return [
{ UserFilter({}),
name: 'user',
label: t`User`,
choices: userFilters.choices,
description: t`Filter by user`
},
{ {
name: 'result', name: 'result',
label: t`Result`, label: t`Result`,
description: t`Filter by result` description: t`Filter by result`
} }
]; ];
}, [userFilters]); }, []);
const canDelete: boolean = useMemo(() => { const canDelete: boolean = useMemo(() => {
return user.isStaff() && user.hasDeleteRole(UserRoles.admin); return user.isStaff() && user.hasDeleteRole(UserRoles.admin);

View File

@ -9,7 +9,7 @@ import { RenderUser } from '../../components/render/User';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { dataImporterSessionFields } from '../../forms/ImporterForms'; import { dataImporterSessionFields } from '../../forms/ImporterForms';
import { useFilters, useUserFilters } from '../../hooks/UseFilter'; import { useFilters } from '../../hooks/UseFilter';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal useDeleteApiFormModal
@ -18,7 +18,7 @@ import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import type { TableColumn } from '../Column'; import type { TableColumn } from '../Column';
import { DateColumn, StatusColumn } from '../ColumnRenderers'; import { DateColumn, StatusColumn } from '../ColumnRenderers';
import { StatusFilterOptions, type TableFilter } from '../Filter'; import { StatusFilterOptions, type TableFilter, UserFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { type RowAction, RowDeleteAction } from '../RowActions'; import { type RowAction, RowDeleteAction } from '../RowActions';
@ -88,8 +88,6 @@ export default function ImportSesssionTable() {
]; ];
}, []); }, []);
const userFilter = useUserFilters();
const modelTypeFilters = useFilters({ const modelTypeFilters = useFilters({
url: apiUrl(ApiEndpoints.import_session_list), url: apiUrl(ApiEndpoints.import_session_list),
method: 'OPTIONS', method: 'OPTIONS',
@ -116,14 +114,9 @@ export default function ImportSesssionTable() {
description: t`Filter by import session status`, description: t`Filter by import session status`,
choiceFunction: StatusFilterOptions(ModelType.importsession) choiceFunction: StatusFilterOptions(ModelType.importsession)
}, },
{ UserFilter({})
name: 'user',
label: t`User`,
description: t`Filter by user`,
choices: userFilter.choices
}
]; ];
}, [modelTypeFilters.choices, userFilter.choices]); }, [modelTypeFilters.choices]);
const tableActions = useMemo(() => { const tableActions = useMemo(() => {
return [ return [

View File

@ -8,7 +8,6 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { stockLocationFields } from '../../forms/StockForms'; import { stockLocationFields } from '../../forms/StockForms';
import { useFilters } from '../../hooks/UseFilter';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useEditApiFormModal useEditApiFormModal
@ -29,14 +28,6 @@ export function StockLocationTable({ parentId }: Readonly<{ parentId?: any }>) {
const table = useTable('stocklocation'); const table = useTable('stocklocation');
const user = useUserState(); const user = useUserState();
const locationTypeFilters = useFilters({
url: apiUrl(ApiEndpoints.stock_location_type_list),
transform: (item) => ({
value: item.pk,
label: item.name
})
});
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
return [ return [
{ {
@ -62,10 +53,12 @@ export function StockLocationTable({ parentId }: Readonly<{ parentId?: any }>) {
name: 'location_type', name: 'location_type',
label: t`Location Type`, label: t`Location Type`,
description: t`Filter by location type`, description: t`Filter by location type`,
choices: locationTypeFilters.choices apiUrl: apiUrl(ApiEndpoints.stock_location_type_list),
model: ModelType.stocklocationtype,
modelRenderer: (instance: any) => instance.name
} }
]; ];
}, [locationTypeFilters.choices]); }, []);
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [

View File

@ -19,12 +19,11 @@ import {
import { RenderUser } from '../../components/render/User'; import { RenderUser } from '../../components/render/User';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { useUserFilters } from '../../hooks/UseFilter';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import type { TableColumn } from '../Column'; import type { TableColumn } from '../Column';
import { DateColumn, DescriptionColumn } from '../ColumnRenderers'; import { DateColumn, DescriptionColumn } from '../ColumnRenderers';
import type { TableFilter } from '../Filter'; import { type TableFilter, UserFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
type StockTrackingEntry = { type StockTrackingEntry = {
@ -37,8 +36,6 @@ export function StockTrackingTable({ itemId }: Readonly<{ itemId: number }>) {
const navigate = useNavigate(); const navigate = useNavigate();
const table = useTable('stock_tracking'); const table = useTable('stock_tracking');
const userFilters = useUserFilters();
// Render "details" for a stock tracking record // Render "details" for a stock tracking record
const renderDetails = useCallback( const renderDetails = useCallback(
(record: any) => { (record: any) => {
@ -186,14 +183,13 @@ export function StockTrackingTable({ itemId }: Readonly<{ itemId: number }>) {
const filters: TableFilter[] = useMemo(() => { const filters: TableFilter[] = useMemo(() => {
return [ return [
{ UserFilter({
name: 'user', name: 'user',
label: t`User`, label: t`User`,
choices: userFilters.choices,
description: t`Filter by user` description: t`Filter by user`
} })
]; ];
}, [userFilters]); }, []);
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [