2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-06-11 19:27:02 +00:00

Improvements for template tables (#12155)

* Enable in-column filtering for model type

* Enable sorting by label size

* Enable backend ordering

* Improve filtering for report template table

* Update API version
This commit is contained in:
Oliver
2026-06-11 15:54:40 +10:00
committed by GitHub
parent 741f0e56c8
commit 39cc399a67
6 changed files with 61 additions and 20 deletions
@@ -1,11 +1,15 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 502 INVENTREE_API_VERSION = 503
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v503 -> 2026-06-11 : https://github.com/inventree/InvenTree/pull/12155
- Adds additional filtering and sorting options to the LabelTemplate API endpoint
- Adds additional filtering and sorting options to the ReportTemplate API endpoint
v502 -> 2026-06-10 : https://github.com/inventree/InvenTree/pull/12142 v502 -> 2026-06-10 : https://github.com/inventree/InvenTree/pull/12142
- Prevents users from printing reports or labels against models for which they do not have adequate permissions. This change improves the security of the system by ensuring that users cannot access or print reports or labels for models they do not have permission to view. - Prevents users from printing reports or labels against models for which they do not have adequate permissions. This change improves the security of the system by ensuring that users cannot access or print reports or labels for models they do not have permission to view.
+6 -7
View File
@@ -7,7 +7,6 @@ from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
import django_filters.rest_framework.filters as rest_filters import django_filters.rest_framework.filters as rest_filters
from django_filters.rest_framework import DjangoFilterBackend
from django_filters.rest_framework.filterset import FilterSet from django_filters.rest_framework.filterset import FilterSet
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
@@ -21,7 +20,7 @@ import users.permissions
from common.models import DataOutput from common.models import DataOutput
from common.serializers import DataOutputSerializer from common.serializers import DataOutputSerializer
from InvenTree.api import meta_path from InvenTree.api import meta_path
from InvenTree.filters import InvenTreeSearchFilter from InvenTree.filters import SEARCH_ORDER_FILTER
from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI
from plugin import PluginMixinEnum from plugin import PluginMixinEnum
from plugin.builtin.labels.inventree_label import InvenTreeLabelPlugin from plugin.builtin.labels.inventree_label import InvenTreeLabelPlugin
@@ -81,7 +80,7 @@ class ReportFilter(ReportFilterBase):
"""Filter options.""" """Filter options."""
model = report.models.ReportTemplate model = report.models.ReportTemplate
fields = ['landscape'] fields = ['landscape', 'merge', 'attach_to_model', 'enabled', 'model_type']
class LabelFilter(ReportFilterBase): class LabelFilter(ReportFilterBase):
@@ -91,7 +90,7 @@ class LabelFilter(ReportFilterBase):
"""Filter options.""" """Filter options."""
model = report.models.LabelTemplate model = report.models.LabelTemplate
fields = [] fields = ['enabled']
class LabelPrint(GenericAPIView): class LabelPrint(GenericAPIView):
@@ -246,9 +245,9 @@ class LabelTemplateList(TemplatePermissionMixin, LabelTemplateMixin, ListCreateA
"""API endpoint for viewing list of LabelTemplate objects.""" """API endpoint for viewing list of LabelTemplate objects."""
filterset_class = LabelFilter filterset_class = LabelFilter
filter_backends = [DjangoFilterBackend, InvenTreeSearchFilter] filter_backends = SEARCH_ORDER_FILTER
search_fields = ['name', 'description'] search_fields = ['name', 'description']
ordering_fields = ['name', 'enabled'] ordering_fields = ['name', 'enabled', 'width', 'height']
class LabelTemplateDetail( class LabelTemplateDetail(
@@ -341,7 +340,7 @@ class ReportTemplateList(TemplatePermissionMixin, ReportTemplateMixin, ListCreat
"""API endpoint for viewing list of ReportTemplate objects.""" """API endpoint for viewing list of ReportTemplate objects."""
filterset_class = ReportFilter filterset_class = ReportFilter
filter_backends = [DjangoFilterBackend, InvenTreeSearchFilter] filter_backends = SEARCH_ORDER_FILTER
search_fields = ['name', 'description'] search_fields = ['name', 'description']
ordering_fields = ['name', 'enabled'] ordering_fields = ['name', 'enabled']
+6 -4
View File
@@ -70,6 +70,11 @@ export type TableState = {
idAccessor?: string; idAccessor?: string;
}; };
export type TableColumnFilterType =
| string
| string[]
| (({ close }: { close: () => void }) => ReactNode);
/** /**
* Table column properties * Table column properties
* *
@@ -109,10 +114,7 @@ export type TableColumnProps<T = any> = {
editable?: boolean; editable?: boolean;
definition?: ApiFormFieldType; definition?: ApiFormFieldType;
render?: (record: T, index?: number) => any; render?: (record: T, index?: number) => any;
filter?: filter?: TableColumnFilterType;
| string
| string[]
| (({ close }: { close: () => void }) => ReactNode);
filtering?: boolean; filtering?: boolean;
width?: number; width?: number;
minWidth?: string | number; minWidth?: string | number;
@@ -10,8 +10,12 @@ function LabelTemplateTable() {
templateEndpoint: ApiEndpoints.label_list, templateEndpoint: ApiEndpoints.label_list,
printingEndpoint: ApiEndpoints.label_print, printingEndpoint: ApiEndpoints.label_print,
additionalFormFields: { additionalFormFields: {
width: {}, width: {
height: {} sortable: true
},
height: {
sortable: true
}
} }
}} }}
/> />
@@ -17,24 +17,44 @@ function ReportTemplateTable() {
modelType: ModelType.reporttemplate, modelType: ModelType.reporttemplate,
templateEndpoint: ApiEndpoints.report_list, templateEndpoint: ApiEndpoints.report_list,
printingEndpoint: ApiEndpoints.report_print, printingEndpoint: ApiEndpoints.report_print,
additionalFilters: [
{
name: 'landscape',
label: t`Landscape`,
type: 'boolean'
},
{
name: 'merge',
label: t`Merge`,
type: 'boolean'
},
{
name: 'attach_to_model',
label: t`Attach to Model`,
type: 'boolean'
}
],
additionalFormFields: { additionalFormFields: {
page_size: { page_size: {
label: t`Page Size` label: t`Page Size`
}, },
landscape: { landscape: {
label: t`Landscape`, label: t`Landscape`,
filter: 'landscape',
modelRenderer: (instance: any) => ( modelRenderer: (instance: any) => (
<YesNoButton value={instance.landscape} /> <YesNoButton value={instance.landscape} />
) )
}, },
merge: { merge: {
label: t`Merge`, label: t`Merge`,
filter: 'merge',
modelRenderer: (instance: any) => ( modelRenderer: (instance: any) => (
<YesNoButton value={instance.merge} /> <YesNoButton value={instance.merge} />
) )
}, },
attach_to_model: { attach_to_model: {
label: t`Attach to Model`, label: t`Attach to Model`,
filter: 'attach_to_model',
modelRenderer: (instance: any) => ( modelRenderer: (instance: any) => (
<YesNoButton value={instance.attach_to_model} /> <YesNoButton value={instance.attach_to_model} />
) )
@@ -18,8 +18,8 @@ import { apiUrl } from '@lib/functions/Api';
import { identifierString } from '@lib/functions/Conversion'; import { identifierString } from '@lib/functions/Conversion';
import useTable from '@lib/hooks/UseTable'; import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters'; import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms'; import type { ApiFormFieldSet, ApiFormFieldType } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables'; import type { TableColumn, TableColumnFilterType } from '@lib/types/Tables';
import { import {
CodeEditor, CodeEditor,
PdfPreview, PdfPreview,
@@ -68,11 +68,21 @@ export type TemplateI = {
template: string; template: string;
}; };
// Additional field props to control the column behaviour in the template table
interface TemplateFormFieldType extends ApiFormFieldType {
sortable?: boolean;
switchable?: boolean;
filter?: TableColumnFilterType;
}
type TemplateFormFieldSet = Record<string, TemplateFormFieldType>;
export interface TemplateProps { export interface TemplateProps {
modelType: ModelType.labeltemplate | ModelType.reporttemplate; modelType: ModelType.labeltemplate | ModelType.reporttemplate;
templateEndpoint: ApiEndpoints; templateEndpoint: ApiEndpoints;
printingEndpoint: ApiEndpoints; printingEndpoint: ApiEndpoints;
additionalFormFields?: ApiFormFieldSet; additionalFilters?: TableFilter[];
additionalFormFields?: TemplateFormFieldSet;
} }
export function TemplateDrawer({ export function TemplateDrawer({
@@ -233,6 +243,7 @@ export function TemplateTable({
}, },
{ {
accessor: 'model_type', accessor: 'model_type',
filter: 'model_type',
sortable: true, sortable: true,
switchable: false switchable: false
}, },
@@ -276,10 +287,10 @@ export function TemplateTable({
}, },
...Object.entries(additionalFormFields || {}).map(([key, field]) => ({ ...Object.entries(additionalFormFields || {}).map(([key, field]) => ({
accessor: key, accessor: key,
...field,
title: field.label,
sortable: false, sortable: false,
switchable: true, switchable: true,
title: field.label,
...field,
render: field.modelRenderer render: field.modelRenderer
})), })),
BooleanColumn({ accessor: 'enabled', title: t`Enabled` }) BooleanColumn({ accessor: 'enabled', title: t`Enabled` })
@@ -391,6 +402,7 @@ export function TemplateTable({
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
return [ return [
...(templateProps.additionalFilters || []),
{ {
name: 'enabled', name: 'enabled',
label: t`Enabled`, label: t`Enabled`,
@@ -404,7 +416,7 @@ export function TemplateTable({
choices: modelTypeFilters.choices choices: modelTypeFilters.choices
} }
]; ];
}, [modelTypeFilters.choices]); }, [templateProps.additionalFilters, modelTypeFilters.choices]);
return ( return (
<> <>