mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-31 13:25:40 +00:00 
			
		
		
		
	Display non-field errors as returned from the server
This commit is contained in:
		| @@ -7,6 +7,7 @@ import "package:date_field/date_field.dart"; | ||||
|  | ||||
| import "package:inventree/api.dart"; | ||||
| import "package:inventree/app_colors.dart"; | ||||
| import 'package:inventree/helpers.dart'; | ||||
| import "package:inventree/inventree/part.dart"; | ||||
| import "package:inventree/inventree/sentry.dart"; | ||||
| import "package:inventree/inventree/stock.dart"; | ||||
| @@ -201,7 +202,15 @@ class APIFormField { | ||||
|  | ||||
|   // Return the error message associated with this field | ||||
|   List<String> errorMessages() { | ||||
|     List<dynamic> errors = (data["errors"] ?? []) as List<dynamic>; | ||||
|  | ||||
|     dynamic errors = data["errors"] ?? []; | ||||
|  | ||||
|     // Handle the case where a single error message is returned | ||||
|     if (errors is String) { | ||||
|       errors = [errors]; | ||||
|     } | ||||
|  | ||||
|     errors = errors as List<dynamic>; | ||||
|  | ||||
|     List<String> messages = []; | ||||
|  | ||||
| @@ -395,7 +404,7 @@ class APIFormField { | ||||
|         helperStyle: _helperStyle(), | ||||
|         hintText: placeholderText, | ||||
|       ), | ||||
|       initialValue: (value ?? 0).toString(), | ||||
|       initialValue: simpleNumberString(double.tryParse(value.toString()) ?? 0), | ||||
|       keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), | ||||
|       validator: (value) { | ||||
|  | ||||
| @@ -871,6 +880,8 @@ class _APIFormWidgetState extends State<APIFormWidget> { | ||||
|  | ||||
|   final IconData icon; | ||||
|  | ||||
|   List<String> nonFieldErrors = []; | ||||
|  | ||||
|   List<APIFormField> fields; | ||||
|  | ||||
|   Function(Map<String, dynamic>)? onSuccess; | ||||
| @@ -881,6 +892,29 @@ class _APIFormWidgetState extends State<APIFormWidget> { | ||||
|  | ||||
|     List<Widget> widgets = []; | ||||
|  | ||||
|     // Display non-field errors first | ||||
|     if (nonFieldErrors.isNotEmpty) { | ||||
|       for (String error in nonFieldErrors) { | ||||
|         widgets.add( | ||||
|           ListTile( | ||||
|             title: Text( | ||||
|               error, | ||||
|               style: TextStyle( | ||||
|                 color: COLOR_DANGER, | ||||
|               ), | ||||
|             ), | ||||
|             leading: FaIcon( | ||||
|               FontAwesomeIcons.exclamationCircle, | ||||
|               color: COLOR_DANGER | ||||
|             ), | ||||
|           ) | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       widgets.add(Divider(height: 5)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     for (var field in fields) { | ||||
|  | ||||
|       if (field.hidden) { | ||||
| @@ -982,7 +1016,36 @@ class _APIFormWidgetState extends State<APIFormWidget> { | ||||
|  | ||||
|       return response; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void extractNonFieldErrors(APIResponse response) { | ||||
|  | ||||
|     List<String> errors = []; | ||||
|  | ||||
|     Map<String, dynamic> data = response.asMap(); | ||||
|  | ||||
|     // Potential keys representing non-field errors | ||||
|     List<String> keys = [ | ||||
|       "__all__", | ||||
|       "non_field_errors", | ||||
|       "errors", | ||||
|     ]; | ||||
|  | ||||
|     for (String key in keys) { | ||||
|       if (data.containsKey(key)) { | ||||
|         dynamic result = data[key]; | ||||
|  | ||||
|         if (result is String) { | ||||
|           errors.add(result); | ||||
|         } else if (result is List) { | ||||
|           result.forEach((element) { | ||||
|             errors.add(element.toString()); | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     nonFieldErrors = errors; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
| @@ -1073,13 +1136,13 @@ class _APIFormWidgetState extends State<APIFormWidget> { | ||||
|           success: false | ||||
|         ); | ||||
|  | ||||
|         print(response.data); | ||||
|  | ||||
|         // Update field errors | ||||
|         for (var field in fields) { | ||||
|           field.extractErrorMessages(response); | ||||
|         } | ||||
|  | ||||
|         extractNonFieldErrors(response); | ||||
|  | ||||
|         break; | ||||
|       case 401: | ||||
|         showSnackIcon( | ||||
|   | ||||
							
								
								
									
										13
									
								
								lib/helpers.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/helpers.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| /* | ||||
|  * A set of helper functions to reduce boilerplate code | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Simplify a numerical value into a string, | ||||
|  * supressing trailing zeroes | ||||
|  */ | ||||
| String simpleNumberString(double number) { | ||||
|   // Ref: https://stackoverflow.com/questions/55152175/how-to-remove-trailing-zeros-using-dart | ||||
|  | ||||
|   return number.toStringAsFixed(number.truncateToDouble() == number ? 0 : 1); | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| import "dart:async"; | ||||
|  | ||||
| import "package:intl/intl.dart"; | ||||
| import 'package:inventree/helpers.dart'; | ||||
| import "package:inventree/inventree/part.dart"; | ||||
| import "package:flutter/cupertino.dart"; | ||||
|  | ||||
| @@ -369,16 +370,11 @@ class InvenTreeStockItem extends InvenTreeModel { | ||||
|  | ||||
|   double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; | ||||
|  | ||||
|   String get quantityString { | ||||
|   String quantityString({bool includeUnits = false}){ | ||||
|  | ||||
|     String q = quantity.toString(); | ||||
|     String q = simpleNumberString(quantity); | ||||
|  | ||||
|     // Simplify integer values e.g. "1.0" becomes "1" | ||||
|     if (quantity.toInt() == quantity) { | ||||
|       q = quantity.toInt().toString(); | ||||
|     } | ||||
|  | ||||
|     if (units.isNotEmpty) { | ||||
|     if (includeUnits && units.isNotEmpty) { | ||||
|       q += " ${units}"; | ||||
|     } | ||||
|  | ||||
| @@ -394,12 +390,7 @@ class InvenTreeStockItem extends InvenTreeModel { | ||||
|       return "SN ${serialNumber}"; | ||||
|     } | ||||
|  | ||||
|     // Is an integer? | ||||
|     if (quantity.toInt() == quantity) { | ||||
|       return "${quantity.toInt()}"; | ||||
|     } | ||||
|  | ||||
|     return "${quantity}"; | ||||
|     return simpleNumberString(quantity); | ||||
|   } | ||||
|  | ||||
|   String get locationName { | ||||
| @@ -436,7 +427,7 @@ class InvenTreeStockItem extends InvenTreeModel { | ||||
|     if (serialNumber.isNotEmpty) { | ||||
|       return "SN: $serialNumber"; | ||||
|     } else { | ||||
|       return quantityString; | ||||
|       return simpleNumberString(quantity); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -622,7 +622,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> { | ||||
|               title: Text(L10().countStock), | ||||
|               leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), | ||||
|               onTap: _countStockDialog, | ||||
|               trailing: Text(item.quantityString), | ||||
|               trailing: Text(item.quantityString(includeUnits: true)), | ||||
|           ) | ||||
|       ); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user