mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	* Refactor form fields
- Allow error message to be passed through via field definition
- Return error information to onFormError
* Fix debounce issue for text fields
* Fix for useForm hook
* Badge fix
- Fix badge rendering for SalesOrderShipment
* Cleanup unit test
(cherry picked from commit aabcf52cd2)
Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
			
			
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							70f17997eb
						
					
				
				
					commit
					4019dc9c9c
				
			| @@ -94,7 +94,7 @@ export interface ApiFormProps { | ||||
|   postFormContent?: JSX.Element; | ||||
|   successMessage?: string; | ||||
|   onFormSuccess?: (data: any) => void; | ||||
|   onFormError?: () => void; | ||||
|   onFormError?: (response: any) => void; | ||||
|   processFormData?: (data: any) => any; | ||||
|   table?: TableState; | ||||
|   modelType?: ModelType; | ||||
| @@ -482,7 +482,7 @@ export function ApiForm({ | ||||
|           default: | ||||
|             // Unexpected state on form success | ||||
|             invalidResponse(response.status); | ||||
|             props.onFormError?.(); | ||||
|             props.onFormError?.(response); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @@ -534,26 +534,30 @@ export function ApiForm({ | ||||
|  | ||||
|               processErrors(error.response.data); | ||||
|               setNonFieldErrors(_nonFieldErrors); | ||||
|               props.onFormError?.(error); | ||||
|  | ||||
|               break; | ||||
|             default: | ||||
|               // Unexpected state on form error | ||||
|               invalidResponse(error.response.status); | ||||
|               props.onFormError?.(); | ||||
|               props.onFormError?.(error); | ||||
|               break; | ||||
|           } | ||||
|         } else { | ||||
|           showTimeoutNotification(); | ||||
|           props.onFormError?.(); | ||||
|           props.onFormError?.(error); | ||||
|         } | ||||
|  | ||||
|         return error; | ||||
|       }); | ||||
|   }; | ||||
|  | ||||
|   const onFormError = useCallback<SubmitErrorHandler<FieldValues>>(() => { | ||||
|     props.onFormError?.(); | ||||
|   }, [props.onFormError]); | ||||
|   const onFormError = useCallback<SubmitErrorHandler<FieldValues>>( | ||||
|     (error: any) => { | ||||
|       props.onFormError?.(error); | ||||
|     }, | ||||
|     [props.onFormError] | ||||
|   ); | ||||
|  | ||||
|   if (optionsLoading || initialDataQuery.isFetching) { | ||||
|     return ( | ||||
|   | ||||
| @@ -46,6 +46,7 @@ export type ApiFormFieldChoice = { | ||||
|  * @param required : Whether the field is required | ||||
|  * @param hidden : Whether the field is hidden | ||||
|  * @param disabled : Whether the field is disabled | ||||
|  * @param error : Optional error message to display | ||||
|  * @param exclude : Whether to exclude the field from the submitted data | ||||
|  * @param placeholder : The placeholder text to display | ||||
|  * @param description : The description to display for the field | ||||
| @@ -88,6 +89,7 @@ export type ApiFormFieldType = { | ||||
|   child?: ApiFormFieldType; | ||||
|   children?: { [key: string]: ApiFormFieldType }; | ||||
|   required?: boolean; | ||||
|   error?: string; | ||||
|   choices?: ApiFormFieldChoice[]; | ||||
|   hidden?: boolean; | ||||
|   disabled?: boolean; | ||||
| @@ -256,7 +258,7 @@ export function ApiFormField({ | ||||
|             aria-label={`boolean-field-${fieldName}`} | ||||
|             radius='lg' | ||||
|             size='sm' | ||||
|             error={error?.message} | ||||
|             error={definition.error ?? error?.message} | ||||
|             onChange={(event) => onChange(event.currentTarget.checked)} | ||||
|           /> | ||||
|         ); | ||||
| @@ -277,7 +279,7 @@ export function ApiFormField({ | ||||
|             id={fieldId} | ||||
|             aria-label={`number-field-${field.name}`} | ||||
|             value={numericalValue} | ||||
|             error={error?.message} | ||||
|             error={definition.error ?? error?.message} | ||||
|             decimalScale={definition.field_type == 'integer' ? 0 : 10} | ||||
|             onChange={(value: number | string | null) => onChange(value)} | ||||
|             step={1} | ||||
| @@ -299,7 +301,7 @@ export function ApiFormField({ | ||||
|             ref={field.ref} | ||||
|             radius='sm' | ||||
|             value={value} | ||||
|             error={error?.message} | ||||
|             error={definition.error ?? error?.message} | ||||
|             onChange={(payload: File | null) => onChange(payload)} | ||||
|           /> | ||||
|         ); | ||||
| @@ -343,6 +345,7 @@ export function ApiFormField({ | ||||
|     booleanValue, | ||||
|     control, | ||||
|     controller, | ||||
|     definition, | ||||
|     field, | ||||
|     fieldId, | ||||
|     fieldName, | ||||
|   | ||||
| @@ -63,7 +63,7 @@ export function ChoiceField({ | ||||
|     <Select | ||||
|       id={fieldId} | ||||
|       aria-label={`choice-field-${field.name}`} | ||||
|       error={error?.message} | ||||
|       error={definition.error ?? error?.message} | ||||
|       radius='sm' | ||||
|       {...field} | ||||
|       onChange={onChange} | ||||
|   | ||||
| @@ -61,7 +61,7 @@ export default function DateField({ | ||||
|       radius='sm' | ||||
|       ref={field.ref} | ||||
|       type={undefined} | ||||
|       error={error?.message} | ||||
|       error={definition.error ?? error?.message} | ||||
|       value={dateValue ?? null} | ||||
|       clearable={!definition.required} | ||||
|       onChange={onChange} | ||||
|   | ||||
| @@ -50,7 +50,7 @@ export default function IconField({ | ||||
|           label={definition.label} | ||||
|           description={definition.description} | ||||
|           required={definition.required} | ||||
|           error={error?.message} | ||||
|           error={definition.error ?? error?.message} | ||||
|           ref={field.ref} | ||||
|           component='button' | ||||
|           type='button' | ||||
|   | ||||
| @@ -284,7 +284,7 @@ export function RelatedModelField({ | ||||
|   return ( | ||||
|     <Input.Wrapper | ||||
|       {...fieldDefinition} | ||||
|       error={error?.message} | ||||
|       error={definition.error ?? error?.message} | ||||
|       styles={{ description: { paddingBottom: '5px' } }} | ||||
|     > | ||||
|       <Select | ||||
|   | ||||
| @@ -258,7 +258,7 @@ export function TableFieldExtraRow({ | ||||
|               fieldName={fieldName ?? 'field'} | ||||
|               fieldDefinition={field} | ||||
|               defaultValue={defaultValue} | ||||
|               error={error} | ||||
|               error={fieldDefinition.error ?? error} | ||||
|             /> | ||||
|           </Group> | ||||
|         </Table.Td> | ||||
|   | ||||
| @@ -56,7 +56,7 @@ export default function TextField({ | ||||
|       aria-label={`text-field-${field.name}`} | ||||
|       type={definition.field_type} | ||||
|       value={rawText || ''} | ||||
|       error={error?.message} | ||||
|       error={definition.error ?? error?.message} | ||||
|       radius='sm' | ||||
|       onChange={(event) => onTextChange(event.currentTarget.value)} | ||||
|       onBlur={(event) => { | ||||
| @@ -64,7 +64,13 @@ export default function TextField({ | ||||
|           onChange(event.currentTarget.value); | ||||
|         } | ||||
|       }} | ||||
|       onKeyDown={(event) => onKeyDown(event.code)} | ||||
|       onKeyDown={(event) => { | ||||
|         if (event.code === 'Enter') { | ||||
|           // Bypass debounce on enter key | ||||
|           onChange(event.currentTarget.value); | ||||
|         } | ||||
|         onKeyDown(event.code); | ||||
|       }} | ||||
|       rightSection={ | ||||
|         value && !definition.required ? ( | ||||
|           <IconX size='1rem' color='red' onClick={() => onTextChange('')} /> | ||||
|   | ||||
| @@ -48,9 +48,8 @@ export function useApiFormModal(props: ApiFormModalProps) { | ||||
|         modalClose.current(); | ||||
|         props.onFormSuccess?.(data); | ||||
|       }, | ||||
|       onFormError: () => { | ||||
|         modalClose.current(); | ||||
|         props.onFormError?.(); | ||||
|       onFormError: (error: any) => { | ||||
|         props.onFormError?.(error); | ||||
|       } | ||||
|     }), | ||||
|     [props] | ||||
|   | ||||
| @@ -90,10 +90,8 @@ test('Build Order - Basic Tests', async ({ page }) => { | ||||
| test('Build Order - Build Outputs', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/`); | ||||
|  | ||||
|   // Navigate to the correct build order | ||||
|   await page.getByRole('tab', { name: 'Manufacturing', exact: true }).click(); | ||||
|   await page.goto(`${baseUrl}/manufacturing/index/`); | ||||
|   await page.getByRole('tab', { name: 'Build Orders', exact: true }).click(); | ||||
|  | ||||
|   // We have now loaded the "Build Order" table. Check for some expected texts | ||||
|   await page.getByText('On Hold').first().waitFor(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user