mirror of
https://github.com/inventree/InvenTree.git
synced 2025-08-10 22:00:56 +00:00
Enhancements for "custom state" form
- More intuitive form actions
This commit is contained in:
@@ -3406,17 +3406,20 @@ class InvenTreeCustomUserStateModel(models.Model):
|
|||||||
"""Custom model to extends any registered state with extra custom, user defined states."""
|
"""Custom model to extends any registered state with extra custom, user defined states."""
|
||||||
|
|
||||||
key = models.IntegerField(
|
key = models.IntegerField(
|
||||||
verbose_name=_('Key'),
|
verbose_name=_('Value'),
|
||||||
help_text=_('Value that will be saved in the models database'),
|
help_text=_('Numerical value that will be saved in the models database'),
|
||||||
)
|
)
|
||||||
|
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=250, verbose_name=_('Name'), help_text=_('Name of the state')
|
max_length=250, verbose_name=_('Name'), help_text=_('Name of the state')
|
||||||
)
|
)
|
||||||
|
|
||||||
label = models.CharField(
|
label = models.CharField(
|
||||||
max_length=250,
|
max_length=250,
|
||||||
verbose_name=_('Label'),
|
verbose_name=_('Label'),
|
||||||
help_text=_('Label that will be displayed in the frontend'),
|
help_text=_('Label that will be displayed in the frontend'),
|
||||||
)
|
)
|
||||||
|
|
||||||
color = models.CharField(
|
color = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
choices=state_color_mappings(),
|
choices=state_color_mappings(),
|
||||||
@@ -3424,12 +3427,14 @@ class InvenTreeCustomUserStateModel(models.Model):
|
|||||||
verbose_name=_('Color'),
|
verbose_name=_('Color'),
|
||||||
help_text=_('Color that will be displayed in the frontend'),
|
help_text=_('Color that will be displayed in the frontend'),
|
||||||
)
|
)
|
||||||
|
|
||||||
logical_key = models.IntegerField(
|
logical_key = models.IntegerField(
|
||||||
verbose_name=_('Logical Key'),
|
verbose_name=_('Logical Key'),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
'State logical key that is equal to this custom state in business logic'
|
'State logical key that is equal to this custom state in business logic'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
model = models.ForeignKey(
|
model = models.ForeignKey(
|
||||||
ContentType,
|
ContentType,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
@@ -3438,6 +3443,7 @@ class InvenTreeCustomUserStateModel(models.Model):
|
|||||||
verbose_name=_('Model'),
|
verbose_name=_('Model'),
|
||||||
help_text=_('Model this state is associated with'),
|
help_text=_('Model this state is associated with'),
|
||||||
)
|
)
|
||||||
|
|
||||||
reference_status = models.CharField(
|
reference_status = models.CharField(
|
||||||
max_length=250,
|
max_length=250,
|
||||||
verbose_name=_('Reference Status Set'),
|
verbose_name=_('Reference Status Set'),
|
||||||
|
@@ -5,7 +5,7 @@ import { ModelType } from '../../enums/ModelType';
|
|||||||
import { resolveItem } from '../../functions/conversion';
|
import { resolveItem } from '../../functions/conversion';
|
||||||
import { useGlobalStatusState } from '../../states/StatusState';
|
import { useGlobalStatusState } from '../../states/StatusState';
|
||||||
|
|
||||||
interface StatusCodeInterface {
|
export interface StatusCodeInterface {
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -13,7 +13,10 @@ interface StatusCodeInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface StatusCodeListInterface {
|
export interface StatusCodeListInterface {
|
||||||
[key: string]: StatusCodeInterface;
|
statusClass: string;
|
||||||
|
values: {
|
||||||
|
[key: string]: StatusCodeInterface;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RenderStatusLabelOptionsInterface {
|
interface RenderStatusLabelOptionsInterface {
|
||||||
@@ -33,10 +36,10 @@ function renderStatusLabel(
|
|||||||
let color = null;
|
let color = null;
|
||||||
|
|
||||||
// Find the entry which matches the provided key
|
// Find the entry which matches the provided key
|
||||||
for (let name in codes) {
|
for (let name in codes.values) {
|
||||||
let entry = codes[name];
|
let entry: StatusCodeInterface = codes.values[name];
|
||||||
|
|
||||||
if (entry.key == key) {
|
if (entry?.key == key) {
|
||||||
text = entry.label;
|
text = entry.label;
|
||||||
color = entry.color;
|
color = entry.color;
|
||||||
break;
|
break;
|
||||||
@@ -97,7 +100,7 @@ export function getStatusCodeName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let name in statusCodes) {
|
for (let name in statusCodes) {
|
||||||
let entry = statusCodes[name];
|
let entry: StatusCodeInterface = statusCodes.values[name];
|
||||||
|
|
||||||
if (entry.key == key) {
|
if (entry.key == key) {
|
||||||
return entry.name;
|
return entry.name;
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import { IconUsers } from '@tabler/icons-react';
|
import { IconUsers } from '@tabler/icons-react';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
|
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
|
||||||
|
import {
|
||||||
|
StatusCodeInterface,
|
||||||
|
StatusCodeListInterface
|
||||||
|
} from '../components/render/StatusRenderer';
|
||||||
|
import { useGlobalStatusState } from '../states/StatusState';
|
||||||
|
|
||||||
export function projectCodeFields(): ApiFormFieldSet {
|
export function projectCodeFields(): ApiFormFieldSet {
|
||||||
return {
|
return {
|
||||||
@@ -12,16 +18,51 @@ export function projectCodeFields(): ApiFormFieldSet {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function customStateFields(): ApiFormFieldSet {
|
export function useCustomStateFields(): ApiFormFieldSet {
|
||||||
return {
|
// Status codes
|
||||||
key: {},
|
const statusCodes = useGlobalStatusState();
|
||||||
name: {},
|
|
||||||
label: {},
|
// Selected base status class
|
||||||
color: {},
|
const [statusClass, setStatusClass] = useState<string>('');
|
||||||
logical_key: {},
|
|
||||||
model: {},
|
// Construct a list of status options based on the selected status class
|
||||||
reference_status: {}
|
const statusOptions: any[] = useMemo(() => {
|
||||||
};
|
let options: any[] = [];
|
||||||
|
|
||||||
|
const valuesList = Object.values(statusCodes.status ?? {}).find(
|
||||||
|
(value: StatusCodeListInterface) => value.statusClass === statusClass
|
||||||
|
);
|
||||||
|
|
||||||
|
Object.values(valuesList?.values ?? {}).forEach(
|
||||||
|
(value: StatusCodeInterface) => {
|
||||||
|
options.push({
|
||||||
|
value: value.key,
|
||||||
|
display_name: value.label
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}, [statusCodes, statusClass]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return {
|
||||||
|
reference_status: {
|
||||||
|
onValueChange(value) {
|
||||||
|
setStatusClass(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
logical_key: {
|
||||||
|
field_type: 'choice',
|
||||||
|
choices: statusOptions
|
||||||
|
},
|
||||||
|
key: {},
|
||||||
|
name: {},
|
||||||
|
label: {},
|
||||||
|
color: {},
|
||||||
|
model: {}
|
||||||
|
};
|
||||||
|
}, [statusOptions]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function customUnitsFields(): ApiFormFieldSet {
|
export function customUnitsFields(): ApiFormFieldSet {
|
||||||
|
@@ -35,8 +35,10 @@ export const useGlobalStatusState = create<ServerStateProps>()(
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
const newStatusLookup: StatusLookup = {} as StatusLookup;
|
const newStatusLookup: StatusLookup = {} as StatusLookup;
|
||||||
for (const key in response.data) {
|
for (const key in response.data) {
|
||||||
newStatusLookup[statusCodeList[key] || key] =
|
newStatusLookup[statusCodeList[key] || key] = {
|
||||||
response.data[key].values;
|
statusClass: key,
|
||||||
|
values: response.data[key].values
|
||||||
|
};
|
||||||
}
|
}
|
||||||
set({ status: newStatusLookup });
|
set({ status: newStatusLookup });
|
||||||
})
|
})
|
||||||
|
@@ -4,7 +4,7 @@ import { useCallback, useMemo, useState } from 'react';
|
|||||||
import { AddItemButton } from '../../components/buttons/AddItemButton';
|
import { AddItemButton } from '../../components/buttons/AddItemButton';
|
||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
import { UserRoles } from '../../enums/Roles';
|
import { UserRoles } from '../../enums/Roles';
|
||||||
import { customStateFields } from '../../forms/CommonForms';
|
import { useCustomStateFields } from '../../forms/CommonForms';
|
||||||
import {
|
import {
|
||||||
useCreateApiFormModal,
|
useCreateApiFormModal,
|
||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
@@ -60,10 +60,13 @@ export default function CustomStateTable() {
|
|||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const newCustomStateFields = useCustomStateFields();
|
||||||
|
const editCustomStateFields = useCustomStateFields();
|
||||||
|
|
||||||
const newCustomState = useCreateApiFormModal({
|
const newCustomState = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.custom_state_list,
|
url: ApiEndpoints.custom_state_list,
|
||||||
title: t`Add State`,
|
title: t`Add State`,
|
||||||
fields: customStateFields(),
|
fields: newCustomStateFields,
|
||||||
table: table
|
table: table
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ export default function CustomStateTable() {
|
|||||||
url: ApiEndpoints.custom_state_list,
|
url: ApiEndpoints.custom_state_list,
|
||||||
pk: selectedCustomState,
|
pk: selectedCustomState,
|
||||||
title: t`Edit State`,
|
title: t`Edit State`,
|
||||||
fields: customStateFields(),
|
fields: editCustomStateFields,
|
||||||
table: table
|
table: table
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user