[feature] tags support (#12077)

* Add Tag API endpoints

* Enable filtering by model type

* Remove old tags filters against Part endpoint

* Add generic tags filter for filtering against tagged items

* Add API unit tests for the tags API endpoints

* Create generic mixin class for adding tags support

* Update existing tagged models

* Add tags to more model types

* Enable new tags API filtering for multiple models

* Add support for tag filtering in part table

* Update transfer table filters

* Add tags filter to more places

* Allow multiple values to be selected as filters

* Add a new 'tags' type form field

* Display tags on part page

* tags support for orders

* Add support for SalesOrderShipment

* build order

* Company support

* SupplierPart and ManufacturerPart

* support StockItem

* Enable tag filtering for attachments

* Make tagslist readonly

* docs

* Mark props as read only

* Update API version

* Update CHANGELOG

* force tags to be case insensitive

* Add playwright test for build order tags

* more playwright testing

* Fix docs link
This commit is contained in:
Oliver
2026-06-04 19:38:22 +10:00
committed by GitHub
parent a0b2452ba5
commit 75a08a1e06
78 changed files with 1294 additions and 263 deletions
+27
View File
@@ -0,0 +1,27 @@
import { ActionIcon, Badge, Group, Paper } from '@mantine/core';
import { IconTag } from '@tabler/icons-react';
export default function TagsList({
tags
}: Readonly<{
tags: string[];
}>) {
if (!tags || tags.length === 0) {
return null;
}
return (
<Paper p='xs' shadow='xs' withBorder>
<Group gap='xs'>
<ActionIcon size='sm' variant='transparent'>
<IconTag />
</ActionIcon>
{tags.map((tag: string) => (
<Badge key={tag} variant='outline' size='sm'>
{tag}
</Badge>
))}
</Group>
</Paper>
);
}
+1
View File
@@ -259,6 +259,7 @@ export enum ApiEndpoints {
config_list = 'admin/config/',
parameter_list = 'parameter/',
parameter_template_list = 'parameter/template/',
tag_list = 'tag/',
// Internal system things
system_internal_trace_end = 'system-internal/observability/end'
@@ -319,5 +319,11 @@ export const ModelInformationDict: ModelDict = {
url_overview: '/settings/admin/errors',
url_detail: '/settings/admin/errors/:pk/',
icon: 'exclamation'
},
tag: {
label: () => t`Tag`,
label_multiple: () => t`Tags`,
api_endpoint: ApiEndpoints.tag_list,
icon: 'tag'
}
};
+2 -1
View File
@@ -38,7 +38,8 @@ export enum ModelType {
contenttype = 'contenttype',
selectionlist = 'selectionlist',
selectionentry = 'selectionentry',
error = 'error'
error = 'error',
tag = 'tag'
}
export enum PluginPanelKey {
+1
View File
@@ -110,6 +110,7 @@ export { ProgressBar } from './components/ProgressBar';
export { PassFailButton, YesNoButton } from './components/YesNoButton';
export { SearchInput } from './components/SearchInput';
export { TableColumnSelect } from './components/TableColumnSelect';
export { default as TagsList } from './components/TagsList';
export { default as InvenTreeTable } from './components/InvenTreeTable';
export {
RowViewAction,
+3
View File
@@ -41,6 +41,7 @@ export type TableFilter = {
name: string;
label?: string;
description?: string;
placeholder?: string;
type?: TableFilterType;
choices?: TableFilterChoice[];
choiceFunction?: () => TableFilterChoice[];
@@ -52,6 +53,8 @@ export type TableFilter = {
apiFilter?: Record<string, any>;
model?: ModelType;
modelRenderer?: (instance: any) => string;
transform?: (item: any) => TableFilterChoice;
multi?: boolean;
};
/*
+2 -1
View File
@@ -99,7 +99,8 @@ export type ApiFormFieldType = {
| 'file upload'
| 'nested object'
| 'dependent field'
| 'table';
| 'table'
| 'tags';
api_url?: string;
pk_field?: string;
model?: ModelType;