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:
Oliver 2023-09-24 23:36:34 +10:00 committed by GitHub
parent 2f0dbf9776
commit 7e6db65cac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 7 deletions

View File

@ -18,6 +18,8 @@ import { ApiFormProps } from '../ApiForm';
import { ChoiceField } from './ChoiceField';
import { RelatedModelField } from './RelatedModelField';
export type ApiFormData = UseFormReturnType<Record<string, unknown>>;
/**
* Callback function type when a form field value changes
*/
@ -25,7 +27,7 @@ export type ApiFormChangeCallback = {
name: string;
value: any;
field: ApiFormFieldType;
form: UseFormReturnType<Record<string, unknown>>;
form: ApiFormData;
};
/* Definition of the ApiForm field component.
@ -51,6 +53,7 @@ export type ApiFormChangeCallback = {
* @param preFieldContent : Content to render before the field
* @param postFieldContent : Content to render after the field
* @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 = {
label?: string;
@ -71,6 +74,7 @@ export type ApiFormFieldType = {
preFieldContent?: JSX.Element | (() => JSX.Element);
postFieldContent?: JSX.Element | (() => JSX.Element);
onValueChange?: (change: ApiFormChangeCallback) => void;
adjustFilters?: (filters: any, form: ApiFormData) => any;
};
/*

View File

@ -55,9 +55,14 @@ export function RelatedModelField({
useEffect(() => {
// If a value is provided, load the related object
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 + '/';
// TODO: Fix this!!
@ -78,9 +83,11 @@ export function RelatedModelField({
setPk(data.pk);
}
});
} else {
setPk(null);
}
}
}, [form]);
}, [form.values[fieldName]]);
const [offset, setOffset] = useState<number>(0);
@ -105,8 +112,14 @@ export function RelatedModelField({
url = url.substring(4);
}
let filters = definition.filters ?? {};
if (definition.adjustFilters) {
filters = definition.adjustFilters(filters, form);
}
let params = {
...definition.filters,
...filters,
search: searchText,
offset: offset,
limit: limit
@ -173,7 +186,7 @@ export function RelatedModelField({
<Input.Wrapper {...definition} error={error}>
<Select
id={fieldId}
value={data.find((item) => item.value == pk)}
value={pk != null && data.find((item) => item.value == pk)}
options={data}
filterOption={null}
onInputChange={(value: any) => {
@ -183,6 +196,11 @@ export function RelatedModelField({
}}
onChange={onChange}
onMenuScrollToBottom={() => setOffset(offset + limit)}
onMenuOpen={() => {
setValue('');
setOffset(0);
selectQuery.refetch();
}}
isLoading={
selectQuery.isFetching ||
selectQuery.isLoading ||

View File

@ -2,6 +2,7 @@ import { t } from '@lingui/macro';
import {
ApiFormChangeCallback,
ApiFormData,
ApiFormFieldSet,
ApiFormFieldType
} from '../../components/forms/fields/ApiFormField';
@ -14,8 +15,13 @@ export function stockFields({}: {}): ApiFormFieldSet {
let fields: ApiFormFieldSet = {
part: {
onValueChange: (change: ApiFormChangeCallback) => {
// TODO: implement this
// TODO: implement remaining functionality from old stock.py
console.log('part changed: ', change.value);
// Clear the 'supplier_part' field if the part is changed
change.form.setValues({
supplier_part: null
});
}
},
supplier_part: {
@ -24,6 +30,14 @@ export function stockFields({}: {}): ApiFormFieldSet {
filters: {
part_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: {