mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-02 10:18:42 +00:00
Merge commit '3393ef4e65267f4f8c5a5a87798553dbe0160a39' into block-notes
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -260,6 +260,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'
|
||||
|
||||
@@ -118,8 +118,8 @@ export const ModelInformationDict: ModelDict = {
|
||||
icon: 'history'
|
||||
},
|
||||
build: {
|
||||
label: () => t`Build`,
|
||||
label_multiple: () => t`Builds`,
|
||||
label: () => t`Build Order`,
|
||||
label_multiple: () => t`Build Orders`,
|
||||
url_overview: '/manufacturing/index/buildorders/',
|
||||
url_detail: '/manufacturing/build-order/:pk/',
|
||||
api_endpoint: ApiEndpoints.build_order_list,
|
||||
@@ -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'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,7 +38,8 @@ export enum ModelType {
|
||||
contenttype = 'contenttype',
|
||||
selectionlist = 'selectionlist',
|
||||
selectionentry = 'selectionentry',
|
||||
error = 'error'
|
||||
error = 'error',
|
||||
tag = 'tag'
|
||||
}
|
||||
|
||||
export enum PluginPanelKey {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useLocalStorage } from '@mantine/hooks';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import type { FilterSetState, TableFilter } from '../types/Filters';
|
||||
import type {
|
||||
FilterSetState,
|
||||
NamedFilterSet,
|
||||
TableFilter
|
||||
} from '../types/Filters';
|
||||
|
||||
export default function useFilterSet(
|
||||
filterKey: string,
|
||||
@@ -16,6 +20,16 @@ export default function useFilterSet(
|
||||
getInitialValueInEffect: false
|
||||
});
|
||||
|
||||
// Named filter set snapshots (saved to local storage, separate key)
|
||||
const [storedNamedSets, setStoredNamedSets] = useLocalStorage<
|
||||
NamedFilterSet[]
|
||||
>({
|
||||
key: `inventree-filtersets-${filterKey}`,
|
||||
defaultValue: [],
|
||||
sync: false,
|
||||
getInitialValueInEffect: false
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (storedFilters == null) {
|
||||
setStoredFilters(initialFilters || []);
|
||||
@@ -26,7 +40,6 @@ export default function useFilterSet(
|
||||
return storedFilters ?? initialFilters ?? [];
|
||||
}, [storedFilters, initialFilters]);
|
||||
|
||||
// Callback to clear all active filters from the table
|
||||
const clearActiveFilters = useCallback(() => {
|
||||
setStoredFilters([]);
|
||||
}, []);
|
||||
@@ -38,10 +51,48 @@ export default function useFilterSet(
|
||||
[setStoredFilters]
|
||||
);
|
||||
|
||||
const saveFilterSet = useCallback(
|
||||
(name: string) => {
|
||||
const snapshot = activeFilters.map(
|
||||
({ name: n, value, displayValue }) => ({
|
||||
name: n,
|
||||
value,
|
||||
displayValue
|
||||
})
|
||||
);
|
||||
setStoredNamedSets((prev) => {
|
||||
const without = (prev ?? []).filter((s) => s.name !== name);
|
||||
return [...without, { name, filters: snapshot }];
|
||||
});
|
||||
},
|
||||
[activeFilters, setStoredNamedSets]
|
||||
);
|
||||
|
||||
const loadFilterSet = useCallback(
|
||||
(name: string) => {
|
||||
const saved = (storedNamedSets ?? []).find((s) => s.name === name);
|
||||
if (saved) {
|
||||
setStoredFilters(saved.filters as TableFilter[]);
|
||||
}
|
||||
},
|
||||
[storedNamedSets, setStoredFilters]
|
||||
);
|
||||
|
||||
const deleteFilterSet = useCallback(
|
||||
(name: string) => {
|
||||
setStoredNamedSets((prev) => (prev ?? []).filter((s) => s.name !== name));
|
||||
},
|
||||
[setStoredNamedSets]
|
||||
);
|
||||
|
||||
return {
|
||||
filterKey,
|
||||
activeFilters,
|
||||
setActiveFilters,
|
||||
clearActiveFilters
|
||||
clearActiveFilters,
|
||||
savedFilterSets: storedNamedSets ?? [],
|
||||
saveFilterSet,
|
||||
loadFilterSet,
|
||||
deleteFilterSet
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -41,6 +41,7 @@ export type TableFilter = {
|
||||
name: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
placeholder?: string;
|
||||
type?: TableFilterType;
|
||||
choices?: TableFilterChoice[];
|
||||
choiceFunction?: () => TableFilterChoice[];
|
||||
@@ -52,6 +53,16 @@ export type TableFilter = {
|
||||
apiFilter?: Record<string, any>;
|
||||
model?: ModelType;
|
||||
modelRenderer?: (instance: any) => string;
|
||||
transform?: (item: any) => TableFilterChoice;
|
||||
multi?: boolean;
|
||||
};
|
||||
|
||||
/*
|
||||
* A named snapshot of a set of active filters, saved to local storage.
|
||||
*/
|
||||
export type NamedFilterSet = {
|
||||
name: string;
|
||||
filters: Pick<TableFilter, 'name' | 'value' | 'displayValue'>[];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -62,10 +73,18 @@ export type TableFilter = {
|
||||
* activeFilters: An array of active filters
|
||||
* setActiveFilters: A function to set the active filters
|
||||
* clearActiveFilters: A function to clear all active filters
|
||||
* savedFilterSets: Named filter set snapshots persisted to local storage
|
||||
* saveFilterSet: Save the current active filters under a given name
|
||||
* loadFilterSet: Replace active filters with a previously saved named set
|
||||
* deleteFilterSet: Remove a saved named filter set by name
|
||||
*/
|
||||
export type FilterSetState = {
|
||||
filterKey: string;
|
||||
activeFilters: TableFilter[];
|
||||
setActiveFilters: (filters: TableFilter[]) => void;
|
||||
clearActiveFilters: () => void;
|
||||
savedFilterSets: NamedFilterSet[];
|
||||
saveFilterSet: (name: string) => void;
|
||||
loadFilterSet: (name: string) => void;
|
||||
deleteFilterSet: (name: string) => void;
|
||||
};
|
||||
|
||||
@@ -99,7 +99,8 @@ export type ApiFormFieldType = {
|
||||
| 'file upload'
|
||||
| 'nested object'
|
||||
| 'dependent field'
|
||||
| 'table';
|
||||
| 'table'
|
||||
| 'tags';
|
||||
api_url?: string;
|
||||
pk_field?: string;
|
||||
model?: ModelType;
|
||||
|
||||
Reference in New Issue
Block a user