2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 05:26:47 +00:00

Display non-field errors as returned from the server

This commit is contained in:
Oliver 2021-10-03 01:20:37 +10:00
parent b7f9f1c55f
commit 2886f7c930
4 changed files with 87 additions and 20 deletions

View File

@ -7,6 +7,7 @@ import "package:date_field/date_field.dart";
import "package:inventree/api.dart"; import "package:inventree/api.dart";
import "package:inventree/app_colors.dart"; import "package:inventree/app_colors.dart";
import 'package:inventree/helpers.dart';
import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/part.dart";
import "package:inventree/inventree/sentry.dart"; import "package:inventree/inventree/sentry.dart";
import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/stock.dart";
@ -201,7 +202,15 @@ class APIFormField {
// Return the error message associated with this field // Return the error message associated with this field
List<String> errorMessages() { 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 = []; List<String> messages = [];
@ -395,7 +404,7 @@ class APIFormField {
helperStyle: _helperStyle(), helperStyle: _helperStyle(),
hintText: placeholderText, hintText: placeholderText,
), ),
initialValue: (value ?? 0).toString(), initialValue: simpleNumberString(double.tryParse(value.toString()) ?? 0),
keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true),
validator: (value) { validator: (value) {
@ -871,6 +880,8 @@ class _APIFormWidgetState extends State<APIFormWidget> {
final IconData icon; final IconData icon;
List<String> nonFieldErrors = [];
List<APIFormField> fields; List<APIFormField> fields;
Function(Map<String, dynamic>)? onSuccess; Function(Map<String, dynamic>)? onSuccess;
@ -881,6 +892,29 @@ class _APIFormWidgetState extends State<APIFormWidget> {
List<Widget> widgets = []; 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) { for (var field in fields) {
if (field.hidden) { if (field.hidden) {
@ -982,7 +1016,36 @@ class _APIFormWidgetState extends State<APIFormWidget> {
return response; 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 success: false
); );
print(response.data);
// Update field errors // Update field errors
for (var field in fields) { for (var field in fields) {
field.extractErrorMessages(response); field.extractErrorMessages(response);
} }
extractNonFieldErrors(response);
break; break;
case 401: case 401:
showSnackIcon( showSnackIcon(

13
lib/helpers.dart Normal file
View 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);
}

View File

@ -1,6 +1,7 @@
import "dart:async"; import "dart:async";
import "package:intl/intl.dart"; import "package:intl/intl.dart";
import 'package:inventree/helpers.dart';
import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/part.dart";
import "package:flutter/cupertino.dart"; import "package:flutter/cupertino.dart";
@ -369,16 +370,11 @@ class InvenTreeStockItem extends InvenTreeModel {
double get quantity => double.tryParse(jsondata["quantity"].toString()) ?? 0; 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 (includeUnits && units.isNotEmpty) {
if (quantity.toInt() == quantity) {
q = quantity.toInt().toString();
}
if (units.isNotEmpty) {
q += " ${units}"; q += " ${units}";
} }
@ -394,12 +390,7 @@ class InvenTreeStockItem extends InvenTreeModel {
return "SN ${serialNumber}"; return "SN ${serialNumber}";
} }
// Is an integer? return simpleNumberString(quantity);
if (quantity.toInt() == quantity) {
return "${quantity.toInt()}";
}
return "${quantity}";
} }
String get locationName { String get locationName {
@ -436,7 +427,7 @@ class InvenTreeStockItem extends InvenTreeModel {
if (serialNumber.isNotEmpty) { if (serialNumber.isNotEmpty) {
return "SN: $serialNumber"; return "SN: $serialNumber";
} else { } else {
return quantityString; return simpleNumberString(quantity);
} }
} }

View File

@ -622,7 +622,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
title: Text(L10().countStock), title: Text(L10().countStock),
leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.checkCircle, color: COLOR_CLICK),
onTap: _countStockDialog, onTap: _countStockDialog,
trailing: Text(item.quantityString), trailing: Text(item.quantityString(includeUnits: true)),
) )
); );