mirror of
https://github.com/inventree/inventree-app.git
synced 2026-03-11 04:34:29 +00:00
Fix bool fields (#778)
* Improved UX for boolean fields - Use segmented button - Allow tristate - Improved filtering options * Bug fix for null filter values * Prevent null filters from being sent to the server * Update release notes
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
- Auto-fill location data when receiving item via barcode scan
|
- Auto-fill location data when receiving item via barcode scan
|
||||||
|
- Visual improvements for boolean form fields
|
||||||
|
- Add support for tri-state boolean form fields
|
||||||
|
- Bug fixes for refreshing list view data
|
||||||
|
|
||||||
## 0.22.2 - February 2026
|
## 0.22.2 - February 2026
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -874,25 +874,86 @@ class APIFormField {
|
|||||||
|
|
||||||
// Construct a boolean input element
|
// Construct a boolean input element
|
||||||
Widget _constructBoolean() {
|
Widget _constructBoolean() {
|
||||||
bool? initial_value;
|
String initial_value = "null";
|
||||||
|
|
||||||
if (value is bool || value == null) {
|
bool allow_null = (getParameter("tristate") ?? false) as bool;
|
||||||
initial_value = value as bool?;
|
|
||||||
|
if (value is bool) {
|
||||||
|
initial_value = value.toString().toLowerCase();
|
||||||
|
} else if (value == null) {
|
||||||
|
if (allow_null) {
|
||||||
|
initial_value = "null";
|
||||||
|
} else {
|
||||||
|
initial_value = "false";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String vs = value.toString().toLowerCase();
|
// Not a boolean value - may be a string
|
||||||
initial_value = ["1", "true", "yes"].contains(vs);
|
if (["1", "true", "yes"].contains(value.toString().toLowerCase())) {
|
||||||
|
initial_value = "true";
|
||||||
|
} else if ([
|
||||||
|
"0",
|
||||||
|
"false",
|
||||||
|
"no",
|
||||||
|
].contains(value.toString().toLowerCase())) {
|
||||||
|
initial_value = "false";
|
||||||
|
} else if (allow_null) {
|
||||||
|
initial_value = "null";
|
||||||
|
} else {
|
||||||
|
initial_value = "false";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CheckBoxField(
|
List<ButtonSegment<String>> buttons = [];
|
||||||
label: label,
|
|
||||||
labelStyle: _labelStyle(),
|
if ((getParameter("tristate") ?? false) as bool) {
|
||||||
helperText: helpText,
|
buttons.add(
|
||||||
helperStyle: _helperStyle(),
|
ButtonSegment<String>(
|
||||||
initial: initial_value,
|
value: "null",
|
||||||
tristate: (getParameter("tristate") ?? false) as bool,
|
icon: Icon(TablerIcons.minus, color: COLOR_GRAY_LIGHT),
|
||||||
onSaved: (val) {
|
),
|
||||||
setFieldValue(val);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
buttons.add(
|
||||||
|
ButtonSegment<String>(
|
||||||
|
value: "false",
|
||||||
|
icon: Icon(TablerIcons.x, color: COLOR_DANGER),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
buttons.add(
|
||||||
|
ButtonSegment<String>(
|
||||||
|
value: "true",
|
||||||
|
icon: Icon(TablerIcons.check, color: COLOR_SUCCESS),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
title: Text(label),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
subtitle: Text(helpText),
|
||||||
|
trailing: SegmentedButton<String>(
|
||||||
|
segments: buttons,
|
||||||
|
selected: {initial_value},
|
||||||
|
showSelectedIcon: false,
|
||||||
|
multiSelectionEnabled: false,
|
||||||
|
style: SegmentedButton.styleFrom(
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
// minimumSize: MaterialStateProperty.all(Size(0, 0)),
|
||||||
|
// tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
),
|
||||||
|
onSelectionChanged: (Set<String> selection) {
|
||||||
|
String element = selection.first;
|
||||||
|
if (element == "null" && allow_null) {
|
||||||
|
setFieldValue(null);
|
||||||
|
} else if (element == "true") {
|
||||||
|
setFieldValue(true);
|
||||||
|
} else {
|
||||||
|
setFieldValue(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,7 +1229,9 @@ class APIFormWidgetState extends State<APIFormWidget> {
|
|||||||
// Callback for when a field value is changed
|
// Callback for when a field value is changed
|
||||||
// Default implementation does nothing,
|
// Default implementation does nothing,
|
||||||
// but custom form implementations may override this function
|
// but custom form implementations may override this function
|
||||||
void onValueChanged(String field, dynamic value) {}
|
void onValueChanged(String field, dynamic value) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> handleSuccess(
|
Future<void> handleSuccess(
|
||||||
Map<String, dynamic> submittedData,
|
Map<String, dynamic> submittedData,
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ class LabelFormWidgetState extends APIFormWidgetState {
|
|||||||
if (field == "plugin") {
|
if (field == "plugin") {
|
||||||
onPluginChanged(value.toString());
|
onPluginChanged(value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.onValueChanged(field, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -92,9 +92,10 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget>
|
|||||||
|
|
||||||
// Skip null values
|
// Skip null values
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
continue;
|
f[k] = "null";
|
||||||
|
} else {
|
||||||
|
f[k] = value.toString();
|
||||||
}
|
}
|
||||||
f[k] = value.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
@@ -341,7 +342,16 @@ abstract class PaginatedSearchState<T extends PaginatedSearchWidget>
|
|||||||
Map<String, String> f = await constructFilters();
|
Map<String, String> f = await constructFilters();
|
||||||
|
|
||||||
if (f.isNotEmpty) {
|
if (f.isNotEmpty) {
|
||||||
params.addAll(f);
|
for (String k in f.keys) {
|
||||||
|
// Remove any existing filter keys
|
||||||
|
dynamic value = f[k];
|
||||||
|
|
||||||
|
if (value == null || value == "null") {
|
||||||
|
params.remove(k);
|
||||||
|
} else {
|
||||||
|
params[k] = value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final page = await requestPage(_pageSize, pageKey, params);
|
final page = await requestPage(_pageSize, pageKey, params);
|
||||||
|
|||||||
Reference in New Issue
Block a user