mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-03 22:08:49 +00:00
Interactive forms (#5608)
* Fix requery bug in related form field * Fixes for RelatedModelField - Better handling of null values * StockItem form fix - Clear 'supplier_part' field when 'part' field value changes * Add adjustFilters callback function - Allows query filters for a relatedfield to be changed on the fly
This commit is contained in:
parent
2f0dbf9776
commit
7e6db65cac
@ -18,6 +18,8 @@ import { ApiFormProps } from '../ApiForm';
|
|||||||
import { ChoiceField } from './ChoiceField';
|
import { ChoiceField } from './ChoiceField';
|
||||||
import { RelatedModelField } from './RelatedModelField';
|
import { RelatedModelField } from './RelatedModelField';
|
||||||
|
|
||||||
|
export type ApiFormData = UseFormReturnType<Record<string, unknown>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function type when a form field value changes
|
* Callback function type when a form field value changes
|
||||||
*/
|
*/
|
||||||
@ -25,7 +27,7 @@ export type ApiFormChangeCallback = {
|
|||||||
name: string;
|
name: string;
|
||||||
value: any;
|
value: any;
|
||||||
field: ApiFormFieldType;
|
field: ApiFormFieldType;
|
||||||
form: UseFormReturnType<Record<string, unknown>>;
|
form: ApiFormData;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Definition of the ApiForm field component.
|
/* Definition of the ApiForm field component.
|
||||||
@ -51,6 +53,7 @@ export type ApiFormChangeCallback = {
|
|||||||
* @param preFieldContent : Content to render before the field
|
* @param preFieldContent : Content to render before the field
|
||||||
* @param postFieldContent : Content to render after the field
|
* @param postFieldContent : Content to render after the field
|
||||||
* @param onValueChange : Callback function to call when the field value changes
|
* @param onValueChange : Callback function to call when the field value changes
|
||||||
|
* @param adjustFilters : Callback function to adjust the filters for a related field before a query is made
|
||||||
*/
|
*/
|
||||||
export type ApiFormFieldType = {
|
export type ApiFormFieldType = {
|
||||||
label?: string;
|
label?: string;
|
||||||
@ -71,6 +74,7 @@ export type ApiFormFieldType = {
|
|||||||
preFieldContent?: JSX.Element | (() => JSX.Element);
|
preFieldContent?: JSX.Element | (() => JSX.Element);
|
||||||
postFieldContent?: JSX.Element | (() => JSX.Element);
|
postFieldContent?: JSX.Element | (() => JSX.Element);
|
||||||
onValueChange?: (change: ApiFormChangeCallback) => void;
|
onValueChange?: (change: ApiFormChangeCallback) => void;
|
||||||
|
adjustFilters?: (filters: any, form: ApiFormData) => any;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -55,9 +55,14 @@ export function RelatedModelField({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If a value is provided, load the related object
|
// If a value is provided, load the related object
|
||||||
if (form.values) {
|
if (form.values) {
|
||||||
let formPk = form.values[fieldName];
|
let formPk = form.values[fieldName] ?? null;
|
||||||
|
|
||||||
if (formPk && formPk != pk) {
|
// If the value is unchanged, do nothing
|
||||||
|
if (formPk == pk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formPk != null) {
|
||||||
let url = (definition.api_url || '') + formPk + '/';
|
let url = (definition.api_url || '') + formPk + '/';
|
||||||
|
|
||||||
// TODO: Fix this!!
|
// TODO: Fix this!!
|
||||||
@ -78,9 +83,11 @@ export function RelatedModelField({
|
|||||||
setPk(data.pk);
|
setPk(data.pk);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setPk(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [form]);
|
}, [form.values[fieldName]]);
|
||||||
|
|
||||||
const [offset, setOffset] = useState<number>(0);
|
const [offset, setOffset] = useState<number>(0);
|
||||||
|
|
||||||
@ -105,8 +112,14 @@ export function RelatedModelField({
|
|||||||
url = url.substring(4);
|
url = url.substring(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let filters = definition.filters ?? {};
|
||||||
|
|
||||||
|
if (definition.adjustFilters) {
|
||||||
|
filters = definition.adjustFilters(filters, form);
|
||||||
|
}
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
...definition.filters,
|
...filters,
|
||||||
search: searchText,
|
search: searchText,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: limit
|
limit: limit
|
||||||
@ -173,7 +186,7 @@ export function RelatedModelField({
|
|||||||
<Input.Wrapper {...definition} error={error}>
|
<Input.Wrapper {...definition} error={error}>
|
||||||
<Select
|
<Select
|
||||||
id={fieldId}
|
id={fieldId}
|
||||||
value={data.find((item) => item.value == pk)}
|
value={pk != null && data.find((item) => item.value == pk)}
|
||||||
options={data}
|
options={data}
|
||||||
filterOption={null}
|
filterOption={null}
|
||||||
onInputChange={(value: any) => {
|
onInputChange={(value: any) => {
|
||||||
@ -183,6 +196,11 @@ export function RelatedModelField({
|
|||||||
}}
|
}}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onMenuScrollToBottom={() => setOffset(offset + limit)}
|
onMenuScrollToBottom={() => setOffset(offset + limit)}
|
||||||
|
onMenuOpen={() => {
|
||||||
|
setValue('');
|
||||||
|
setOffset(0);
|
||||||
|
selectQuery.refetch();
|
||||||
|
}}
|
||||||
isLoading={
|
isLoading={
|
||||||
selectQuery.isFetching ||
|
selectQuery.isFetching ||
|
||||||
selectQuery.isLoading ||
|
selectQuery.isLoading ||
|
||||||
|
@ -2,6 +2,7 @@ import { t } from '@lingui/macro';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ApiFormChangeCallback,
|
ApiFormChangeCallback,
|
||||||
|
ApiFormData,
|
||||||
ApiFormFieldSet,
|
ApiFormFieldSet,
|
||||||
ApiFormFieldType
|
ApiFormFieldType
|
||||||
} from '../../components/forms/fields/ApiFormField';
|
} from '../../components/forms/fields/ApiFormField';
|
||||||
@ -14,8 +15,13 @@ export function stockFields({}: {}): ApiFormFieldSet {
|
|||||||
let fields: ApiFormFieldSet = {
|
let fields: ApiFormFieldSet = {
|
||||||
part: {
|
part: {
|
||||||
onValueChange: (change: ApiFormChangeCallback) => {
|
onValueChange: (change: ApiFormChangeCallback) => {
|
||||||
// TODO: implement this
|
// TODO: implement remaining functionality from old stock.py
|
||||||
console.log('part changed: ', change.value);
|
console.log('part changed: ', change.value);
|
||||||
|
|
||||||
|
// Clear the 'supplier_part' field if the part is changed
|
||||||
|
change.form.setValues({
|
||||||
|
supplier_part: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
supplier_part: {
|
supplier_part: {
|
||||||
@ -24,6 +30,14 @@ export function stockFields({}: {}): ApiFormFieldSet {
|
|||||||
filters: {
|
filters: {
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
supplier_detail: true
|
supplier_detail: true
|
||||||
|
},
|
||||||
|
adjustFilters: (filters: any, form: ApiFormData) => {
|
||||||
|
let part = form.values.part;
|
||||||
|
if (part) {
|
||||||
|
filters.part = part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
use_pack_size: {
|
use_pack_size: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user