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:
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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']
|
||||||
|
|
||||||
|
|||||||
@@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|||||||
Reference in New Issue
Block a user